MRが楽しい

MRやVRについて学習したことを書き残す

Blender2.8で利用可能なpythonスクリプトを作る その37(UVマップのピン止め)

本日は Blender の技術調査枠です。
Blender2.8で利用可能なpythonスクリプトを作ります。

UVマップの全頂点をピン止めする

UVマップの全頂点をピン止めします。
指定のUVマップが存在しない場合は処理ません。
ビューを通さず、直接UVのピン止め情報にアクセスします。
・pin_UVmap_all.py

# bpyインポート
import bpy
# メッシュ操作のため
import bmesh

# UVマップの全頂点をピン止めする
def pin_UVmap_all(arg_objectname="Default", arg_uvname="UVMap") -> bool:
    """UVマップの全頂点をピン止めする

    Keyword Arguments:
        arg_objectname {str} -- 指定オブジェクト名 (default: {"Default"})
        arg_uvname {str} -- 指定UVマップ名 (default: {"UVMap"})

    Returns:
        bool -- 実行正否
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    selectob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if selectob == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return False
    
    # オブジェクトがメッシュであるか確認する
    if selectob.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return False

    # 指定オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = selectob

    # 元々の操作モードを記録する
    befmode = bpy.context.active_object.mode

    # 編集モードに移行する
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)

    # Bメッシュデータを取得する
    # Bメッシュアクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh)
    bmeshdata = bmesh.from_edit_mesh(selectob.data)

    # UVレイヤーの参照を取得する
    # レイヤーアクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMLayerAccessLoop)
    targetuvlayer = bmeshdata.loops.layers.uv.get(arg_uvname)

    # 指定UVマップが存在するか確認する
    if targetuvlayer == None:
        # 指定UVマップが存在しない場合は処理しない
        return False

    # メッシュの面の参照からUVマップの頂点を編集する
    # 面の参照を取得する
    # 面アクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMFace)
    for face in bmeshdata.faces:
        # 要素の参照を取得する
        # 要素アクセスのマニュアル
        # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMElemSeq)
        for loop in face.loops:
            # UVレイヤーの参照を取得する
            loop_uv = loop[targetuvlayer]

            # 頂点のUV情報を取得してピンを設定する
            # UV情報アクセスのマニュアル
            # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMLoopUV)
            loop_uv.pin_uv = True

    # メッシュ情報を更新する
    bmesh.update_edit_mesh(selectob.data)

    # 変更前のモードに移行する
    bpy.ops.object.mode_set(mode=befmode)

    return True

# 関数の実行例
pin_UVmap_all(arg_objectname="Sphere", arg_uvname="UVMap")

f:id:bluebirdofoz:20200531202430j:plain

選択中の頂点のUVマップの頂点をピン止めする

選択中の頂点のUVマップの頂点をピン止めします。
指定のUVマップが存在しない場合は処理ません。
サンプルはメッシュにおけるY軸の端の頂点を選択してピン留めします。
・pin_UVmap_selected.py

# bpyインポート
import bpy
# メッシュ操作のため
import bmesh

# 選択中の頂点のUVマップの頂点をピン止めする
def pin_UVmap_selected(arg_objectname="Default", arg_uvname="UVMap") -> bool:
    """選択中の頂点のUVマップの頂点をピン止めする

    Keyword Arguments:
        arg_objectname {str} -- 指定オブジェクト名 (default: {"Default"})
        arg_uvname {str} -- 指定UVマップ名 (default: {"UVMap"})

    Returns:
        bool -- 実行正否
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    selectob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if selectob == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return False
    
    # オブジェクトがメッシュであるか確認する
    if selectob.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return False

    # 指定オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = selectob

    # 元々の操作モードを記録する
    befmode = bpy.context.active_object.mode

    # 編集モードに移行する
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)

    # Bメッシュデータを取得する
    # Bメッシュアクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh)
    bmeshdata = bmesh.from_edit_mesh(selectob.data)

    # UVレイヤーの参照を取得する
    # レイヤーアクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMLayerAccessLoop)
    targetuvlayer = bmeshdata.loops.layers.uv.get(arg_uvname)

    # 指定UVマップが存在するか確認する
    if targetuvlayer == None:
        # 指定UVマップが存在しない場合は処理しない
        return False

    # メッシュの面の参照からUVマップの頂点を編集する
    # 面の参照を取得する
    # 面アクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMFace)
    for face in bmeshdata.faces:
        # 要素の参照を取得する
        # 要素アクセスのマニュアル
        # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMElemSeq)
        for loop in face.loops:
            # 頂点が選択中か否か判定する
            if loop.vert.select == True:
                # UVレイヤーの参照を取得する
                loop_uv = loop[targetuvlayer]

                # 頂点のUV情報を取得してピンを設定する
                # UV情報アクセスのマニュアル
                # (https://docs.blender.org/api/current/bmesh.types.html#bmesh.types.BMLoopUV)
                loop_uv.pin_uv = True

    # メッシュ情報を更新する
    bmesh.update_edit_mesh(selectob.data)

    # 変更前のモードに移行する
    bpy.ops.object.mode_set(mode=befmode)

    return True

