Blender 2.8 の使い方 (08) Python スクリプト
前 (リトポロジー) www.mztn.org 次 (マテリアル1)
Blender 2.8 の使い方 (08) Python スクリプト
Blender は主要な部分は C や C++ で書かれていますが、多くの機能が Blender に組み込まれている Python でコントロールできるようになっています。 ユーザインターフェイスの多くの部分も Python で書かれています。
Python は最近人気のプログラミング言語なので、情報はネット上でも簡単に入手できると思います。 本格的にプログラミングしない人でも、数行のコマンドを記述するだけでも、作業の自動化や効率化に便利に使うことができます。
今回の blend ファイルは model08.zip (1.6MB)としてダウンロード できます。 Blender 2.90以降用はmodel082.zip (1.6MB) です。
Blender 2.8 には Python 3.7 が組み込まれていて、Blender 内で Python スクリプトを書いて実行することができ、アドオンの開発もできます。 多くのオブジェクトが存在していてマウスやペンで繰り返し操作するのが大変な場合などに、Python スクリプトを使うことで一瞬で作業を完了することができたり、各種の情報のリスト作成などに使うことができます。
Blender 内で Python スクリプトを使う
Blender 内で Python スクリプトを使うには、Python コンソールを使う方法と、内蔵のテキストエディターにスクリプトを記述して、そこで実行する方法があります。
Python コンソール (Shift + [F4])
エリア にヘッダーの左端のアイコンから「Python コンソール」を選ぶか、Shift + [F4]を押します。
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]を押します。
Pythonの文法にしたがって着色されるテキストエディターです。ヘッダー領域(リージョン)の右端に「スクリプト実行」ボタンがあって、python スクリプトを実行できます。 またメニューの「テンプレート」には、Blenderで使える多くのサンプルがあって非常に参考になります。
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
変数と型、代入
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 で親子関係を設定できます。親が移動、回転、拡大縮小すると、子孫も動くようになります。 「腕を上げれば、指も追従する」ということです。
ミラーモディファイアの一括適用と左右分離
人型モデルを構成するオブジェクトについて、次のような操作を行います。
- ミラーモディファイアを使ったオブジェクトを選んで、
- ミラーモディファイアを適用して、
- その結果としてできた左右対称のオブジェクトを左右で別のオブジェクトに分離して、
- 左右のオブジェクトに名前をつけて、
- オブジェクト自身の原点を設定する。
スクリプトは選択した範囲のオブジェクトの処理になりますが、ここではモデル全体を選択して処理します。次のプログラムリストの内容をテキストエディターに貼り付けます。
Blender 2.83までは以下のスクリプトを使用してください。
# 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'
Blender 2.90以降は以下のスクリプトを使用してください。赤字の部分が異なります。
# 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(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]キーを押してすべてのオブジェクトを選択してから、テキストエディターのヘッダー領域(リージョン)の右端にある「スクリプト実行」ボタンを押します。
ミラーモディファイアを適用して、オブジェクトを左右で分離した結果、オブジェクトの総数は以下のように 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 |
逆に、選択した複数のオブジェクトに対して一括でミラーモディファイアを設定するスクリプトです。 空間の原点に Emptyオブジェクトを配置するなどして、それを中心として引数で指定できます。
通常はオブジェクトの原点に対してミラーされますが、オブジェクトの原点とシーンの原点は異なることに注意が必要です。
# set_mirror.py # 選択したオブジェクトに対してミラーモディファイアを設定する # ミラーの中心のオブジェクト名を引数とする # 2020-05-28 Jun Mizutani def set_mirror(center_name): 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') obj.select_set(True) bpy.context.view_layer.objects.active = obj # ミラーモディファイアを追加する bpy.ops.object.modifier_add(type='MIRROR') obj.modifiers['Mirror'].mirror_object = bpy.data.objects[center_name]
>>> def set_mirror(center_name): ... 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') ... obj.select_set(True) ... bpy.context.view_layer.objects.active = obj ... # ミラーモディファイアを追加する ... bpy.ops.object.modifier_add(type='MIRROR') ... obj.modifiers['Mirror'].mirror_object = bpy.data.objects[center_name] ... >>> set_mirror('Empty')
親子関係の修正
このモデルの場合、ポーズを付けられるようにオブジェクト間に親子関係を設定しています。 腰を回すと肩も腕も指も回転するようにしています。しかし、破線が左右に広がっているのは、ミラーモディファイアで左側のオブジェクトを右側に反転コピーしても、親子関係は変わらず、右腕は左肩に付き、右指は、左指が親になっています。 親子関係を手作業で再構成する事はできますが、数が多いので大変です。
ここで、また新しい 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()
実行結果を示します。 親子関係を示す破線が消えています。 オブジェクトから見て右側のオブジェクトの親は、正しく右側のオブジェクトになっています。
位置をロック
親子関係のあるオブジェクトについて、親オブジェクトと独立して移動できないように制限します。 親から見た子の位置の変更を制限して、不用意にモデルが崩れるのを防ぐことにします。うっかりオブジェクトを移動してしまって「手首から先が離れてしまう」といった状況を予防します。 「位置制限」のコンストレイントを設定する方法もありますが、トランスフォームの「位置」をロックするほうが簡単です。
Blender の画面上のボタンなどのパーツを制御する python のコードは、プリファレンスで「Pythonツールチップを表示」にチェックを入れることで、上の図のオレンジの枠内のように Python のコードが表示されるので簡単です。
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回ぐらいのマウスのクリックが省略できました。
選択可能なオブジェクトを制限
今回のモデルのポースを変える場合、関節に当たるオブジェクトを回転させることで行います。 しかし、例えば手の指の場合はオブジェクト間の間隔が狭く、目的とするオブジェクトが選択し難くなっています。 そこで、選択する必要のないオブジェクトを選択できないように設定できると便利です。 そのためにはアウトラーナーエリアのフィルターのアイコンを押すと表示される「選択可能」項目をチェックして ON にします。
アウトラーナーエリアのオブジェクトの右側に矢印型の「選択無効」アイコンが表示されるようになります。
次のスクリプトでは、回転させる関節に当たるオブジェクト名をリストにしておいて、まず全体を選択不可にした後、リストに登録しているオブジェクトを順次選択可能に設定しています。
# 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
このファイルはmodel08.zip (1.6MB)としてダウンロード できます。 Blender 2.90以降ではmodel082.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
ポーズを変えてみたところ。
pythonスクリプトをblendファイルに内蔵
気に入ったポーズになって、スカルプトモードで詳細を彫り込む場合は、選択して統合、リメッシュする必要があるので、次のスクリプトですべて選択できるように戻します。
# all_selectable.py import bpy for obj in bpy.data.objects: obj.hide_select = False
スクリプトをファイルとして保存すると、そのスクリプトをblendファイルに内蔵できます。
blendファイルに内蔵されたスクリプトは、テキストエディターのヘッダーで選んでアドオンのようにすぐに実行できます。
ページ先頭へ
Blender 2.8 - 4.3 の使い方 [目次]
- (01) インストールと日本語化
- (02) 画面構成とモード
- (03) オブジェクトモード
- (04) 球と円柱でモデリング
- (05) スカルプトモード
- (06) 編集モード
- (07) リトポロジー
- (08) Python スクリプト
- (09) マテリアル (1)
- (10) マテリアル (2)
- (11) マテリアル (3)
- (12) アーマチュア(ボーン)
- (13) Rigifyによるリギング
- (14) パーティクルヘア
- (15) グリースペンシル
- (16) ジオメトリーノード (1)
- (17) ジオメトリーノード (2)
- (18) カメラ
- (19) ジオメトリーノード (3)
- (20) 新ヘアシステム Hair Curves
- (21) ヘアカーブの進化
- (22) Vector Displacement Mapブラシ
- (23) アセットライブラリ
- (24) シミュレーションゾーン
- (25) ボーンコレクションとRigify