読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Blender 2.63 での Python の使い方についてまとめてみた

Blender Python 3DCG

はじめに

Blender はとても高機能なオープンソース & マルチプラットフォームな 3DCG ソフトウェアです。中でも注目すべきなのが Python で全てを制御できる点です。新しくキューブを追加したりそこにテクスチャを貼ったり移動したりコピーしたりレンダリングしたり…、GUI を通じて操作することは全て Python で書くことができます。Python での制御は予め書いたスクリプトを実行させることでもできますし、Blender 内に表示される Python コンソールを通じて対話的に制御することもできます。要は 3DCG の勉強をしながら Python の勉強もできるという一石二鳥な素晴らしいソフトウェアというわけです。
しかしながら Blender 2.5x 系で大きく Blender API が変更されたことにより、最新の Blender 2.63 では過去のコード資産がそのままでは使えなくなっています。つまり検索しても大半のサンプルコードが古い API を使用しており、新しい API を使ったものが少ないので、何をすれば良いのか、どうやれば良いのか良く分からない、という状況に陥る訳です。そこで間違っているところも多々あると思いますが、これからはじめる人のお役に立てれば、ということで勉強したことを備忘録的にまとめてみました。

できるようになること

以下みたいなムービーとかであれば 30 行弱くらいで出来ます。

これを実現するコードは最後の方に載っけてあります。

参考文献

Blender API については以下のサイトが参考になります。

Blender の基本的な操作等に関しては、以下の書籍を参考にしました。

Blender 2.5マスターブック

Blender 2.5マスターブック

Python の基礎は以下のサイトでサクッと予習/復習できます。

とりあえず Blender API を使ってみる

Python コンソールを開きます。Blender API は bpy モジュール以下にあるので、「bpy.」と打ってみてから Ctrl + Space を押すと図のように bpy.* の候補一覧が出てきます。Ctrl + Space は補完をしてくれるショートカットです。bpy.data、bpy.ops、bpy.context あたりを良く使うと思いますので簡単に紹介します。
bps.ops は Operators のことで、これを通じていろんな操作が可能です。

>>> bpy.ops.mesh.primitive_cube_add()
{'FINISHED'}

を実行してみると原点に立方体が追加されます。bpy.ops では実行が成功すると {'FINISHED'} が返ってきます。

bpy.data はオブジェクトにアクセスしてそのデータを読み取ったり書き換えたりするものです。

>>> for obj in bpy.data.objects:
...   print(obj.name)
... 
Camera
Cube
Lamp

ここでは全てのオブジェクトの名前を書き出しています。

>>> bpy.data.objects['Cube'].location.x += 1
<<

Outliner パネルから確認できるオブジェクトの名前を直接指定して特定のオブジェクトのプロパティを直接書き換えることもできます。上記例では先程追加した立方体の x 座標が 1 移動します。

bpy.context は Blender で表示されている画面に応じた操作が可能です。

>>> bpy.context.selected_objects
[bpy.data.objects['Cube']]

ここでは現在選択されているオブジェクトを取得しています。

>>> bpy.context.area.type = 'VIEW_3D'

こうすると Python コンソールが 3D View パネルに切り替わります。

スクリプトの実行

上記例では Python コンソールベースで実行していましたが、今度はスクリプトベースで実行してみます。
Text Editor パネルを開いて New ボタンで適当なテキストファイルを追加します。で、次のように書いてみます。

import bpy
bpy.data.objects['Cube'].location.z += 2

対話コンソールでは予め bpy モジュールを使えましたが、スクリプトベースで実行する際には import bpy しないといけません。そして、Alt + P もしくは Run Script ボタンを押下するとスクリプトが実行され、立方体が z 方向に 2 移動します。開発の基本的な流れとしては Python コンソールで単発のコードを確認、それをスクリプトにまとめていく、というようなものになると思います。
Text Editor ではシンタックスハイライトなどないので、スクリプト自体は Vim など別のエディタで編集、ファイルが変更されると変更されたことを通知するアイコンが出てくるのでそこをクリックすると変更を反映させることができます。ちなみに日本語を入力したスクリプトを読み込むとフリーズします。

具体的な操作を紹介してみる

よく使いそうなところを紹介してみます。

オブジェクトの追加
import bpy
import math

# ライトの追加
bpy.ops.object.lamp_add(
	type='POINT',
	location=( 0, 0, 10 ),
	rotation=( 0, 0, 0 ),
)

