Blender 2.8 の使い方 (08) Python スクリプト

Blender 2.8 の使い方 (08) Python スクリプト

Blender は主要な部分は C や C++ で書かれていますが、多くの機能が Blender に組み込まれている Python でコントロールできるようになっています。 ユーザインターフェイスの多くの部分も Python で書かれています。

Python は最近人気のプログラミング言語なので、情報はネット上でも簡単に入手できると思います。 本格的にプログラミングしない人でも、数行のコマンドを記述するだけでも、作業の自動化や効率化に便利に使うことができます。

model08b.png

今回の blend ファイルは model08.zip (1.6MB)としてダウンロード できます。

Blender 2.8 には Python 3.7 が組み込まれていて、Blender 内で Python スクリプトを書いて実行することができ、アドオンの開発もできます。 多くのオブジェクトが存在していてマウスやペンで繰り返し操作するのが大変な場合などに、Python スクリプトを使うことで一瞬で作業を完了することができたり、各種の情報のリスト作成などに使うことができます。


b28_python_00.png


Blender 内で Python スクリプトを使う

Blender 内で Python スクリプトを使うには、Python コンソールを使う方法と、内蔵のテキストエディターにスクリプトを記述して、そこで実行する方法があります。

Python コンソール (Shift + [F4])

エリア にヘッダーの左端のアイコンから「Python コンソール」を選ぶか、Shift + [F4]を押します。

b28_python_01.png

Linux や Mac のコンソールで Python を対話的に実行した場合と同じような環境となります。「>>>」がプロンプトで、その後にコマンドを入力します。 以下の例では、Linux 、Mac、BlenderのPython コンソールで「1 + 1.5」の足し算をしてみました。

macOSの例
MacBook-Pro:~ jun$ python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:52:21) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print(1 + 1.5)
2.5
>>> 
Linux (Raspberry Pi)の例
@raspberrypi ~ $ python3
Python 3.7.3 (default, Apr  3 2019, 05:39:12)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print(1 + 1.5)
2.5
>>>
Blender 2.8の場合
PYTHON INTERACTIVE CONSOLE 3.7.4 (default, Aug 13 2019, 14:10:15) [MSC v.1916 64 bit (AMD64)]

Command History:     Up/Down Arrow
Cursor:              Left/Right Home/End
Remove:              Backspace/Delete
Execute:             Enter
Autocomplete:        Ctrl-Space
Zoom:                Ctrl +/-, Ctrl-Wheel
Builtin Modules:     bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, blf, mathutils
Convenience Imports: from mathutils import *; from math import *
Convenience Variables: C = bpy.context, D = bpy.data

>>> print(1 + 1.5)
2.5

>>> print(2**65)
36893488147419103232

>>> 

上記のように print関数を1つ知っているだけでも、Blender で電卓で計算できない「2の65乗」といった非常に大きい数の計算ができてしまいます。 64ビットを超える数の計算が簡単にできるだけでもスゴイことなんです。

Blender の Python コンソールでは、はじめに簡単な操作方法が表示されています。 よく使いそうなものだけ、表にしてみました。

機能キー
コマンド履歴↑、↓
カーソル移動←、→、[Home]、[End]
スクリプト実行[Enter]
補完 (2.81まで)[Ctrl] + [Space]
補完 (2.82以降)[TAB]

Python コンソールでは、Blender 全体を扱うためのモジュール (bpy) や計算用のモジュール (mathutils) が読み込み済みとなっています。

例えば、存在するすべてのオブジェクトのリストは、次の2行だけで表示できます。この例では3つだけですが、数が多い場合にはリストの作成に使えます。

>>> for o in bpy.data.objects:
...     print(o)
...     
<bpy_struct, Object("Camera")>
<bpy_struct, Object("Cube")>
<bpy_struct, Object("Light")>

Python コンソールの補完機能で Blender の Python API を調べる事ができます。

>>> bpy.ここで補完キー
        app
        context
        data
        msgbus
        ops
        path
        props
        types
        utils
