Pythonプログラミングでチョコレートブロックを描く(Blender)

12-7.Blender

2020年7月。夏だというのに、すっかり寒くなってきました。
チョコレートが美味しく楽しめる季節です。
コマンドの達人というからには、チョコレートくらいは、キーパンチするだけで創造できねばなりません。
ってことで、Pythonを使ってチョコレートブロックを作りたいと思います。

スポンサーリンク

準備

まず、レンダリングエンジンの切り替えから。

bpy.context.scene.render.engine

を使います。
Cyclesに切り替えるには、

bpy.context.scene.render.engine='CYCLES'

です。

起動時のCubeはもちろんチョコレートブロックになります。最初の大きさは、2 x 2 x 2の立方体ですが、
いろいろと指定しやすいように、0.5倍にします。

bpy.ops.transform.resize(value=(0.5, 0.5, 0.5))

Cubeのアクセスを楽にするため変数にオブジェクトを設定しておきます。

cube=bpy.data.objects['Cube']

次は剛体設定。

bpy.ops.rigidbody.object_add(type='ACTIVE')

ACTIVE設定しておくと、アニメーションさせると、地面まで落ち始めます。

Cubeのコピーは、Duplicateを使います。全部でチョコレートブロックが125個になるようにコピーします。
※これは、x軸のコピー y z も同じようにコピーする

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

地面は、思いっきり広くして、剛体設定をPASSIVE指定するだけです。

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))
bpy.ops.rigidbody.object_add(type='PASSIVE')

このAPIを実行すると、アニメーション開始します。

bpy.ops.screen.animation_play()

全スクリプトです。

import bpy

bpy.context.scene.render.engine='CYCLES'

cube=bpy.data.objects['Cube']
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cube.rigid_body.collision_shape='BOX'
bpy.ops.transform.translate(value=(-2.5,-2.5,20))

mat=bpy.data.materials['Material']
mat.diffuse_color=(0.08, 0.03, 0.02)

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

cube_objs=[o for o in bpy.data.objects if o.name.startswith('Cube')]
for o in cube_objs:
	o.select = True

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

cube_objs=[o for o in bpy.data.objects if o.name.startswith('Cube')]
for o in cube_objs:
	o.select = True

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

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))
bpy.ops.rigidbody.object_add(type='PASSIVE')

bpy.ops.screen.animation_play()

グラスを作る

チョコレートを受けるグラスを作ります。

回転体の元になるカーブから作ります。
各ポイントの座標は、手で先にグラスの形を作って求めると簡単です。

xyzs = [
( 0,       0, 0),
( 0,       0, 0),
(-2.19903, 0, -0.01731),
(-1.70155, 0, 0.29024),
( 0.14407, 0, 0.32944),
(-1.077,   0, 1.02418),
( 0.40246, 0, 2),
(-3.19444, 0, 2.09537),
(-3.52777, 0, 4.90455)]

回転体にして、

bpy.ops.object.modifier_add(type="SCREW")

厚みを持たせて、

bpy.ops.object.modifier_add(type="SOLIDIFY")

MESHに変換します。

bpy.ops.object.convert(target="MESH")

MESHにしたら、剛体設定を、チョコレートブロックを設定した時と同じく設定し、今度はPASSIVEに。

bpy.ops.rigidbody.object_add(type='PASSIVE')

あとこのままだと、チョコレートが宙に浮いてしまうので、collision_shapeをMESHにしておきます。

cube.rigid_body.collision_shape='MESH'

全スクリプトです。

import bpy

xyzs = [
( 0,       0, 0),
( 0,       0, 0),
(-2.19903, 0, -0.01731),
(-1.70155, 0, 0.29024),
( 0.14407, 0, 0.32944),
(-1.077,   0, 1.02418),
( 0.40246, 0, 2),
(-3.19444, 0, 2.09537),
(-3.52777, 0, 4.90455)]

cv=bpy.data.curves.new('Curve', type='CURVE')
cv.dimensions = '3D'
cv.resolution_u = 2

line = cv.splines.new('NURBS')
line.points.add(len(xyzs))
for i, xyz in enumerate(xyzs):
    x,y,z = xyz
    line.points[i].co = (x, y, z, 1)

o = bpy.data.objects.new('Curve', cv)

bpy.context.scene.objects.link(o)
bpy.context.scene.objects.active = o
o.select = True

bpy.ops.object.modifier_add(type="SCREW")
bpy.ops.object.modifier_add(type="SOLIDIFY")
bpy.ops.object.convert(target="MESH")

bpy.ops.rigidbody.object_add(type='PASSIVE')
cube.rigid_body.collision_shape='MESH'

マテリアルの設定

CYCLESエンジンにしてから、グラスに新規マテリアルを設定します。

mat=bpy.data.materials.new(name='Material.001')
bpy.context.object.data.materials.append(mat)

ノードを有効にして、新規追加します。ガラスっぽくするので、BsdfGlassにします。

mat.use_nodes=True
mat.node_tree.nodes.new(type='ShaderNodeBsdfGlass')

ノードを入力出力つなげたら、オブジェクトにマテリアルを設定します。