# Y軸座標が最大または最小の座標の頂点を選択する
def select_vert_Ytip(arg_objectname="Default", arg_uvname="UVMap", arg_max=False) -> bool:
    """Y軸座標が最大または最小の座標の頂点を選択する

    Keyword Arguments:
        arg_objectname {str} -- 指定オブジェクト名 (default: {"Default"})
        arg_uvname {str} -- 指定UVマップ名 (default: {"UVMap"})
        arg_max {bool} -- 最大値の端か否か (default: {True})

    Returns:
        bool -- 実行正否
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    selectob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if selectob == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return False
    
    # オブジェクトがメッシュであるか確認する
    if selectob.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return False

    # 指定オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = selectob

    # 元々の操作モードを記録する
    befmode = bpy.context.active_object.mode

    # 編集モードに移行する
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)

    # Bメッシュデータを取得する
    # Bメッシュアクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMesh)
    bmeshdata = bmesh.from_edit_mesh(selectob.data)

    # 選択モードを頂点選択モードにする
    bmeshdata.select_mode = {'VERT'}

    # 頂点を走査する
    # 頂点アクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMVert)
    for vert in bmeshdata.verts:
        # 全ての頂点は一旦選択状態を解除する
        vert.select = False

    # Y座標の比較用変数を初期化
    Ytip_pos = 0.0
    Ytip_index = -1
    
    # 頂点を走査する
    # 頂点アクセスのマニュアル
    # (https://docs.blender.org/api/current/bmesh.types.html?highlight=bmedge#bmesh.types.BMVert)
    for vert in bmeshdata.verts:
        # 1つ目の座標は基準として取得する
        if Ytip_index == -1:
            # 座標の値とインデックスを取得する
            Ytip_pos = vert.co[1]
            Ytip_index = vert.index
        else:
            # Y軸座標が最大または最小の座標かチェックする
            if (vert.co[1] > Ytip_pos) == arg_max:
                # 座標の値とインデックスを取得する
                Ytip_pos = vert.co[1]
                Ytip_index = vert.index

    # インデックス参照のため、テーブルを初期化する
    bmeshdata.verts.ensure_lookup_table()

    # Y軸座標が最大または最小の座標を選択する
    if Ytip_index > -1:
        bmeshdata.verts[Ytip_index].select = True

    # 辺または面の選択状態を更新する
    bmeshdata.select_flush_mode()

    # 変更前のモードに移行する
    bpy.ops.object.mode_set(mode=befmode)

    return True

# 関数の実行例
select_vert_Ytip(arg_objectname="Sphere", arg_uvname="UVMap", arg_max=False)
pin_UVmap_selected(arg_objectname="Sphere", arg_uvname="UVMap")

f:id:bluebirdofoz:20200531202449j:plain