>>> bpy.path.ここで補完キー
             abspath(
             basename(
             clean_name(
             display_name(
             display_name_from_filepath(
             display_name_to_filepath(
             ensure_ext(
             extensions_audio
             extensions_image
             extensions_movie
             is_subdir(
             module_names(
             native_pathsep(
             reduce_dirs(
             relpath(
             resolve_ncase(

テキストエディター (Shift + [F11])

ヘッダーの左端のアイコンからテキストエディターを選ぶか、Shift + [F11]を押します。

b28_python_02.png

Pythonの文法にしたがって着色されるテキストエディターです。ヘッダー領域(リージョン)の右端に「スクリプト実行」ボタンがあって、python スクリプトを実行できます。 またメニューの「テンプレート」には、Blenderで使える多くのサンプルがあって非常に参考になります。

b28TextEditor.png

Python コンソールと異なり、テキストエディターでは Blender を扱うためのモジュール (bpy) は読み込まれないので、「import bpy」が必要です。


Python の簡単な解説

特徴

まず最初に、Pythonの公式サイトは https://www.python.org/ です。 そこには公式の 日本語マニュアル もフリーで公開されています。 ここの解説を読まなくても、詳細な情報はいくらでも簡単に入手できます。

Python はコンパイルした後に実行する形式のスクリプト言語で、C、C++などの言語に比べると実行速度が数十分の1であることが欠点です。 しかし利点としては、プログラムが読みやすく、簡潔に書きやすい文法になっています。 最近は、NumPy というモジュールを使うことでの数値計算、特に行列演算が楽であることから AI 分野での人気が高いようです。 また、よく使われるようになって 15 年以上経っているため、ネット上に解説記事などが多く見つかります。 最初からオブジェクト指向のスクリプト言語として設計されています。 プログラミング言語としては、Ruby とライバル関係にある感じです。 Python はオープンソースソフトウェアであすから、すべてが無料で入手できます。

文法

Python の文法全体はマニュアルを参照してください。ここではこの記事で使った機能だけを解説します。 これだけでも多くの事ができます。

コメント

「#」の後ろ行末まではコメントとして扱われ、スクリプトの実行に影響しません。

# すべてのオブジェクトの位置をロックする
for obj in bpy.data.objects:
    obj.lock_location[0] = True # x'''  obj.lock_location[1] = True # y'''  obj.lock_location[2] = True # z''')
    obj.lock_location[1] = True # y'''  obj.lock_location[2] = True # z''')
    obj.lock_location[2] = True # z''')

変数と型、代入

Python が扱うデータには型があって、整数、浮動小数点数、文字列、リスト、クラスのインスタンスなどがあります。 そのデータには名前を付ける事ができ、その名前を変数名といいます。 代入文は「 name = '名前' 」といった形式で変数名とデータを結びつけます。 変数名とデータを結びつけるだけなので、変数には型はありません。

字下げによるブロック

行頭の空白でブロックを示します。 空白の数が多いとブロックが一段深くなります。 字下げに使う空白の数には言語仕様上は制限がありませんが、4文字または、ブロックが深くなりすぎる場合には2文字を使います。

関数の宣言と実行

ひとかたまりの機能を関数としてまとめて、くり返し使うことができます。 「def 関数名 (引数) :」に続くブロックの形式で定義します。 関数を実行するには「関数名(引数)」とします。次の例はテキストエディタにテンプレートとして用意されている「addon_add_object.py」のコードの部分で、赤字が関数宣言、青字が関数の呼び出しです。

def register():
def register():
    bpy.utils.register_class(OBJECT_OT_add_object)
    bpy.utils.register_manual_map(add_object_manual_map)
    bpy.types.VIEW3D_MT_mesh_add.append(add_object_button)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_add_object)
    bpy.utils.unregister_manual_map(add_object_manual_map)
    bpy.types.VIEW3D_MT_mesh_add.remove(add_object_button)


if __name__ == "__main__":
    register()

繰り返し

「for 変数 in リスト:」の形式で、リストの中の要素の1つずつが変数に入って、続くブロックを繰り返し実行します。 次の例では bpy.data.objects はBlenderのオブジェクトのリストなので、すべてのBlenderオブジェクトを表示します。

for obj in bpy.data.objects:
    print(obj)

条件分岐

if 文は、「if 条件式 :」で条件式が「True」の場合に次のブロックを実行し、「False」の場合には次のブロックを飛ばします。

「if 条件式 :」が「False」の場合に「elif 条件式 :」があれば評価されて「True」の場合には続くブロックを実行し、全ての条件式が「False」の場合 「else :」があれば、続くブロックが実行されます。

次の例では Blenderのオブジェクトの型に応じて指定した文字列を表示します。

for obj in bpy.data.objects :
    if obj.type == 'CAMERA' :
        print('Camera')
    elif obj.type == 'LIGHT' :
        print('Lump')
    else :
        print('Other')

Blender のアドオンの形式

この記事では解説していませんが、Blender のアドオンも非常に簡単にすると次のような形式のpythonスクリプトです。

import bpy
import その他必要なモジュール

class クラス名(Operator, AddObjectHelper):
    def メソッド名(self, context):
        # なにか処理
        return {'FINISHED'}

def register():
    bpy.utils.register_class(クラス)

def unregister():
    bpy.utils.unregister_class(クラス)

if __name__ == "__main__":
    register()

Blender で威力を発揮する例

これまでの記事(球と円柱でモデリングスカルプトモード編集モードリトポロジー )で作成した人型モデル(をちょっと改良)をサンプルに使います。 人型のモデルでは左右対称な部分が多いため、多くのオブジェクトにミラーモディファイアを使っています。 スカルプトモードリトポロジー で行ったように、頭部を構成するオブジェクトを結合して、スカルプトで形を整えて、リトポロジーで面を貼り直そうとすると大変です。 また右側のアウトライナーエリアに表示されているように、オブジェクトに親子関係を設定しています。 シフトキーを押しながら子を先に選択して、親を選択して、Ctrl + P で親子関係を設定できます。親が移動、回転、拡大縮小すると、子孫も動くようになります。 「腕を上げれば、指も追従する」ということです。

b28om8_005_01b.png


ミラーモディファイアの一括適用と左右分離

人型モデルを構成するオブジェクトについて、次のような操作を行います。

スクリプトは選択した範囲のオブジェクトの処理になりますが、ここではモデル全体を選択して処理します。次のプログラムリストの内容をテキストエディターに貼り付けます。

# apply_mirror.py

import bpy

objects = bpy.context.selected_objects
bpy.context.view_layer.update()
for obj in objects:
    if obj.type == 'MESH':
        bpy.ops.object.select_all(action='DESELECT')
        print(obj.name)
        obj.select_set(True)
        bpy.context.view_layer.objects.active = obj
        # ミラーモディファイアの適用
        for mod in [m for m in obj.modifiers]:
            bpy.ops.object.modifier_apply(apply_as="DATA", modifier="Mirror")
            # 接続されていないメッシュの分離
            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
            bpy.ops.mesh.separate(type='LOOSE')
            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
            # 分離したオブジェクトのパーツ毎に原点を中心に設定
            parts = bpy.context.selected_objects
            for o in parts:
                bpy.context.view_layer.objects.active = o
                bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
            # 左右のオブジェクト名を ObjectName_L と ObjectName_R とする
            # 右オブジェクトの親は無しに設定
            if len(parts) == 2:
                # 左右の位置(正なら左、負なら右)を調べて名前を修正
                if parts[0].matrix_world.translation.x > parts[1].matrix_world.translation.x:
                    name = parts[0].name
                    parts[0].name = name + '_L'
                    parts[1].name = name + '_R'
                else:
                    name = parts[1].name111
                    parts[1].name = name + '_L'
                    parts[0].name = name + '_R'

3Dビューポートで、[A]キーを押してすべてのオブジェクトを選択してから、テキストエディターのヘッダー領域(リージョン)の右端にある「スクリプト実行」ボタンを押します。

b28om8_005_01c.png

ミラーモディファイアを適用して、オブジェクトを左右で分離した結果、オブジェクトの総数は以下のように 117 個に増えました。 これだけの数をマウスクリックで行うのはちょっとうんざりします。 一度だけならなんとかなりますが、もとに戻ってなにか修正してもう一度作業するにはかなりの精神力が必要です。 スクリプトを作っておけば何度でも一瞬で完了です。

ancle_L ancle_R arm_lower_L arm_lower_R arm_upper_L arm_upper_R
breast_L breast_R chest_L chest_R clavicle_L clavicle_R
Cylinder.001_L Cylinder.001_R Cylinder.002_L Cylinder.002_R Cylinder.003_L Cylinder.003_R
Cylinder.004_L Cylinder.004_R Cylinder.005_L Cylinder.005_R Cylinder.006_L Cylinder.006_R
Cylinder.007_L Cylinder.007_R Cylinder.008_L Cylinder.008_R Cylinder.009_L Cylinder.009_R
Cylinder.010_L Cylinder.010_R Cylinder.011_L Cylinder.011_R Cylinder.012_L Cylinder.012_R
Cylinder.013_L Cylinder.013_R Cylinder.014_L Cylinder.014_R Cylinder_L Cylinder_R
ear_L ear_R elbow_L elbow_R eye_brow_L_L eye_brow_L_R
eyeball_L eyeball_R face_retopo foot_L foot_R heel_L
heel_R hip_joint_L hip_joint_R hip_L hip_R knee_L
knee_R leg_lower_L leg_lower_R leg_upper_L leg_upper_R neck
neck_back neck_mussle_L neck_mussle_R pelvis ribs Shoulder0_L
Shoulder0_R shoulder_blade_L shoulder_blade_R Shoulder_L Shoulder_R Sphere.001_L
Sphere.001_R Sphere.002_L Sphere.002_R Sphere.003_L Sphere.003_R Sphere.004_L
Sphere.004_R Sphere.005_L Sphere.005_R Sphere.006_L Sphere.006_R Sphere.007_L
Sphere.007_R Sphere.008_L Sphere.008_R Sphere.009_L Sphere.009_R Sphere.010_L
Sphere.010_R Sphere.011_L Sphere.011_R Sphere.012_L Sphere.012_R Sphere.015_L
Sphere.015_R Sphere.019_L Sphere.019_R Sphere.020_L Sphere.020_R Sphere.021_L
Sphere.021_R stomach thumb_L thumb_R toe_L toe_R
waist wrist_L wrist_R

親子関係の修正

このモデルの場合、ポーズを付けられるようにオブジェクト間に親子関係を設定しています。 腰を回すと肩も腕も指も回転するようにしています。しかし、破線が左右に広がっているのは、ミラーモディファイアで左側のオブジェクトを右側に反転コピーしても、親子関係は変わらず、右腕は左肩に付き、右指は、左指が親になっています。 親子関係を手作業で再構成する事はできますが、数が多いので大変です。

b28om8_005_01d.png

ここで、また新しい Python スクリプトの登場です。 オブジェクトの左右を表すオブジェクト名の最後についた「_R」を選んで、そのオブジェクトに親が設定されていて、その親の名前が「_L」で終わっていたら、親の名前の「_L」を「_R」に変更することで新しい親を設定することにします。 上のスクリプトに続いて実行します。

次のプログラムリストの内容をテキストエディターに貼り付けます。テキストエディターのヘッダー領域(リージョン)の右端にある「スクリプト実行」ボタンを押します。 このスクリプトでは実行前にオブジェクトを選択しなくてもかまいません。 選択していても最初に選択解除されます。

# fix_parent.py

import bpy
import re

bpy.ops.object.select_all(action='DESELECT')
for obj in [o for o in bpy.data.objects]:
    match = re.match(r'(.*)_R$', obj.name)
    if match:
        name = match.group(1)
        obj_left = bpy.data.objects[name + '_L']
        if obj_left.parent:
            parent_left = obj_left.parent
            if parent_left.name[-2:] == '_L':
                parent_right_name = parent_left.name[:-2] + '_R'
            else:
                parent_right_name = parent_left.name
            parent_right = bpy.data.objects[parent_right_name]
            print(obj.name)
            obj.select_set(state=True)
            parent_right.select_set(state=True)
            bpy.context.view_layer.objects.active = parent_right
            bpy.ops.object.parent_set(type='OBJECT')
            obj.select_set(state=False)
            parent_right.select_set(state=False)
            obj.location = obj_left.location
            obj.location.x = -obj_left.location.x
            bpy.context.view_layer.update()

実行結果を示します。 親子関係を示す破線が消えています。 オブジェクトから見て右側のオブジェクトの親は、正しく右側のオブジェクトになっています。

b28om8_005_01e.png


位置をロック

親子関係のあるオブジェクトについて、親オブジェクトと独立して移動できないように制限します。 親から見た子の位置の変更を制限して、不用意にモデルが崩れるのを防ぐことにします。うっかりオブジェクトを移動してしまって「手首から先が離れてしまう」といった状況を予防します。 「位置制限」のコンストレイントを設定する方法もありますが、トランスフォームの「位置」をロックするほうが簡単です。

lock_location.png

Blender の画面上のボタンなどのパーツを制御する python のコードは、プリファレンスで「Pythonツールチップを表示」にチェックを入れることで、上の図のオレンジの枠内のように Python のコードが表示されるので簡単です。

toolchips_python.png

pythonのスクリプトは親が設定してあるオブジェクトの位置をロックするだけです。

# lock_location.py

import bpy

for obj in [o for o in bpy.data.objects if o.parent]:
    obj.lock_location[0] = True
    obj.lock_location[1] = True
    obj.lock_location[2] = True

「[o for o in bpy.data.objects if o.parent]」の部分は、リスト内包表記といって、すべてのオブジェクト(bpy.data.objects) の中で親を持っているものだけ (if o.parent) をリスト化するもので、次のように書いても結果は同じです。

import bpy

for obj in bpy.data.objects:
    if obj.parent:
        obj.lock_location[0] = True
        obj.lock_location[1] = True
        obj.lock_location[2] = True

親を持つ全てのオブジェクトの X、Y、Z座標がロックされました。500回ぐらいのマウスのクリックが省略できました。

b28om8_005_01f.png


選択可能なオブジェクトを制限

今回のモデルのポースを変える場合、関節に当たるオブジェクトを回転させることで行います。 しかし、例えば手の指の場合はオブジェクト間の間隔が狭く、目的とするオブジェクトが選択し難くなっています。 そこで、選択する必要のないオブジェクトを選択できないように設定できると便利です。 そのためにはアウトラーナーエリアのフィルターのアイコンを押すと表示される「選択可能」項目をチェックして ON にします。

hyde_select0.png

アウトラーナーエリアのオブジェクトの右側に矢印型の「選択無効」アイコンが表示されるようになります。

hyde_select1.png

次のスクリプトでは、回転させる関節に当たるオブジェクト名をリストにしておいて、まず全体を選択不可にした後、リストに登録しているオブジェクトを順次選択可能に設定しています。

# set_selectable.py

import bpy

namelist = [
    "ancle_L", "ancle_R", "elbow_L","elbow_R", "eyeball_L", "eyeball_R",
    "face_retopo", "hip_joint_L", "hip_joint_R","knee_L","knee_R","neck",
    "pelvis","ribs","Shoulder_L","Shoulder_R","Shoulder0_L","Shoulder0_R",
    "Sphere.001_L","Sphere.001_R","Sphere.002_L","Sphere.002_R","Sphere.003_L",
    "Sphere.003_R","Sphere.004_L","Sphere.004_R","Sphere.005_L","Sphere.005_R",
    "Sphere.006_L","Sphere.006_R","Sphere.007_L","Sphere.007_R","Sphere.008_L",
    "Sphere.008_R","Sphere.009_L","Sphere.009_R","Sphere.010_L","Sphere.010_R",
    "Sphere.011_L","Sphere.011_R","Sphere.012_L","Sphere.012_R","Sphere.015_L",
    "Sphere.015_R","stomach","thumb_L","thumb_R","waist","wrist_L","wrist_R"
]

# 一旦全てのメッシュオブジェクトを選択無効に設定
for obj in [o for o in bpy.data.objects if o.type == 'MESH']:
    obj.hide_select = True

# オブジェクト名にあるオブジェクトを選択可能に設定
for name in namelist:
  bpy.data.objects[name].hide_select = False

b28om8_005_01g.png

このファイルはmodel08.zip (1.6MB)としてダウンロード できます。 適当に遊んでみてください。

関節のオブジェクトを回転させ過ぎてムチャクチャになっても、次のスクリプトを実行すると元の姿勢に戻ります。

# reset_rotation.py
import bpy

for obj in [o for o in bpy.data.objects if o.type == 'MESH']:
    obj.rotation_euler[0] = 0.0
    obj.rotation_euler[1] = 0.0
    obj.rotation_euler[2] = 0.0

ポーズを変えてみたところ。

model08c.png


pythonスクリプトをblendファイルに内蔵

気に入ったポーズになって、スカルプトモードで詳細を彫り込む場合は、選択して統合、リメッシュする必要があるので、次のスクリプトですべて選択できるように戻します。

# all_selectable.py
import bpy

for obj in bpy.data.objects:
    obj.hide_select = False

スクリプトをファイルとして保存すると、そのスクリプトをblendファイルに内蔵できます。

b28TextEditor1.png

blendファイルに内蔵されたスクリプトは、テキストエディターのヘッダーで選んでアドオンのようにすぐに実行できます。

b28TextEditor2.png


ページ先頭へ


Blender 2.8 の使い方 [目次]