2017年5月10日水曜日

XY座標をUVに

Blenderの作業で3Dビュー上の頂点座標をUVマップの値に変換する必要があって
アドオンを作ってみたのでメモ。

厳密に値を合わせるのでなければ通常の「プロジェクション」展開や
たまに使う程度なら UV投影(UVProject)モデファイアを使えばいいので
これ自体を他の人が使うことはなさそうですが UV設定のスクリプトの参考に残しておきます。

bl_info = {
    "name": "projection UV as XY plane",
    "description": "XY平面の座標をUVに",
    "author": "Yukimi",
    "version": (0,2),
    "blender": (2, 6, 0),
    "location": "Object",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Object"}

import bpy
class UV_ptoject_xy(bpy.types.Operator):
    bl_idname = "object.uv_ptoject_xy"
    #bl_label = "Projection UV  XY-plane"
    bl_label = "XY平面の座標をUVに"
    bl_options = {'REGISTER', 'UNDO'}
    def execute(self, context):
        #形状の取得
        obj = context.active_object
        #グローバル座標への変換マトリクス
        matrix_world = obj.matrix_world
        #頂点座標の取得
        location_list = [v.co*matrix_world for v in obj.data.vertices]
        uv_list = [p[:2] for p in location_list]
        #UVレイヤがない場合は新規作成
        if obj.data.uv_layers.active_index == -1:
            obj.data.uv_textures.new()
        mode = context.mode
        if  (mode == 'OBJECT'):
            self.on_objmode(obj, uv_list)
        elif (mode == 'EDIT_MESH'):
            self.on_editmode(obj, uv_list)
        return {'RUNNING_MODAL'}
    def on_editmode(self, obj, uv_list):
        """
        編集モードでのUVの設定
        """
        #状態の更新
        bpy.context.edit_object.update_from_editmode()
        import bmesh
        mesh = obj.data
        bm = bmesh.from_edit_mesh(mesh)   # メッシュからBMeshを作成
        #アクティブなUV_layer
        #(bmeshで使うにはUV LayerもBMeshオブジェクトでないといけない)
        uv_layer = bm.loops.layers.uv.active
        #UVの設定
        for bm_face in bm.faces:
            for v in bm_face.loops:
                id = v.vert.index
                v[uv_layer].uv = uv_list[id]
        bmesh.update_edit_mesh(mesh)
            
                    
    def on_objmode(self, obj, uv_list):
        """
        オブジェクトモードでのUVの設定(アドオンでは未使用)
        """
        #アクティブなUVレイヤを取得
        uv_index =obj.data.uv_layers.active_index
        uv_layer = obj.data.uv_layers[uv_index]
        #UVの設定
        for f in obj.data.polygons:
            for i,loop_id in enumerate(f.loop_indices):
                uv_layer.data[ loop_id ].uv = uv_list[i]

################################################
#メニュー項目の設定
def menu_funk(self, context):
    self.layout.operator("object.uv_ptoject_xy")
 # アドオン有効化時の処理
def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_uv_map.append(menu_funk)
 
# アドオン無効化時の処理
def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_uv_map.remove(menu_funk)
################################################    
 
 
# メイン処理
if __name__ == "__main__":
    register()

編集モード時のUVマッピングメニューの末尾に登録しています

非常に単純な機能ですが
UVの取得は少し手順が多いのと
エディットモードでのデータを操作するのにbmeshを使って "bmesh.from_edit_mesh(mesh)" で今ある形状からBmeshオブジェクトを作成し
"bmesh.update_edit_mesh(mesh)" で変更を適応する
といったことは やり方を忘れてしまいがちですね