松本市のコワーキングスペースKNOWERSで月に1回、「Pythonもくもく会」を開催していて、僕はBlenderとPythonを組み合わせて遊んでいます。

今回はもくもく会で作った物理シミュレーションをお見せします。

動作環境

  • macOS High Sierra 10.13.2
  • Blender 2.79

bash_profileの設定

BlenderにはPythonが組み込まれており、「Cubeを作る」や「Cubeの名前を取得」などがコードを通じて操作できます。

組んだPythonプログラムはTerminalかBlender内のコンソールから実行できます。Terminalからの実行を楽にやるために、bash_profileにaliasを追加しておくといいです。

$ alias blender='/Applications/blender/blender.app/contents/MacOS/blender'
$ source .bash_profile

すると、Terminalで「blender」と打つだけで起動できるようになります。

$ blender --python hogehoge.py
$ blender --background --python hogehoge.py (バックグラウンドレンダリング)

物理シミュレーション

さて、本題の物理シミュレーション。参考にさせてもらったサイトはこちら。

参考:Blenderの物理シミュレーションをpythonスクリプトで作成 – 株式会社CFlatの明後日スタイルのブログ

これをベースにプログラムを組みました。

ソースコード

import bpy
import os
import math


def delete_all():
    """ デフォルトで存在しているCubeを削除 """
    bpy.ops.object.delete()


def create_scene():
    """ シーンを作成 """
    # Cube作成
    cube_count = 10
    for axis_x in range(0, cube_count):
        for axis_y in range(0, cube_count):
            for axis_z in range(0, cube_count):
                # pattern1
                bpy.ops.mesh.primitive_cube_add(location=(axis_x*2, axis_y*2, axis_z*2))
                bpy.ops.rigidbody.object_add()

                # pattern2
                # bpy.ops.mesh.primitive_cube_add(location=(axis_x*2, axis_y*2, axis_z*2), rotation=(15, 15, 0))
                # bpy.ops.rigidbody.object_add()

                # pattern3
                # bpy.ops.mesh.primitive_cube_add(location=(axis_x*2, axis_y*2, axis_z*2))
                #bpy.ops.rigidbody.object_add()
                # bpy.ops.object.modifier_add(type='SOFT_BODY')

    # 平面作成
    bpy.ops.mesh.primitive_plane_add(location=(cube_count-1, cube_count-1, -10))
    bpy.ops.rigidbody.object_add(type='PASSIVE')
    bpy.data.objects["Plane"].scale = (cube_count+10, cube_count+10, 1)

    # カメラ
    bpy.data.objects["Camera"].location = (cube_count+20, cube_count+20, cube_count+20)
    bpy.data.objects["Camera"].rotation_euler = (math.pi/6, 0, math.pi*3/4)
    bpy.data.cameras["Camera"].lens = 10

    # 照明
    bpy.data.objects["Lamp"].location = (0, 0, cube_count+10)
    bpy.data.lamps["Lamp"].type = 'SUN'


def start_simulation():
    """ 物理シミュレーション """
    bpy.ops.ptcache.bake_all()

    # 動画作成
    bpy.context.scene.render.resolution_x = 400
    bpy.context.scene.render.resolution_y = 300
    bpy.context.scene.render.resolution_percentage = 100
    bpy.context.scene.render.image_settings.file_format = 'AVI_JPEG'
    bpy.data.scenes["Scene"].render.filepath = "Physical.avi"
    bpy.context.scene.frame_start = 0
    bpy.context.scene.frame_end = 250
    bpy.ops.render.render(animation=True)

    # 保存
    save_path = os.path.abspath(os.path.dirname(__file__))
    bpy.path.relpath(save_path)
    bpy.ops.wm.save_as_mainfile(filepath="Physical.blend", relative_remap=True)


if __name__ == '__main__':
    delete_all()
    create_scene()
    start_simulation()

シミュレーションの設定は18行目から3パターンあります。pattern1は剛体のシミュレーション、pattern3が柔体シミュレーション。

柔体シミュレーションは「bpy.ops.object.modifier_add(type=’SOFT_BODY’)」を追加して「Cubeたちよ!君たちは柔体だ!」と定義してあげるだけ(笑)

詳しく調べていませんが、柔体用のパラメータはたくさんあると思います。上記1行ではおそらくデフォルト値が設定されるのではないかと思います。

動作画面

おわりに

Blenderは3DCGソフトウェア。本来はマウスであれこれやって作っていくもの。でも、Cubeを1000個並べるような単純な繰り返しはスクリプトを組んで実行させた方が楽。

それ以外にもスクリプトが効果的なシーンはあるでしょう。Creative Codingをやっている方もいますし。

いろんなことができるソフトウェアが(基本的に)無料で使えて遊べる。とてもありがたいことですね。

追記:v2.8 betaに対応しました

この記事を書いた人

花村貴史|Takashi Hanamura

◆Photographer|木漏れ日や水、空が魅せるきらきらが好き|写真を通じて「やさしい世界」を伝えてゆく ◆Software Engineer|Private: Go/C++/WebGL|Work: SAP/SAC

写真素材note発売中

継続課金マガジンで販売しています。ブログに載せるもOK、壁紙に設定するもOK、使い方は自由です。フリー素材も良いけれど、人と被りたくないという方に人気です。

人物写真|Photo Session

お話しながらのポートレイト撮影です。「今」そして「これから」のあなたにフォーカスして撮影します。SNSやサイト用のプロフィール写真に。

イベント写真|Photo Shooting

「友達と楽しんでいる」「セミナーで講演している」「パーティーを主催している」など、皆さんが大切な時間を過ごしている瞬間をスナップします。