だるまさんの言うとおり(Blenderダルマ落とし)

12-7.Blender

映画『神さまの言うとおり』(2014)

ほんと怖すぎです。イケメンが出てくるからって安心しないでください。(R15+)で、スプラッターなので視聴に注意が必要です。
楽しいゲームがたくさん用意されているのですが、そのゲームに負けてしまうとデス! つまり生き残ることができないのですが、ほとんどの高校生が失敗して果てます。男子も、女子も、美男子でも、美少女でも、差別なく酷いことされます。

私は初めて試聴したときは、ダルマのシーンでリタイヤして、続きを見ないままレンタルへ返却しました。当時ダルマが怖くて眠れなくなりそうだったので、怖くないダルマをBlenderでPythonプログラミングしてみようと思い、本記事を書いた次第です。

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

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

dharma-title

9. 完成スクリプト

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

~$ 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

10. 実行すると

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

あれから本映画を最後まで試聴してみましたが、やはり怖いものは怖いです。
本記事のダルマ落とし失敗の動画を見て気を紛らわしました。

コメント

タイトルとURLをコピーしました