bpy.ops.transform による変換【第 7 回 Python × Blender】
今回はbpy.ops.transform
による変換についての記事です。
まずは以下のut.py
という Python スクリプトを Blender で実行してみてください。このスクリプトのif __name__ == "__main__"
以下の部分はbpy.ops.transform
を説明するためのスクリプト例です。
import bpy import math # 全てのオブジェクトを選択. def select_all(): bpy.ops.object.select_all(action='SELECT') # 全てのオブジェクトの選択を解除. def deselect_all(): bpy.ops.object.select_all(action='DESELECT') # 名前 obj_name を持つオブジェクトを選択. deselect==False の時には, 以前に選択したオブジェクトの選択は保たれる. def select(obj_name, deselect=True): if deselect: deselect_all() bpy.data.objects[obj_name].select = True # 名前 obj_name を持つオブジェクトのアクティブ化. def activate(obj_name): bpy.context.scene.objects.active = bpy.data.objects[obj_name] class selected: ''' 選択された全てのオブジェクトに対する操作関数クラス. ''' #(変換)vector 分だけ移動. def translate(vector): bpy.ops.transform.translate(value=vector, constraint_axis=(True,True,True)) #(変換)ratios 分だけ x,y,z 軸方向に拡大. def scale(ratios): bpy.ops.transform.resize(value=ratios, constraint_axis=(True,True,True)) #(変換)axis_vector 回転軸に angle だけ回転. def rotate(axis_vector, angle): bpy.ops.transform.rotate(value=angle, axis=axis_vector) #(変換)x 軸を回転軸に angle だけ回転. def x_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(1,0,0)) #(変換)y 軸を回転軸に angle だけ回転. def y_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(0,1,0)) #(変換)z 軸を回転軸に angle だけ回転. def z_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(0,0,1)) class activated: ''' アクティブ化しているオブジェクトに対する操作関数クラス. ''' #(宣言)location に位置を変更. def locate(location): bpy.context.object.location = location #(宣言)ratios 分だけ x,y,z 軸方向に拡大. def scale(ratios): bpy.context.object.scale = ratios #(宣言)オイラー角 euler_angles 分回転. def rotate(euler_angles): bpy.context.object.rotation_euler = euler_angles #(宣言)名前の変更. def rename(new_name): bpy.context.object.name = new_name class specified: ''' specified されたオブジェクトに対する操作関数クラス. ''' #(宣言)obj_name を名前に持つオブジェクトの位置を location に変更. def locate(obj_name, location): bpy.data.objects[obj_name].location = location #(宣言)obj_name を名前に持つオブジェクトを ratios 分だけ x,y,z 軸方向に拡大. def scale(obj_name, ratios): bpy.data.objects[obj_name].scale = ratios #(宣言)obj_name を名前に持つオブジェクトの位置をオイラー角 euler_angles 分回転. def rotate(obj_name, euler_angles): bpy.data.objects[obj_name].rotation_euler = euler_angles class create: ''' オブジェクトの生成関数クラス. ''' # 立方体を配置. def cube(new_name, new_radius=0.5, new_location=(0,0,0)): bpy.ops.mesh.primitive_cube_add(radius=new_radius, location=new_location) activated.rename(new_name) # 球を配置. def sphere(new_name, new_size=0.5, new_location=(0,0,0)): bpy.ops.mesh.primitive_uv_sphere_add(size=new_size, location=new_location) activated.rename(new_name) # 円錐を配置. def cone(new_name, new_radius1=0.5, new_depth=1, new_location=(0,0,0)): bpy.ops.mesh.primitive_cone_add(radius1=new_radius1, depth=new_depth, location=new_location) activated.rename(new_name) # 円柱を配置. def cylinder(new_name, new_radius=0.5, new_depth=1, new_location=(0,0,0)): bpy.ops.mesh.primitive_cylinder_add(radius=new_radius, depth=new_depth, location=new_location) activated.rename(new_name) # 名前 delete_name を持つオブジェクトを削除. def delete(delete_name): selected_name_list = [obj.name for obj in bpy.context.selected_objects if not obj.name == delete_name] select(obj_name=delete_name, deselect=True) bpy.ops.object.delete(use_global=False) for selected_name in selected_name_list: select(selected_name, False) # 全てのオブジェクトを削除. def delete_all(): if len(bpy.data.objects) > 0: select_all() bpy.ops.object.delete(use_global=False) if __name__ == "__main__": ''' import ut では以降のスクリプトは実行されない. ''' # 初期化 delete_all() # 立方体を 5×5×5 で配置. for i in range(5): x = -2 + i for j in range(5): y = -2 + j for k in range(5): z = -2 + k # 立方体の位置. cube_location = (x, y, z) # 立方体の名前. cube_name = "Cube." + str(i) + str(j) + str(k) # 立方体を配置. create.cube(cube_name) # 立方体(アクティブ化されている)の名前の確認. print(bpy.context.object.name) # 立方体(アクティブ化されている)の位置を設定(宣言). activated.locate(cube_location) # 全ての立方体を選択. select_all() # 選択されている全ての立方体を (1, 1, 1) 中心に 60° 回転(変換). selected.rotate((1, 1, 1), math.pi / 3) # 選択されている全ての立方体を x 軸方向に 1.5 倍, y 軸方向に 3 倍(変換). selected.scale((1.5, 3, 1))
実行結果は以下のようになります。
ターミナルは以下のようになっているでしょう。
Cube.000 Cube.001 Cube.002 Cube.003 Cube.004 Cube.010 Cube.011 Cube.012 Cube.013 Cube.014 Cube.020 Cube.021 Cube.022 Cube.023 Cube.024 Cube.030 Cube.031 Cube.032 Cube.033 Cube.034 Cube.040 Cube.041 Cube.042 Cube.043 Cube.044 Cube.100 Cube.101 Cube.102 Cube.103 Cube.104 Cube.110 Cube.111 Cube.112 Cube.113 Cube.114 Cube.120 Cube.121 Cube.122 Cube.123 Cube.124 Cube.130 Cube.131 Cube.132 Cube.133 Cube.134 Cube.140 Cube.141 Cube.142 Cube.143 Cube.144 Cube.200 Cube.201 Cube.202 Cube.203 Cube.204 Cube.210 Cube.211 Cube.212 Cube.213 Cube.214 Cube.220 Cube.221 Cube.222 Cube.223 Cube.224 Cube.230 Cube.231 Cube.232 Cube.233 Cube.234 Cube.240 Cube.241 Cube.242 Cube.243 Cube.244 Cube.300 Cube.301 Cube.302 Cube.303 Cube.304 Cube.310 Cube.311 Cube.312 Cube.313 Cube.314 Cube.320 Cube.321 Cube.322 Cube.323 Cube.324 Cube.330 Cube.331 Cube.332 Cube.333 Cube.334 Cube.340 Cube.341 Cube.342 Cube.343 Cube.344 Cube.400 Cube.401 Cube.402 Cube.403 Cube.404 Cube.410 Cube.411 Cube.412 Cube.413 Cube.414 Cube.420 Cube.421 Cube.422 Cube.423 Cube.424 Cube.430 Cube.431 Cube.432 Cube.433 Cube.434 Cube.440 Cube.441 Cube.442 Cube.443 Cube.444
Blender での Python スクリプトの動かし方は以下の記事を参考にしてください。
tamaki-py.hatenablog.com
今回説明したいのはbpy.ops.transform
です。上記のコード中では、選択されたオブジェクトに対する操作関数クラスであるselected
クラスの部分です。
class selected: ''' 選択された全てのオブジェクトに対する操作関数クラス. ''' #(変換)vector 分だけ移動. def translate(vector): bpy.ops.transform.translate(value=vector, constraint_axis=(True,True,True)) #(変換)ratios 分だけ x,y,z 軸方向に拡大. def scale(ratios): bpy.ops.transform.resize(value=ratios, constraint_axis=(True,True,True)) #(変換)axis_vector 回転軸に angle だけ回転. def rotate(axis_vector, angle): bpy.ops.transform.rotate(value=angle, axis=axis_vector) #(変換)x 軸を回転軸に angle だけ回転. def x_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(1,0,0)) #(変換)y 軸を回転軸に angle だけ回転. def y_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(0,1,0)) #(変換)z 軸を回転軸に angle だけ回転. def z_rotate(angle): bpy.ops.transform.rotate(value=angle, axis=(0,0,1))
このスクリプトからもわかるように、選択されている全てのオブジェクトの移動・拡大縮小・回転といった『変換型(differential)』の操作を行うことができるのがbpy.ops.transform
クラスです。ドキュメンテーションは以下をご覧ください。
docs.blender.org
また注意していただきたいのは、アクティブ化されたオブジェクトに対する操作関数クラスactivated
・specified されたオブジェクトに対する操作関数クラスspecified
の関数は、選択されたオブジェクトに対する操作関数クラスであるselected
クラスと違って「宣言型(declarative)」の操作関数であるということです。
class activated: ''' アクティブ化しているオブジェクトに対する操作関数クラス. ''' #(宣言)location に位置を変更. def locate(location): bpy.context.object.location = location #(宣言)ratios 分だけ x,y,z 軸方向に拡大. def scale(ratios): bpy.context.object.scale = ratios #(宣言)オイラー角 euler_angles 分回転. def rotate(euler_angles): bpy.context.object.rotation_euler = euler_angles #(宣言)名前の変更. def rename(new_name): bpy.context.object.name = new_name class specified: ''' specified されたオブジェクトに対する操作関数クラス. ''' #(宣言)obj_name を名前に持つオブジェクトの位置を location に変更. def locate(obj_name, location): bpy.data.objects[obj_name].location = location #(宣言)obj_name を名前に持つオブジェクトを ratios 分だけ x,y,z 軸方向に拡大. def scale(obj_name, ratios): bpy.data.objects[obj_name].scale = ratios #(宣言)obj_name を名前に持つオブジェクトの位置をオイラー角 euler_angles 分回転. def rotate(obj_name, euler_angles): bpy.data.objects[obj_name].rotation_euler = euler_angles
「変換」と「宣言」の違いは、
- 変換は既にあるオブジェクトのデータを基準にオブジェクトを変形する。
- 宣言はオブジェクトのデータを書き換える。
ということです。
例えばbpy.ops.transform.translate(value=vector, constraint_axis=(True,True,True))
は選択された全てのオブジェクトを、そのオブジェクトの存在する位置から 3 次元 float 型配列ベクトルvector
分だけ移動する「変換」なのに対し、
bpy.context.object.location = location
はアクティブ化されているオブジェクトの位置をそもそも書き換えてしまっている「宣言」型の操作です。
今回のこのut.py
はあくまで最も簡単なツールのモジュールとして定義しているだけではありますが、長いコードを関数で短くスッキリ書くことを可能にしていますので、これからもimport
で用いていきます。