inp = mat.node_tree.nodes['Material Output'].inputs['Surface']
outp = mat.node_tree.nodes['Glass BSDF'].outputs['BSDF']
mat.node_tree.links.new(inp,outp)
bpy.data.objects['Curve'].active_material = mat

床には色は付けません。

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))

ランプが明るくなるように設定。

lamp=bpy.data.lamps['Lamp']
bpy.data.scenes['Scene'].cycles.samples=10
bpy.data.lamps['Lamp'].shadow_soft_size=1

strengthは、ノードから指定します。

lamp.use_nodes=True
lamp.node_tree.nodes['Emission'].inputs['Strength'].default_value = 10000

全スクリプトです。

bpy.context.scene.render.engine='CYCLES'

mat=bpy.data.materials.new(name='Material.001')
bpy.context.object.data.materials.append(mat)
mat.use_nodes=True
mat.node_tree.nodes.new(type='ShaderNodeBsdfGlass')

inp = mat.node_tree.nodes['Material Output'].inputs['Surface']
outp = mat.node_tree.nodes['Glass BSDF'].outputs['BSDF']
mat.node_tree.links.new(inp,outp)
bpy.data.objects['Curve'].active_material = mat

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))

lamp=bpy.data.lamps['Lamp']
bpy.data.scenes['Scene'].cycles.samples=10
bpy.data.lamps['Lamp'].shadow_soft_size=1

lamp.use_nodes=True
lamp.node_tree.nodes['Emission'].inputs['Strength'].default_value = 10000

完成

今までのスクリプトをつなげてグラスにチョコレートを入れます。
グラスはチョコレートパフェのように縦長に伸ばします。

bpy.ops.transform.resize(value=(0.5, 0.5, 2))

グラスが深くなると、チョコレートが足りません。増やします。

for i in range(0,40):

全部つなげたスクリプトです。

import bpy

bpy.context.scene.render.engine='CYCLES'

cube=bpy.data.objects['Cube']
bpy.ops.transform.resize(value=(0.5, 0.5, 0.5))
bpy.ops.rigidbody.object_add(type='ACTIVE')
cube.rigid_body.collision_shape='BOX'
bpy.ops.transform.translate(value=(-2,-2,20))

mat=bpy.data.materials['Material']
mat.diffuse_color=(0.08, 0.03, 0.02)

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

cube_objs=[o for o in bpy.data.objects if o.name.startswith('Cube')]
for o in cube_objs:
	o.select = True

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

cube_objs=[o for o in bpy.data.objects if o.name.startswith('Cube')]
for o in cube_objs:
	o.select = True

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

cube_objs=[o for o in bpy.data.objects if o.name.startswith('Cube')]
for o in cube_objs:
	o.select = True

bpy.ops.transform.resize(value=(0.4, 0.4, 0.4))

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))
bpy.ops.rigidbody.object_add(type='PASSIVE')

xyzs = [
( 0,       0, 0),
( 0,       0, 0),
(-2.19903, 0, -0.01731),
(-1.70155, 0, 0.29024),
( 0.14407, 0, 0.32944),
(-1.077,   0, 1.02418),
( 0.40246, 0, 2),
(-3.19444, 0, 2.09537),
(-3.52777, 0, 4.90455)]

cv= bpy.data.curves.new('myCurve', type='CURVE')
cv.dimensions = '3D'
cv.resolution_u = 2

polyline = cv.splines.new('NURBS')
polyline.points.add(len(xyzs))
for i, xyz in enumerate(xyzs):
    x,y,z = xyz
    polyline.points[i].co = (x, y, z, 1)

o = bpy.data.objects.new('Curve', cv)

scn = bpy.context.scene
scn.objects.link(o)
scn.objects.active = o
o.select = True

bpy.ops.object.modifier_add(type="SCREW")
bpy.ops.object.modifier_add(type="SOLIDIFY")
bpy.context.object.modifiers['Solidify'].thickness=0.1
bpy.ops.object.modifier_add(type="SUBSURF")

bpy.ops.object.convert(target="MESH")

bpy.ops.rigidbody.object_add(type='PASSIVE')
bpy.ops.transform.resize(value=(0.5, 0.5, 2))

bpy.context.scene.render.engine='CYCLES'

mat=bpy.data.materials.new(name='Material.001')
bpy.context.object.data.materials.append(mat)
mat.use_nodes=True
mat.node_tree.nodes.new(type='ShaderNodeBsdfGlass')

inp = mat.node_tree.nodes['Material Output'].inputs['Surface']
outp = mat.node_tree.nodes['Glass BSDF'].outputs['BSDF']
mat.node_tree.links.new(inp,outp)
bpy.data.objects['Curve'].active_material = mat

bpy.context.scene.cursor_location = (0,0,0)
bpy.ops.mesh.primitive_plane_add()
bpy.ops.transform.resize(value=(99, 99, 1))

lamp=bpy.data.lamps['Lamp']
bpy.data.scenes['Scene'].cycles.samples=10
bpy.data.lamps['Lamp'].shadow_soft_size=1

lamp.use_nodes=True
lamp.node_tree.nodes['Emission'].inputs['Strength'].default_value = 10000

Sphereを乗せるとアイスっぽくなります。
でもグラスの中はチョコしか入ってないため、あまり美味しそうに見えませんね。

コメント

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