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を乗せるとアイスっぽくなります。
でもグラスの中はチョコしか入ってないため、あまり美味しそうに見えませんね。
コメント