bpy (Blender Python API)を用いたUV展開の方法について、備忘録として考えをまとめておきます。
UV展開とは、立体のオブジェクトの面にマテリアル(イラストや画像等)を割り当てるために、平面に展開するための作業です。
動作確認環境 : Blender 4.2
UV展開フォーマットを考える
UV展開を行うにあたり、必要な処理は次のように分類されると思います。
- モディファイアの適用
- 全適用(オブジェクト位置, サイズ, 回転, 中心点初期化)
- シーム(切れ目)のマーク
- UV展開
- 展開後の要素整理
モディファイアの適用
モディファイア(非破壊的効果)はオブジェクトのメッシュそのものを変更しているわけではないので、モディファイア追加後、増えた面に対してUV展開は適用されません。
ベベルやソリッド化のモディファイアをオブジェクトに追加後、モディファイアを適用することで上記のようにUV展開の対象に含めることができます。
オブジェクトにマテリアルをどのように付与するかによっては、適用が必要ない場合もあります。
全適用
UV展開の際に、スケールの適用を行いスケールを1にしておかないと、特定の面が意図せず大きくスケールされるなど、面積比が実際のオブジェクト上の面の大きさとずれることがあるようです。
スケール適用をUV展開前に行います。
シーム(切れ目)のマーク
オブジェクトを展開するために、展開位置を示すシーム(切れ目)を入れていきます。
- 要素の選択
- シームとしてマーク
Python :
# 要素選択
element_select(
element_list=[1, 2, 3, 6, 7, 9, 10
]
, select_mode="EDGE"
, object_name_list=[OB_TEMP_00]
)
シームをマークする際は非常に多くの辺の選択が必要になるため、テキストベースで1つ1つのインデックスを指定していては時間がかかりすぎます。
マウスである程度辺を選択したうえで辺のインデックスリストを取得し、コード上へコピペするのが無難です。
▼element_select
▼選択インデックス取得
以下で選択した辺をシームとしてマークします。
Python :
# シームをマーク
bpy.ops.mesh.mark_seam(clear=False)
UV展開
UV展開にはシームに従って手動でオブジェクトを展開する方法と、自動でUV展開する方法があります。
シームを用いてUnwrap
Python :
# UV 展開
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0)
自動でUnwrap
Python :
# UV 展開
bpy.ops.uv.smart_project(angle_limit=math.radians(89))
展開後の要素整理
UV展開後にUV Editor上に展開された要素を整理するための処理をいくつか行います。
Python :
# UV Editor内のすべてのUVを選択
bpy.ops.uv.select_all(action='SELECT')
# UVの回転を揃える
bpy.ops.uv.align_rotation()
# アイランドをパックして整理
bpy.ops.uv.pack_islands(rotate=True, margin=0.001)
# UV展開後にストレッチを最小化
bpy.ops.uv.minimize_stretch()
UV展開処理の例
キューブを追加してUV展開を行う例を示します、
Python :
def Base_create():
bpy.ops.object.mode_set(mode='OBJECT')
# 立方体を追加
bpy.ops.mesh.primitive_cube_add(
size=1
, location=(0, 0, 0)
, scale=(1,1,1)
)
# 名前設定
bpy.context.object.name = "cube_00"
# Mode切り替え
bpy.ops.object.mode_set(mode='OBJECT')
# ----------------------------------
# オブジェクト全適用
# ----------------------------------
object_list=["cube_00"]
# 全適用
# オブジェクト位置, サイズ, 回転, 中心点初期化
for i in range(len(object_list)):
initialize_transform_apply(
object_name_list=[object_list[i]]
)
OB_TEMP_00 = "cube_00"
# ----------------------------------
# シーム(切れ目を入れる)
# ----------------------------------
# アクティブオブジェクト
active_element_select(object_name_list=[OB_TEMP_00])
# インデックスをソート
sort_element_index_wrap(element_type="EDGE")
# Mode切り替え
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='EDGE')
# 要素選択
element_select(
element_list=[1, 2, 3, 6, 7, 9, 10
]
, select_mode="EDGE"
, object_name_list=[OB_TEMP_00]
)
# ループ選択(Alt+Click) / 一周選択
# bpy.ops.mesh.loop_multi_select(ring=False)
# シームをマーク
bpy.ops.mesh.mark_seam(clear=False)
# ----------------------------------
# UV展開
# ----------------------------------
# 要素選択
element_select(
element_list=["all"]
, select_mode="FACE"
, object_name_list=[OB_TEMP_00]
)
# UV 展開
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0)
# bpy.ops.uv.smart_project(angle_limit=math.radians(89))
# UV Editor内のすべてのUVを選択
bpy.ops.uv.select_all(action='SELECT')
# UVの回転を揃える
bpy.ops.uv.align_rotation()
# アイランドをパックして整理
bpy.ops.uv.pack_islands(rotate=True, margin=0.001)
# UV展開後にストレッチを最小化
bpy.ops.uv.minimize_stretch()
Base_create()
▼sort_element_index_wrap
以上