はじめてのBlenderアドオン開発
Last Update: 2023.3.1
Blender 2.7
はじめてのBlenderアドオン開発
Blender 2.7
Last Update: 2023.3.1
2-4. ツール・シェルフのオプションを活用する②
本節では、オブジェクトを複製するアドオンのサンプルを紹介し、前節で解説したツール・シェルフについてより深く理解します。
本節で作成するアドオンの仕様を以下に示します。
1-5節 を参考にして以下のソースコードを入力し、ファイル名 sample_2_4.py
で保存してください。
import bpy
from bpy.props import FloatVectorProperty, EnumProperty
from mathutils import Vector
bl_info = {
"name": "サンプル2-4: オブジェクトを複製するアドオン",
"author": "Nutti",
"version": (2, 0),
"blender": (2, 75, 0),
"location": "3Dビュー > オブジェクト",
"description": "選択したオブジェクトを複製するアドオン",
"warning": "",
"support": "TESTING",
"wiki_url": "",
"tracker_url": "",
"category": "Object"
}
# EnumPropertyで表示したい項目リストを作成する関数
def location_list_fn(scene, context):
items = [
('3D_CURSOR', "3Dカーソル", "3Dカーソル上に配置します"),
('ORIGIN', "原点", "原点に配置します")
]
items.extend([
('OBJ_' + o.name, o.name, "オブジェクトに配置します")
for o in bpy.data.objects
])
return items
# 選択したオブジェクトを複製するアドオン
class ReplicateObject(bpy.types.Operator):
bl_idname = "object.replicate_object"
bl_label = "選択オブジェクトの複製"
bl_description = "選択中のオブジェクトを複製します"
bl_options = {'REGISTER', 'UNDO'}
location = EnumProperty(
name="配置位置",
description="複製したオブジェクトの配置位置",
items=location_list_fn
)
scale = FloatVectorProperty(
name="拡大率",
description="複製したオブジェクトの拡大率を設定します",
default=(1.0, 1.0, 1.0),
subtype='XYZ',
unit='LENGTH'
)
rotation = FloatVectorProperty(
name="回転角度",
description="複製したオブジェクトの回転角度を設定します",
default=(0.0, 0.0, 0.0),
subtype='AXISANGLE',
unit='ROTATION'
)
offset = FloatVectorProperty(
name="オフセット",
description="複製したオブジェクトの配置位置からのオフセットを設定します",
default=(0.0, 0.0, 0.0),
subtype='TRANSLATION',
unit='LENGTH'
)
def execute(self, context):
# bpy.ops.object.duplicate()実行後に複製オブジェクトが選択されるため、
# 選択中のオブジェクトを保存
# context.active_object.name:選択中のオブジェクトの名前
src_obj_name = context.active_object.name
# bpy.ops.object.duplicate():オブジェクトの複製
bpy.ops.object.duplicate()
active_obj = context.active_object
# 複製したオブジェクトを配置位置に移動
# context.active_object.location:選択中のオブジェクトの位置
if self.location == '3D_CURSOR':
# context.scene.cursor_location:3Dカーソルの位置
# Shallow copyを避けるため、copy()によるDeep copyを実行
active_obj.location = context.scene.cursor_location.copy()
elif self.location == 'ORIGIN':
active_obj.location = Vector((0.0, 0.0, 0.0))
elif self.location[0:4] == 'OBJ_':
# bpy.data.objects:配置されているオブジェクトのリスト
objs = bpy.data.objects
active_obj.location = objs[self.location[4:]].location.copy()
# 複製したオブジェクトの拡大率を設定
# context.active_object.scale:選択中のオブジェクトの拡大率
active_obj.scale.x = active_obj.scale.x * self.scale[0]
active_obj.scale.y = active_obj.scale.y * self.scale[1]
active_obj.scale.z = active_obj.scale.z * self.scale[2]
# 複製したオブジェクトの回転角度を設定
# context.active_object.rotation_euler:選択中のオブジェクトの回転角度
# (ラジアン)
rot_euler = active_obj.rotation_euler
active_obj.rotation_euler.x = rot_euler.x + self.rotation[0]
active_obj.rotation_euler.y = rot_euler.y + self.rotation[1]
active_obj.rotation_euler.z = rot_euler.z + self.rotation[2]
# 複製したオブジェクトの最終位置を設定
active_obj.location = active_obj.location + Vector(self.offset)
self.report({'INFO'}, "サンプル2-4: 「%s」を複製しました。" % (src_obj_name))
print("サンプル2-4: オペレーション「%s」が実行されました。" % (self.bl_idname))
return {'FINISHED'}
def menu_fn(self, context):
self.layout.separator()
self.layout.operator(ReplicateObject.bl_idname)
def register():
bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_object.append(menu_fn)
print("サンプル2-4: アドオン「サンプル2-4」が有効化されました。")
def unregister():
bpy.types.VIEW3D_MT_object.remove(menu_fn)
bpy.utils.unregister_module(__name__)
print("サンプル2-4: アドオン「サンプル2-4」が無効化されました。")
if __name__ == "__main__":
register()
1-5節 を参考にして、作成したアドオンを有効化すると、コンソールウィンドウに以下の文字列が出力されます。
サンプル2-4: アドオン「サンプル2-4」が有効化されました。
アドオン有効化後、[3Dビュー] エリアのメニューに [オブジェクト] > [選択オブジェクトの複製] が追加されていることを確認します。
以下の手順に従って、作成したアドオンの機能を使ってみます。
1 | Blender起動直後に生成される [Cube] を選択した状態で追加されたメニューを実行すると、選択したCubeが複製されます。 また、スクリプト実行ログに以下のメッセージが表示されます。 サンプル2-4: 「Cube」を複製しました。 |
2 | [3Dビュー] エリアのツール・シェルフに表示されたオプションの値を変更すると、変更した値に応じて複製されたオブジェクトの形が変化します。 |
本節のサンプルでは、以下に示すオプションが利用可能です。
オプション名 | オプション指定による動作への影響 |
---|---|
配置位置 | 3Dカーソル : 3Dカーソルの位置に複製オブジェクトを配置します 原点 : [3Dビュー] エリアの原点に複製オブジェクトを配置します オブジェクト名 : 選択したオブジェクトの中心位置に複製オブジェクトを配置します |
拡大率 | 複製したオブジェクトについて、複製元のオブジェクトに対する拡大率を設定します |
回転角度 | 複製したオブジェクトについて、複製元オブジェクトからの回転角度の差分をオイラー角で設定します |
オフセット | 複製したオブジェクトについて、配置位置からのオフセット位置を指定します |
1-5節 を参考にしてアドオンを無効化すると、コンソールウィンドウに以下の文字列が出力されます。
サンプル2-4: アドオン「サンプル2-4」が無効化されました。
本節のサンプルは、2-3節 で紹介したサンプルを改造したものです。 ここでは、 2-3節 で解説していない部分について解説します。 なお、新しく登場するBlender APIの説明は、ソースコードのコメントとして記載しています。
EnumProperty
クラスを用いると、ユーザがセレクトボックスにより値を選択することが可能なUIを作成することできます。 EnumProperty
クラスを用いてセレクトボックスに選択項目を追加するためには、EnumProperty
クラス作成時の引数 items
に選択項目のリストを渡す必要があります。
以下に、選択項目に [3Dカーソル] と [原点] を追加するコードを示します。
location_list = [
('3D_CURSOR', "3Dカーソル", "3Dカーソル上に配置します"),
('ORIGIN', "原点", "原点に配置します")]
location = EnumProperty(
name = "配置位置",
description = "複製したオブジェクトの配置位置",
items = location_list
)
items
に以下の要素からなるタプルの配列を渡しています。
要素 | 要素の意味 |
---|---|
第1要素 | 識別子(項目選択時に変数 items に設定される値) |
第2要素 | セレクトボックスに表示される項目名 |
第3要素 | セレクトボックスに表示される項目の説明 |
これでセレクトボックスを作ることができましたが、[3Dビュー] エリアに配置されているオブジェクトの位置に複製したオブジェクトを配置するための項目が足りません。
基本的には [3Dビュー] エリア上に存在するオブジェクト名一覧を項目に追加すれば良さそうですが、存在するオブジェクトは処理の実行状況に応じて変化するため、items
に渡す項目リストを動的に生成する必要があります。 例えば、[3Dビュー] エリアのメニューである、[オブジェクト] > [選択オブジェクトの複製] を実行した後に、[オブジェクト] > [選択オブジェクトの複製] を再度実行した場合、最初に複製したオブジェクトを複製オブジェクトの配置先として選べる必要があります。 このため、本節のサンプルでは以下のようにして EnumProperty
クラスにより作られるセレクトボックスの選択項目を動的に追加する処理を記載しています。
# EnumPropertyで表示したい項目リストを作成する関数
def location_list_fn(scene, context):
items = [
('3D_CURSOR', "3Dカーソル", "3Dカーソル上に配置します"),
('ORIGIN', "原点", "原点に配置します")
]
items.extend([
('OBJ_' + o.name, o.name, "オブジェクトに配置します")
for o in bpy.data.objects
])
return items
location = EnumProperty(
name="配置位置",
description="複製したオブジェクトの配置位置",
items=location_list_fn
)
EnumProperty
クラスの items
に項目リストを渡す代わりに、項目リストを返す location_list_fn
関数を渡しています。
location_list_fn
関数は、3Dカーソルと原点についてセレクトボックスの選択項目リストを作成した後、[3Dビュー] 上に置かれている全オブジェクトについてセレクトボックスの選択項目を作成してリストに追加しています。 そして最後に、作成したリストを返して関数が復帰します。
このように、セレクトボックスの選択項目リストを返す関数を EnumProperty
クラスの items
に指定することで、選択項目を動的に追加することができます。
本節のサンプルでは、配置位置の他にも拡大率・回転角度・配置位置からのオフセットを、ツール・シェルフから指定できます。 これを実現するため、FloatVectorProperty
クラスのインスタンス化時に、目的に沿った値に応じて引数 subtype
を指定しています。 subtype
に指定可能な値とUIの例を以下に示します。
値 | 値の説明 | UI例 |
---|---|---|
NONE |
3要素から構成されるプロパティグループ | |
COLOR |
カラーパレット(RGBの3要素から構成されるプロパティグループ) | |
TRANSLATION |
X軸、Y軸、Z軸の3要素から構成されるプロパティグループ(単位はcm、mなど) | |
VELOCITY |
X軸、Y軸、Z軸の3要素から構成されるプロパティグループ(単位はm/s) | |
ACCELERATION |
X軸、Y軸、Z軸の3要素から構成されるプロパティグループ(単位はm/s2) | |
EULER |
X軸、Y軸、Z軸の3要素から構成されるプロパティグループ(単位は°) | |
QUATERNION |
3要素(W、X、Y)から構成されるプロパティグループ | |
AXISANGLE |
3要素(W、X、Y)から構成されるプロパティグループ(単位は°) | |
XYZ |
X軸、Y軸、Z軸の3要素から構成されるプロパティグループ |
また引数 unit
を指定すると、以下のような単位をUIに表示させることができます。
値 | 値の説明 | UI上での表示単位 (表示単位を度数表記・メートル法にした場合) |
---|---|---|
NONE |
引数 subtype に指定した値に応じて表示される単位が決定 |
|
LENGTH |
長さ | cm |
AREA |
面積 | cm2、m2など |
VOLUME |
長さ | cm3、m3など |
ROTATION |
角度 | ° |
TIME |
時間 | (単位なし) |
VELOCITY |
速度 | m/s |
ACCELERATION |
加速度 | m/s2 |
2-3節 で紹介したツール・シェルフのプロパティを用いて、アドオンを作成しました。
ツール・シェルフのプロパティを用いると、直前に行った操作に対してユーザがより細かい調整を行った上で操作を再実行することができます。 ただし特定の機能に対してプロパティを追加しすぎると、指示できる項目が多すぎてかえってわかりづらくなるという問題もありますので、本当に必要な項目かどうかを見極めてプロパティを追加していきましょう。
EnumProperty
生成時の引数 items
に選択項目リストを返す関数を指定することで、セレクトボックスの選択項目を動的に追加できるsubtype
を指定することで、目的に沿ったプロパティを簡単に作成できるunit
を指定することで、UIに単位を表示することができる