Blenderダルマ落とし

dharma-title
映画『神さまの言うとおり』(R15+)(2014)。怖すぎです。スプラッターなので視聴に注意が必要です。チャレンジに失敗すると生き残ることができないのですが、ほとんどの高校生が失敗して果てます。男子高校生も、女子高校生も、差別なく酷いことされます。
私は一番最初のダルマのシーンでリタイヤしました。ダルマが怖くて眠れなくなりそうなので、怖くないダルマを描いてみました。

では怖くないダルマを使って、Blenderでダルマ落としをチャレンジしてみます。

1 ダルマのマッピング画像を準備する。
2 z方向の重力を大きくする。
3 最初からあるCubeを地面に変形する。
4 新規に円柱を追加してダルマにする。
5 ダルマを剛体にする。
6 ダルマをコピーして増やす。
7 ダルマ落とし用ハンマー(床にくっついている四角い棒)を作る。
8 フレームを設定して、ハンマーを往復移動させる。

1.ダルマ画像としてこのように塗り絵を作りました。
dharma

2.z方向の重力を大きくする。
重力が小さいままだと、ダルマが浮き上がってしまいますので、大きい数字(マイナス)にします。

bpy.data.scenes["Scene"].gravity.z=-50

3.最初からあるCubeを地面に変形する。
Cubeを変形して地面にしたら、PASSIVEタイプの剛体にします。

bpy.data.objects['Cube'].location=(0,0,-2)
bpy.ops.transform.resize(value=(9,9,1))
bpy.ops.rigidbody.object_add(type='PASSIVE')

4.新規に円柱を追加してダルマにする。
円柱を追加したら、UVマッピング用の切れ込みを入れます。

bpy.ops.mesh.primitive_cylinder_add()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='EDGE')

mesh=bmesh.from_edit_mesh(bpy.context.object.data)

bpy.ops.mesh.select_all(action='DESELECT')
mesh.edges[0].select = True
for i in range(0,32):
	mesh.edges[i*3+1].select = True
	mesh.edges[i*3+2].select = True

bpy.context.scene.objects.active = bpy.context.scene.objects.active
bpy.ops.mesh.mark_seam()

mat=bpy.data.materials.new('Material.001')
mat.emit=1
tex1 = bpy.data.textures.new('Tex1', type='IMAGE')
fname=os.path.expanduser('~/dharma.png')
tex1.image = bpy.data.images.load(fname)
bpy.context.object.data.materials.append(mat)

mt=mat.texture_slots.add()
mat.texture_slots[0].texture=tex1
mt.texture_coords='OBJECT'

bpy.data.materials['Material.001'].texture_slots[0].texture = tex1
bpy.data.materials['Material.001'].texture_slots[0].texture_coords='UV'
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.unwrap()

5 ダルマを剛体にする。
ダルマをACTIVEタイプの剛体にします。一番下のダルマが飛ばされたときに、上のダルマが真下に落ちるように細かい設定をします。

bpy.ops.rigidbody.object_add(type='ACTIVE')
cy.rigid_body.use_deactivation=True
cy.rigid_body.use_start_deactivated=True
cy.rigid_body.collision_shape="CYLINDER"
cy.rigid_body.use_margin=True
cy.rigid_body.collision_margin=1

6 ダルマをコピーして増やす。
ダルマをコピーしていきます。スクリプトの見せ場ですね。

for i in range(0,100):
	bpy.ops.object.duplicate()
	bpy.ops.transform.translate(value=(0,0,2))

7 ダルマ落とし用ハンマー(床にくっついている四角い棒)を作る。
Cubeを追加して、細長くします。ACTIVEタイプの剛体にしますが、collision_shapeをMESH型にしないと、なぜかダルマをすり抜けることがあります。

bpy.ops.mesh.primitive_cube_add()
bpy.ops.transform.resize(value=(9, 0.2, 1))
bpy.ops.rigidbody.object_add(type='ACTIVE')
bpy.data.objects['Cube.001'].rigid_body.kinematic=True
bpy.data.objects["Cube.001"].rigid_body.collision_shape="MESH"