# カメラの追加
bpy.ops.object.camera_add()

# プレーンの追加
bpy.ops.mesh.primitive_plane_add(
	location=( 1, 2, 3 ),
	rotation=( math.pi/3, math.pi/4, math.pi/5 ),
	layers=(False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
)

こんな感じで追加位置や回転、追加するレイヤを指定してオブジェクトを追加することができます。どんな引数があるかについては対話コンソールで調べることができます。Python なので名前付き引数で渡せる所が良いですね。Layer の指定はイケてない気もしますが。。。

また、そもそもどうやって GUI の操作がどの Blender API に紐付いているのかについては、GUI 上のコンポーネントにマウスオーバーさせてしばらく待っていると表示されるので、そこで調べることができます。

マテリアル/テクスチャの追加
import bpy

mat = bpy.data.materials.new('Hoge')
tex = bpy.data.textures.new('Piyo', type='MAGIC')
mat.texture_slots.add()
mat.texture_slots[0].texture = tex

obj = bpy.context.scene.objects.active
obj.data.materials.append(mat)

新しくマテリアルとテクスチャを作成、そのテクスチャを割り当てたマテリアルを現在選択しているオブジェクトに適用する、という流れになっています。レンダリングしてみると以下のようになります。

アニメーションの追加
import bpy

bpy.context.scene.frame_set(0)
obj = bpy.context.scene.objects.active
obj.keyframe_insert(data_path='location')
bpy.context.scene.frame_set(100)
obj.location.z += 5
obj.keyframe_insert(data_path='location')

old_type = bpy.context.area.type
bpy.context.area.type = 'GRAPH_EDITOR'
bpy.ops.graph.interpolation_type(type='LINEAR')
bpy.context.area.type = old_type

シーンのフレームをセットしてオブジェクトを移動、そして keyframe_insert でキーフレームを挿入する、というのが基本的な流れになります。このとき data_path ではキーフレームとして扱いたいたいデータを指定します。ここでは位置を移動させているので location を指定しています。
また、移動を制御したい時は一度 Graph Editor へ移動してそこで作業をする必要があります。通常は移動は初速と終速度が 0 になるようにイージングがかかった CONSTANT になっています。直線的に移動させるには LINEAR を指定します。

参考: bpy.ops.graph.select_all_toggle() / bpy.ops.transform.translate() / coordinates [Archive] - Blender Artists Community

こんな感じで上手く利用すれば幾何学的な物体などは簡単に作ることができると思います。

GUI 上で設定するにしても色んな方法があるように、上で紹介した以外の方法で同じ事を達成する方法は何通りもありますので、ここで紹介した方法よりもっと簡単な方法があるかもしれません(あったら教えて下さい)。

冒頭のムービーのコード

上で紹介した知識だけで冒頭のムービーは作成できます。

import bpy
import math

START = 0
END   = 100
N     = 10

bpy.context.scene.frame_start = START
bpy.context.scene.frame_end   = END

# Add a camera
bpy.ops.object.camera_add(
    location=(70, -40, 50),
    rotation=(1.1, 0, 0.8)
)

# Add color cubes
for x in range(0, N):
    for y in range(0, N):
        for z in range(0, N):
            # Add a color cube
            bpy.ops.mesh.primitive_cube_add( location=(x*3, y*3, z*3) )
            obj = bpy.context.scene.objects.active
            mat = bpy.data.materials.new('Cube')
            mat.diffuse_color = (x/N, y/N, z/N)
            mat.use_transparency = True
            mat.alpha = 0.6
            obj.data.materials.append(mat)
            
            # Set the start key frame
            bpy.context.scene.frame_set(START)
            obj.keyframe_insert( data_path='rotation_euler' )
            obj.keyframe_insert( data_path='location' )
            
            # Set the end key frame
            bpy.context.scene.frame_set(END)
            obj.location = ( (N-x)*3, (N-y)*3, (N-z)*3 )
            obj.rotation_euler = (math.pi, math.pi, math.pi)
            obj.keyframe_insert( data_path='location' )
            obj.keyframe_insert( data_path='rotation_euler' )

とてもお手軽ですね。

(追記:2013/03/22)
ライティングの設定をしないと真っ黒になるので、「Properties > World」から Environment Lighting と Ambient Occlusion にチェックを入れてください。

おわりに

Blender を通じて 3DCG も勉強できますし、Python を勉強するモチベーションにもなります。素晴らしいですね。