8 キーフレームを設定して、ハンマーを往復移動させる。
フレーム番号を設定したら、ハンマーを所定の場所に移動させ、キーフレームを設定します。
往復するために方向(direction)が交互に変わります。

direction=-1
for i in range(1,10):
	bpy.context.scene.frame_set(i*20)
	bpy.ops.transform.translate(value=(0,direction*18,0))
	bpy.context.active_object.keyframe_insert(data_path="location", index=-1)
	direction= -direction

全部を通したスクリプトはこれです。

~$ cat dharma.sh
#!/bin/bash
cat <<EOL>/tmp/tmp.py

import bpy,bmesh,math,os

bpy.data.scenes["Scene"].gravity.z=-50

bpy.data.objects['Cube'].location=(0,0,-2)
bpy.ops.transform.resize(value=(9,9,1))
bpy.ops.rigidbody.object_add(type='PASSIVE')

bpy.ops.mesh.primitive_cylinder_add()
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='EDGE')

mesh=bmesh.from_edit_mesh(bpy.context.object.data)

bpy.ops.mesh.select_all(action='DESELECT')
mesh.edges[0].select = True
for i in range(0,32):
	mesh.edges[i*3+1].select = True
	mesh.edges[i*3+2].select = True

bpy.context.scene.objects.active = bpy.context.scene.objects.active
bpy.ops.mesh.mark_seam()

mat=bpy.data.materials.new('Material.001')
mat.emit=1
tex1 = bpy.data.textures.new('Tex1', type='IMAGE')
fname=os.path.expanduser('~/dharma.png')
tex1.image = bpy.data.images.load(fname)
bpy.context.object.data.materials.append(mat)

mt=mat.texture_slots.add()
mat.texture_slots[0].texture=tex1
mt.texture_coords='OBJECT'

bpy.data.materials['Material.001'].texture_slots[0].texture = tex1
bpy.data.materials['Material.001'].texture_slots[0].texture_coords='UV'
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.unwrap()

cy=bpy.data.objects['Cylinder']
cy.rotation_mode='XYZ'
cy.rotation_euler=(0, 0, math.pi/2)
 
bpy.ops.object.mode_set(mode='OBJECT')

bpy.ops.rigidbody.object_add(type='ACTIVE')
cy.rigid_body.use_deactivation=True
cy.rigid_body.use_start_deactivated=True
cy.rigid_body.collision_shape="CYLINDER"
cy.rigid_body.use_margin=True
cy.rigid_body.collision_margin=1

for i in range(0,100):
	bpy.ops.object.duplicate()
	bpy.ops.transform.translate(value=(0,0,2))

bpy.ops.mesh.primitive_cube_add()
bpy.ops.transform.resize(value=(9, 0.2, 1))
bpy.ops.rigidbody.object_add(type='ACTIVE')
bpy.data.objects['Cube.001'].rigid_body.kinematic=True
bpy.data.objects["Cube.001"].rigid_body.collision_shape="MESH"

bpy.context.scene.frame_set(1)
bpy.ops.transform.translate(value=(0,9,0))
bpy.context.active_object.keyframe_insert(data_path="location", index=-1)

direction=-1
for i in range(1,10):
	bpy.context.scene.frame_set(i*20)
	bpy.ops.transform.translate(value=(0,direction*18,0))
	bpy.context.active_object.keyframe_insert(data_path="location", index=-1)
	direction= -direction

bpy.context.scene.frame_set(1)

bpy.data.objects['Camera'].location=(10,-9,10)
bpy.data.objects['Lamp'].location=(3,-4,5)
bpy.data.lamps['Lamp'].distance=2000

EOL
blender -b -P /tmp/tmp.py -o //test -a -F PNG -x 1 -f 1 | grep ^Save
convert -layers optimize -loop 0 -delay 5 test????.png test.gif

上のスクリプトを実行すると、このようなGIFアニメができます。
dharma
見事にダルマ落としチャレンジ失敗しました。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA