[maya][python]接合したメッシュの法線をいい感じに丸く滑らかにするツール furcraeaSmoothNormalTool.pyとfurcraeaSeamNormalTool.py

できます。まずは 選択したメッシュ、フェース、頂点の法線を滑らかにする Maya Python ツールとして作るのが扱いやすいです。

下のコードは、次の機能を持っています。

  • 選択範囲だけ法線をソフト化
  • メッシュ全体をソフト化
  • 角度を指定
  • 法線ロック解除
  • 法線の平均化
  • ハードエッジ化
  • 法線履歴の削除

furcraeaSmoothNormalTool.py

# -*- coding: utf-8 -*-
import maya.cmds as cmds


WINDOW_NAME = "furcraeaSmoothNormalTool"


def get_selected_mesh_components():
    """
    現在の選択を取得します。
    オブジェクト選択の場合は、そのメッシュ全体を返します。
    コンポーネント選択の場合は、そのまま返します。
    """
    selection = cmds.ls(selection=True, long=True, flatten=True) or []

    if not selection:
        cmds.warning("メッシュ、フェース、エッジ、頂点を選択してください。")
        return []

    result = []

    for item in selection:
        # コンポーネント選択
        if "." in item:
            result.append(item)
            continue

        # TransformからShapeを取得
        if cmds.nodeType(item) == "transform":
            shapes = cmds.listRelatives(
                item,
                shapes=True,
                noIntermediate=True,
                fullPath=True
            ) or []

            mesh_shapes = [
                shape for shape in shapes
                if cmds.nodeType(shape) == "mesh"
            ]

            if mesh_shapes:
                result.append(item)

        # Shapeが直接選択されている場合
        elif cmds.nodeType(item) == "mesh":
            parents = cmds.listRelatives(
                item,
                parent=True,
                fullPath=True
            ) or []

            if parents:
                result.append(parents[0])

    if not result:
        cmds.warning("選択内にポリゴンメッシュがありません。")

    return result


def unlock_normals():
    """選択したメッシュまたはコンポーネントの法線ロックを解除します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

        cmds.inViewMessage(
            amg="<hl>法線ロックを解除しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def soften_normals(angle=None):
    """
    指定角度以下のエッジをソフト化します。

    angle:
        180の場合、基本的にすべてのエッジを滑らかにします。
        30~60程度なら、鋭い角を残しやすくなります。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    if angle is None:
        angle = cmds.floatSliderGrp(
            "smoothNormalAngleSlider",
            query=True,
            value=True
        )

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            # ロックされた法線がある場合に備えて解除
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

            cmds.polySoftEdge(
                target,
                angle=angle,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線を滑らかにしました:</hl> {}°".format(angle),
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def soften_all():
    """選択したメッシュまたはコンポーネントを完全にソフト化します。"""
    soften_normals(180.0)


def harden_normals():
    """選択した範囲をハードエッジ化します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

            cmds.polySoftEdge(
                target,
                angle=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>ハードエッジ化しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def average_vertex_normals():
    """
    選択頂点の法線を平均化します。
    頂点以外を選択した場合は頂点へ変換します。
    """
    selection = cmds.ls(selection=True, long=True, flatten=True) or []

    if not selection:
        cmds.warning("平均化するメッシュまたはコンポーネントを選択してください。")
        return

    vertices = cmds.polyListComponentConversion(
        selection,
        toVertex=True
    )

    vertices = cmds.ls(
        vertices,
        flatten=True,
        long=True
    ) or []

    if not vertices:
        cmds.warning("頂点を取得できませんでした。")
        return

    cmds.undoInfo(openChunk=True)

    try:
        try:
            cmds.polyNormalPerVertex(
                vertices,
                unFreezeNormal=True
            )
        except RuntimeError:
            pass

        cmds.polyAverageNormal(
            vertices,
            distance=0.0,
            replaceNormalXYZ=(0, 0, 0)
        )

        cmds.inViewMessage(
            amg="<hl>頂点法線を平均化しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def conform_normals():
    """
    法線の向きを統一します。
    裏返ったフェースが混在している場合に使用します。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            cmds.polyNormal(
                target,
                normalMode=2,
                userNormalMode=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線方向を統一しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def reverse_normals():
    """選択したフェースまたはメッシュの法線を反転します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            cmds.polyNormal(
                target,
                normalMode=0,
                userNormalMode=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線を反転しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def delete_normal_history():
    """
    選択メッシュの履歴を削除します。
    法線処理以外の履歴も削除されるため注意してください。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    transforms = set()

    for target in targets:
        object_name = target.split(".")[0]

        if cmds.nodeType(object_name) == "mesh":
            parents = cmds.listRelatives(
                object_name,
                parent=True,
                fullPath=True
            ) or []

            if parents:
                transforms.add(parents[0])
        else:
            transforms.add(object_name)

    if transforms:
        cmds.delete(list(transforms), constructionHistory=True)

        cmds.inViewMessage(
            amg="<hl>ヒストリを削除しました</hl>",
            pos="midCenter",
            fade=True
        )


def show_smooth_normal_tool():
    """UIを表示します。"""
    if cmds.window(WINDOW_NAME, exists=True):
        cmds.deleteUI(WINDOW_NAME)

    window = cmds.window(
        WINDOW_NAME,
        title="Smooth Normal Tool",
        sizeable=False,
        widthHeight=(340, 390)
    )

    cmds.columnLayout(
        adjustableColumn=True,
        rowSpacing=8
    )

    cmds.separator(height=8, style="none")

    cmds.text(
        label="メッシュ・フェース・エッジ・頂点に対応",
        align="center"
    )

    cmds.separator(height=8, style="in")

    cmds.floatSliderGrp(
        "smoothNormalAngleSlider",
        label="Soft Angle",
        field=True,
        minValue=0.0,
        maxValue=180.0,
        fieldMinValue=0.0,
        fieldMaxValue=180.0,
        value=60.0,
        columnWidth3=(80, 60, 180)
    )

    cmds.button(
        label="指定角度で滑らかにする",
        height=36,
        command=lambda *_: soften_normals()
    )

    cmds.button(
        label="すべて滑らかにする  180°",
        height=32,
        command=lambda *_: soften_all()
    )

    cmds.button(
        label="ハードエッジにする  0°",
        height=32,
        command=lambda *_: harden_normals()
    )

    cmds.separator(height=10, style="in")

    cmds.button(
        label="頂点法線を平均化",
        height=32,
        command=lambda *_: average_vertex_normals()
    )

    cmds.button(
        label="法線ロックを解除",
        height=32,
        command=lambda *_: unlock_normals()
    )

    cmds.separator(height=10, style="in")

    cmds.rowLayout(
        numberOfColumns=2,
        adjustableColumn=1,
        columnWidth2=(165, 165)
    )

    cmds.button(
        label="法線方向を統一",
        height=30,
        command=lambda *_: conform_normals()
    )

    cmds.button(
        label="法線を反転",
        height=30,
        command=lambda *_: reverse_normals()
    )

    cmds.setParent("..")

    cmds.separator(height=10, style="in")

    cmds.button(
        label="ヒストリを削除",
        height=30,
        command=lambda *_: delete_normal_history()
    )

    cmds.separator(height=8, style="none")

    cmds.showWindow(window)


show_smooth_normal_tool()

メッシュの接合部で法線がめちゃくちゃになってるパターンをどうにか滑らかにしたい

その場合は polySoftEdge だけでは直らない可能性が高いです。

接合部で法線が乱れる原因は主に次の2種類です。

  1. 頂点は接合されているが、法線がロック・分割されている
  2. 別メッシュ同士で、同じ位置にある頂点の法線が一致していない

特に髪・顔・首・胴体など、別メッシュの境界を滑らかにつなぎたい場合は、接合部の近接頂点を探して、両方の法線を平均化する必要があります。

以下は、選択した複数メッシュ間で、同じ位置にある頂点の法線を平均化するPythonツールです。

furcraeaSeamNormalTool.py

# -*- coding: utf-8 -*-

import maya.cmds as cmds
import maya.api.OpenMaya as om


WINDOW_NAME = "furcraeaSeamNormalTool"


def get_selected_mesh_dag_paths():
    """
    選択されたTransformまたはMesh Shapeから、
    MeshのMDagPathを取得する。
    """
    selection = om.MGlobal.getActiveSelectionList()
    mesh_paths = []

    for index in range(selection.length()):
        try:
            dag_path = selection.getDagPath(index)
        except RuntimeError:
            continue

        if dag_path.node().hasFn(om.MFn.kTransform):
            try:
                dag_path.extendToShape()
            except RuntimeError:
                continue

        if dag_path.node().hasFn(om.MFn.kMesh):
            mesh_paths.append(dag_path)

    return mesh_paths


def unlock_mesh_normals(dag_path):
    """
    メッシュ全体の頂点法線ロックを解除する。
    """
    mesh_name = dag_path.fullPathName()

    try:
        cmds.polyNormalPerVertex(
            mesh_name,
            unFreezeNormal=True
        )
    except RuntimeError:
        pass


def get_vertex_data(dag_path):
    """
    各頂点について以下を取得する。

    - 頂点番号
    - ワールド座標
    - 頂点法線
    """
    mesh_fn = om.MFnMesh(dag_path)

    points = mesh_fn.getPoints(om.MSpace.kWorld)
    normals = mesh_fn.getVertexNormals(
        True,
        om.MSpace.kWorld
    )

    result = []

    for vertex_id, point in enumerate(points):
        normal = normals[vertex_id]

        result.append({
            "dag_path": dag_path,
            "mesh_fn": mesh_fn,
            "vertex_id": vertex_id,
            "position": om.MVector(point.x, point.y, point.z),
            "normal": om.MVector(normal.x, normal.y, normal.z)
        })

    return result


def build_spatial_hash(vertex_data, tolerance):
    """
    頂点座標をグリッド化して、近接頂点を高速に検索する。
    """
    spatial_hash = {}

    for data in vertex_data:
        position = data["position"]

        key = (
            int(round(position.x / tolerance)),
            int(round(position.y / tolerance)),
            int(round(position.z / tolerance))
        )

        spatial_hash.setdefault(key, []).append(data)

    return spatial_hash


def get_neighbor_keys(position, tolerance):
    """
    誤差境界をまたいだ頂点も検索できるように、
    周囲27セルを返す。
    """
    center_x = int(round(position.x / tolerance))
    center_y = int(round(position.y / tolerance))
    center_z = int(round(position.z / tolerance))

    for offset_x in (-1, 0, 1):
        for offset_y in (-1, 0, 1):
            for offset_z in (-1, 0, 1):
                yield (
                    center_x + offset_x,
                    center_y + offset_y,
                    center_z + offset_z
                )


def average_seam_normals(tolerance=0.001, border_only=True):
    """
    選択した複数メッシュ間で、
    同じ位置にある頂点法線を平均化する。

    tolerance:
        同じ位置と判定する距離。

    border_only:
        Trueの場合は境界頂点のみを対象にする。
    """
    dag_paths = get_selected_mesh_dag_paths()

    if len(dag_paths) < 2:
        cmds.warning(
            "接合部を修正する2つ以上のメッシュを選択してください。"
        )
        return

    cmds.undoInfo(openChunk=True)

    try:
        all_vertex_data = []

        for dag_path in dag_paths:
            unlock_mesh_normals(dag_path)

            mesh_vertex_data = get_vertex_data(dag_path)

            if border_only:
                border_ids = get_border_vertex_ids(dag_path)

                mesh_vertex_data = [
                    data
                    for data in mesh_vertex_data
                    if data["vertex_id"] in border_ids
                ]

            all_vertex_data.extend(mesh_vertex_data)

        spatial_hash = build_spatial_hash(
            all_vertex_data,
            tolerance
        )

        processed = set()
        matched_groups = []

        for source_data in all_vertex_data:
            source_key = (
                source_data["dag_path"].fullPathName(),
                source_data["vertex_id"]
            )

            if source_key in processed:
                continue

            matching_vertices = []

            for neighbor_key in get_neighbor_keys(
                source_data["position"],
                tolerance
            ):
                candidates = spatial_hash.get(
                    neighbor_key,
                    []
                )

                for candidate in candidates:
                    candidate_key = (
                        candidate["dag_path"].fullPathName(),
                        candidate["vertex_id"]
                    )

                    if candidate_key in processed:
                        continue

                    # 同一メッシュ内の近接頂点は対象外
                    if (
                        candidate["dag_path"].fullPathName()
                        == source_data["dag_path"].fullPathName()
                    ):
                        continue

                    distance = (
                        candidate["position"]
                        - source_data["position"]
                    ).length()

                    if distance <= tolerance:
                        matching_vertices.append(candidate)

            if not matching_vertices:
                continue

            group = [source_data] + matching_vertices

            # 同一頂点の重複を除去
            unique_group = {}
            for data in group:
                key = (
                    data["dag_path"].fullPathName(),
                    data["vertex_id"]
                )
                unique_group[key] = data

            group = list(unique_group.values())

            if len(group) < 2:
                continue

            matched_groups.append(group)

            for data in group:
                processed.add((
                    data["dag_path"].fullPathName(),
                    data["vertex_id"]
                ))

        if not matched_groups:
            cmds.warning(
                "指定距離内に一致する接合頂点が見つかりませんでした。"
            )
            return

        apply_average_normals(matched_groups)

        cmds.inViewMessage(
            amg=(
                "<hl>接合部法線を平均化しました</hl>"
                "<br/>一致グループ数: {}"
            ).format(len(matched_groups)),
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def get_border_vertex_ids(dag_path):
    """
    メッシュの境界エッジに含まれる頂点番号を取得する。
    """
    border_vertex_ids = set()

    edge_iterator = om.MItMeshEdge(dag_path)

    while not edge_iterator.isDone():
        if edge_iterator.onBoundary():
            border_vertex_ids.add(
                edge_iterator.vertexId(0)
            )
            border_vertex_ids.add(
                edge_iterator.vertexId(1)
            )

        edge_iterator.next()

    return border_vertex_ids


def apply_average_normals(matched_groups):
    """
    法線グループごとに平均法線を計算し、
    各頂点へ適用する。
    """
    mesh_updates = {}

    for group in matched_groups:
        average_normal = om.MVector()

        for data in group:
            average_normal += data["normal"]

        if average_normal.length() < 0.000001:
            continue

        average_normal.normalize()

        for data in group:
            mesh_name = data["dag_path"].fullPathName()

            if mesh_name not in mesh_updates:
                mesh_updates[mesh_name] = {
                    "mesh_fn": data["mesh_fn"],
                    "vertex_ids": [],
                    "normals": []
                }

            mesh_updates[mesh_name]["vertex_ids"].append(
                data["vertex_id"]
            )

            mesh_updates[mesh_name]["normals"].append(
                om.MVector(
                    average_normal.x,
                    average_normal.y,
                    average_normal.z
                )
            )

    for update_data in mesh_updates.values():
        mesh_fn = update_data["mesh_fn"]

        mesh_fn.setVertexNormals(
            update_data["normals"],
            update_data["vertex_ids"],
            om.MSpace.kWorld
        )


def run_from_ui(*args):
    tolerance = cmds.floatField(
        "seamNormalToleranceField",
        query=True,
        value=True
    )

    border_only = cmds.checkBox(
        "seamNormalBorderOnlyCheckBox",
        query=True,
        value=True
    )

    if tolerance <= 0:
        cmds.warning("許容距離は0より大きくしてください。")
        return

    average_seam_normals(
        tolerance=tolerance,
        border_only=border_only
    )


def show_seam_normal_tool():
    if cmds.window(WINDOW_NAME, exists=True):
        cmds.deleteUI(WINDOW_NAME)

    window = cmds.window(
        WINDOW_NAME,
        title="Seam Normal Smoother",
        sizeable=False,
        widthHeight=(360, 190)
    )

    cmds.columnLayout(
        adjustableColumn=True,
        rowSpacing=8
    )

    cmds.separator(height=8, style="none")

    cmds.text(
        label="接合する2つ以上のメッシュを選択",
        align="center"
    )

    cmds.text(
        label="同じ位置にある境界頂点の法線を平均化します",
        align="center"
    )

    cmds.separator(height=8, style="in")

    cmds.floatFieldGrp(
        "seamNormalToleranceField",
        numberOfFields=1,
        label="許容距離",
        value1=0.001,
        precision=6,
        columnWidth2=(100, 220)
    )

    cmds.checkBox(
        "seamNormalBorderOnlyCheckBox",
        label="境界頂点のみを処理",
        value=True
    )

    cmds.separator(height=8, style="in")

    cmds.button(
        label="接合部の法線を滑らかにする",
        height=38,
        command=run_from_ui
    )

    cmds.separator(height=8, style="none")

    cmds.showWindow(window)


show_seam_normal_tool()

[maya][UE5.7.3]USD workflow pipline tool :レイヤー持ち背景のインポート

[Maya][UE5.7.3] USD workflow pipeline tool: Importing backgrounds with layers

https://github.com/nobolu-ootsuka-unrealengine/furcraeaMayaTool

kind を設定版を作ってUE で毎回オプションを触らなくて済むようにします。

USD Export Selection

Window > USD Stage Windowを開き


Openから S_Stg_Furcraea_Gate_Com_Geom.usda を選択


USD Stage Editor >option>collapsing>Use prim kinds for collapsingをoffにしたらStaticMeshが分かれた

Import

インポートフォルダ選択

インポートオプションにも Kind To Collapseがあるがこの設定にした。

一番上のGeom以下の全部選択して>Level>Create Packed Actor

Level Instance

BPP

BPP

Level Instance

レイヤー持ち背景のインポートできあがり。

[maya][mel] MELでファイルの読み取り専用をチェックする。

[maya][mel] Check if a file is read-only in MEL.


global proc MEL_FileReadModeCheck(string $Save_path){
    //MELでファイルの読み取り専用をチェックする。
    print("MEL_FileReadModeCheck("+$Save_path+") \n");
    python("import os");

    int $FileReadOnlybool = python("os.access('"+$Save_path+"', os.W_OK)");
    print("$FileReadOnlybool= "+$FileReadOnlybool+" \n");
    if($FileReadOnlybool==0){
        print("読み取り専用 のため書き込み不可 \n");    
    }else{
        print("書き込み出来ます \n");      
    }
}
MEL_FileReadModeCheck("D:/check_ON.txt");
MEL_FileReadModeCheck("D:/check_OFF.txt");

maya python 検索用の 正規表現 を作成したテキストフィールドから入力するには?

maya python How can I enter a regular expression for search from the created text field?

import maya.cmds as cmds
import re

def search_objects_by_regex(*args):
    # テキストフィールドから正規表現を取得
    regex_pattern = cmds.textField("regexField", query=True, text=True)

    # シーン内のすべてのオブジェクトを取得
    all_objects = cmds.ls()

    # 正規表現パターンをコンパイル
    try:
        regex = re.compile(regex_pattern)
    except re.error as e:
        cmds.warning(f"Invalid regex pattern: {e}")
        return

    # 正規表現に一致するオブジェクトをフィルタリング
    matching_objects = [obj for obj in all_objects if regex.search(obj)]

    # 結果を表示
    if matching_objects:
        cmds.confirmDialog(title='Search Results', message='\n'.join(matching_objects))
    else:
        cmds.confirmDialog(title='Search Results', message='No matching objects found.')

# UIの作成
if cmds.window("regexSearchWindow", exists=True):
    cmds.deleteUI("regexSearchWindow")

cmds.window("regexSearchWindow", title="Regex Search", widthHeight=(300, 100))
cmds.columnLayout(adjustableColumn=True)
cmds.text(label="Enter Regex Pattern:")
cmds.textField("regexField")
cmds.button(label="Search", command=search_objects_by_regex)
cmds.showWindow("regexSearchWindow")

検索置換の場合

import maya.cmds as cmds
import re

def replace_objects_by_regex(*args):
    # テキストフィールドから正規表現と置換文字列を取得
    regex_pattern = cmds.textField("regexField", query=True, text=True)
    replace_text = cmds.textField("replaceField", query=True, text=True)

    # シーン内のすべてのオブジェクトを取得
    all_objects = cmds.ls()

    # 正規表現パターンをコンパイル
    try:
        regex = re.compile(regex_pattern)
    except re.error as e:
        cmds.warning(f"Invalid regex pattern: {e}")
        return

    # 正規表現に一致するオブジェクトを置換
    replaced_objects = [regex.sub(replace_text, obj) for obj in all_objects]

    # 結果を表示
    if replaced_objects:
        cmds.confirmDialog(title='Replace Results', message='\n'.join(replaced_objects))
    else:
        cmds.confirmDialog(title='Replace Results', message='No objects replaced.')

# UIの作成
if cmds.window("regexReplaceWindow", exists=True):
    cmds.deleteUI("regexReplaceWindow")

cmds.window("regexReplaceWindow", title="Regex Replace", widthHeight=(300, 150))
cmds.columnLayout(adjustableColumn=True)
cmds.text(label="Enter Regex Pattern:")
cmds.textField("regexField")
cmds.text(label="Enter Replace Text:")
cmds.textField("replaceField")
cmds.button(label="Replace", command=replace_objects_by_regex)
cmds.showWindow("regexReplaceWindow")

[UE5]Pythonからダイアログメッセージを表示 unreal.EditorDialog.show_message

import unreal
class hoge:
    def show_messageDialog(self):
        title="タイトル"
        message="メッセージ"
        message_type=unreal.AppMsgType.OK_CANCEL
        
        unreal.EditorDialog.show_message(title,message,message_type, default_value=unreal.AppReturnType.NO, message_category=unreal.AppMsgCategory.WARNING)

class_Ins=hoge()
hoge.show_messageDialog()

参考URL

https://docs.unrealengine.com/5.3/en-US/PythonAPI/class/EditorDialog.html#unreal.EditorDialog

[Maya][Python]round protrusion sphere Thorns sphere 3d model 丸い突起のついた球。

round protrusion sphere Thorns sphere 3d model

つぶつぶのついた球を探したけどなくてpythonで作ったよ

#sphire_vertex_position_shpire.py
BaseSphere=cmds.polySphere(sx=25, sy=12, r=6,axis=[0,0,0])
BaseSphere=BaseSphere[0]
print("BaseSphere= "+str(BaseSphere))

import maya.cmds as cmds

def get_vertex_positions(obj_name):
    vertex_positions = []
    vertices = cmds.ls(obj_name + '.vtx[*]', fl=True)
    for vertex in vertices:
        pos = cmds.xform(vertex, q=True, ws=True, t=True)
        vertex_positions.append(pos)
    return vertex_positions

vertex_positions = get_vertex_positions(BaseSphere)
print(vertex_positions)

for v_pos in vertex_positions:
    mySphere=cmds.polySphere(sx=15, sy=10, r=1)
    cmds.xform(mySphere, translation=(v_pos[0],v_pos[1],v_pos[2]) ,absolute=1,worldSpace=1)

[maya][PySide2][QtWidgets]PySide2.QtWidgets.QApplication’ object has no attribute ‘close’

QApplicationをコードで自動で閉じようとするときに出たエラーの解決方法です。

PySide2.QtWidgets.QApplication’ object has no attribute ‘close’

Question : QMainWindow

class DF_TalkUI(QMainWindow):


    def __init__(self, parent = None):

Answer : QWidget

class DF_TalkUI(QWidget):


    def __init__(self, parent = None):

Fix Code


#------------------------------------------------------------------------------------------------------------------------------------------


# -*- coding: utf-8 -*-
import os
from functools import partial
import time
import imp

"""
PySide2モジュールを探し、ある場合はそちらをインポートします。
"""
try:
    imp.find_module('PySide2')
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    from PySide2.QtCore import *

except ImportError:
    from PySide.QtGui import *
    from PySide.QtCore import *


LOGO_IMAGE = r"画像のパスをここに入れてください。"


def get_maya_pointer():
    """
    Mayaのメインウィンドウを取得する関数
    """
    try:
        import maya.cmds as cmds
        from maya import OpenMayaUI

    except ImportError:
        return None

    """
    実は2017ではshibokenも2になっているので、あればshiboken2をインポートします。
    """
    try:
        imp.find_module("shiboken2")
        import shiboken2
        return shiboken2.wrapInstance(int(OpenMayaUI.MQtUtil.mainWindow()), QWidget)

    except ImportError:
        import shiboken
        return shiboken.wrapInstance(int(OpenMayaUI.MQtUtil.mainWindow()), QWidget)






class DF_TalkUI(QWidget):


    def __init__(self, parent = None):
        super(DF_TalkUI, self).__init__(parent)
        self.setObjectName("DF_Talk_Window")
        self.setWindowTitle("DF Talk Window")
        #self._initUI()
        self.errorDialog = QErrorMessage(self) # QErrorMessageインスタンスの保持
        self.Window = self

    def myInit(self,qApp,refPath):
        self.qApp=qApp
        self.wrapper=wrapper = QWidget()
        #self.setCentralWidget(wrapper)

        mainLayout = QVBoxLayout()
        self.mainLayout= mainLayout
        wrapper.setLayout(mainLayout)

        #-----------------------------------------------------------------------
        # sixth row
        #-----------------------------------------------------------------------
        sixthHorizontalArea = QHBoxLayout()
        sixthHorizontalArea.setSpacing(20)
        mainLayout.addLayout(sixthHorizontalArea)


        """
        progressDialogBtn = QPushButton("Progress Dialog")
        sixthHorizontalArea.addWidget(progressDialogBtn)
        progressDialogBtn.clicked.connect(self.havyfunc)
        """
        #---------------------------
        self.havyfunc(refPath)
        #-----------------------------

        #-----------------------------------------------------------------------
        # seventh row
        #-----------------------------------------------------------------------
        #self.havyfunc()

    def _showProgressDialog(self):
        print("---------------------ProgressBar Starting--------------------------")

        self.max = 100
        self.progressDialog = QProgressDialog("Progress...", "Cancel", 0, self.max, self)
        self.progressDialog.setWindowTitle("Progress Dialog")
        self.progressDialog.show()
    
    def setProgress(self,count):
        print("---------------------setProgress ( "+str(count)+"/100 )--------------------------")
        self.qApp.processEvents()
        if self.progressDialog.wasCanceled():
            self.progressDialog.setValue(100)
        self.progressDialog.setValue(count)
        self.progressDialog.setLabelText("Progress... %d %%" % count)


    def havyfunc(self,refPath):
        
        #--------------------------------------------------
        self._showProgressDialog()
        self.setProgress(1)
        #--------------------------------------------------
        duplicatedMesh_vtx_arr=[1,2,3,4,5]
        duplicatedMesh_vtx_arr_len=len(duplicatedMesh_vtx_arr)
        
        cmds.file(refPath, ignoreVersion=1, type="mayaAscii", namespace=":", r=1, gl=1, mergeNamespacesOnClash=False, options="v=0;")
        """
        for i in range(0,duplicatedMesh_vtx_arr_len):
            
            
            #---------------------------------------------------
            parcent=(100*i/duplicatedMesh_vtx_arr_len) /2
            self.setProgress(parcent)
            print("setProgress("+str(parcent)+")")
            time.sleep(0.1)
            #---------------------------------------------------
            
            #重たい処理1
        
        for i in range(0,duplicatedMesh_vtx_arr_len):
            
            #---------------------------------------------------
            parcent=(100*i/duplicatedMesh_vtx_arr_len) /2 +50
            
            self.setProgress(parcent)
            
            print("setProgress("+str(parcent)+")")
            time.sleep(0.1)
            #---------------------------------------------------
            #重たい処理2
        """      
        #--------------------------------------
        self.setProgress(100)
        print("setProgress("+str(100)+")")

        self.MyHide()
        #self.closeEvent(QCloseEvent)
        #--------------------------------------
    def MyHide(self):
        self.resize(2, 1)  # 幅800、高さ600
        self.Window.move(10000, 10000) #X 10000 Y 10000


        """
        #self.mainLayout.close()
        self.wrapper.hide()
        self.wrapper.close()
        self.Window.hide()
        self.Window.close()
        self.close()
        """


    def _makeHorizontalLine(self):
        hline = QFrame()
        hline.setFrameShape(QFrame.HLine)
        hline.setFrameShadow(QFrame.Sunken)
        return hline






def start(app,refPath):
    maya_win = get_maya_pointer()
    ui = DF_TalkUI(parent = maya_win)
    ui.myInit(app,refPath)
    ui.show()
    return ui


def starter(refPath):
    app = QApplication.instance()
    if app is None:
        app = QApplication([])
    ui = start(app,refPath)
    app.exec_()
    
#=----------------------------------------------------------------------------------------------
# -*- coding: utf-8 -*- 
from maya import cmds 
import pymel.core as pm 

def mosa_anim_func10_2to10_3_reference(RigIDNum):
	
	reference_path="D:/MOSADesign/WorkData/Avatar/" + RigIDNum + "/Motion/Rig/PL_" + RigIDNum + "_rig.ma"
	#cmds.file(reference_path, ignoreVersion=1, type="mayaAscii", namespace=":", r=1, gl=1, mergeNamespacesOnClash=False, options="v=0;")
	starter(reference_path)
print("__name__  = "+__name__ )
if __name__ == '__main__':
    mosa_anim_func10_2to10_3_reference("005")

参考

https://forum.freecad.org/viewtopic.php?t=43989

maya mel python 環境変数 一覧 path MAYA_SCRIPT_PATH

maya mel python environment variables list path MAYA_SCRIPT_PATH

maya python 自動的にロードする場所と

maya python 自動的にロードする場所を追加する方法。

MEL

//getenv "MAYA_SCRIPT_PATH";//パスを確認

$sPath=`getenv "PATH"`;
print("$sPath= "+$sPath+"\n");
$sMAYA_SCRIPT_PATH=`getenv "MAYA_SCRIPT_PATH"`;
print("$sMAYA_SCRIPT_PATH= "+$sMAYA_SCRIPT_PATH+"\n");

$array = stringToStringArray($sMAYA_SCRIPT_PATH, ";");

for ($MSP in $array) {
    print($MSP+"\n");
}

Python

import os
print("------------------------PATH---------------------------")
ePath = os.environ["PATH"]
ePath_List=ePath.split(";")
for ePath_line in ePath_List:
    #for ev in environ:
    print(ePath_line)

print("------------------------MAYA_SCRIPT_PATH-----------------------------")

mayaScriptPath = os.environ["MAYA_SCRIPT_PATH"]
mayaScriptPath_List=mayaScriptPath.split(";")
for mayaScriptPath_line in mayaScriptPath_List:
    #for ev in environ:
    print(mayaScriptPath_line)

大体自分のパスを追加したい時にこの記事見てるので

追加方法も載せておく、

$sMAYA_SCRIPT_PATH_StrArr=getenv "MAYA_SCRIPT_PATH";
print(“$sMAYA_SCRIPT_PATH_StrArr= “+$sMAYA_SCRIPT_PATH_StrArr+”\n”);

の結果はこう。配列にみえるけどカンマ ; で区切られた文字列

$sMAYA_SCRIPT_PATH_StrArr= D:/MOSADesign/WorkTools/Maya/MOSATool/python/USD_Temp/scripts;C:/Users/furcr/Documents/maya/2022/ja_JP/scripts;C:/Users/furcr/Documents/maya/2022/scripts;C:/Users/furcr/Documents/maya/scripts;C:/Users/furcr/Documents/maya/2022/ja_JP/presets;C:/Users/furcr/Documents/maya/2022/ja_JP/prefs/shelves;C:/Users/furcr/Documents/maya/2022/ja_JP/prefs/markingMenus;C:/Users/furcr/Documents/maya/2022/ja_JP/prefs/scripts;C:/Program Files/Autodesk/Maya2022/scripts;C:/Program Files/Autodesk/Maya2022/scripts/startup;C:/Program Files/Autodesk/Maya2022/scripts/shelves;C:/Program Files/Autodesk/Maya2022/scripts/others;C:/Program Files/Autodesk/Maya2022/scripts/AETemplates;C:/Program Files/Autodesk/Maya2022/scripts/unsupported;C:/Program Files/Autodesk/Maya2022/scripts/paintEffects;C:/Program Files/Autodesk/Maya2022/scripts/fluidEffects;C:/Program Files/Autodesk/Maya2022/scripts/hair;C:/Program Files/Autodesk/Maya2022/scripts/cloth;C:/Program Files/Autodesk/Maya2022/scripts/live;C:/Program Files/Autodesk/Maya2022/scripts/fur;C:/Program Files/Autodesk/Maya2022/scripts/muscle;C:/Program Files/Autodesk/Maya2022/scripts/turtle;C:/Program Files/Autodesk/Maya2022/scripts/FBX;C:/Program Files/Autodesk/Maya2022/scripts/mayaHIK;C:/Program Files/Autodesk/Maya2022/plug-ins/ATF/scripts;C:/Program Files/Autodesk/Bifrost/Maya2022/2.2.1.0/bifrost/scripts;C:/Program Files/Autodesk/Maya2022/plug-ins/MASH/scripts;C:/Program Files/Autodesk/MayaUSD/Maya2022/0.8.0/mayausd/MayaUSD3/plugin/adsk/scripts;C:/Program Files/Rokoko Motion Library/Maya/2022/scripts;C:/Program Files/Autodesk/Maya2022/plug-ins/fbx/scripts;C:/Program Files/Side Effects Software/Houdini Engine/Maya/21.0.671/maya2022/scripts;C:/Program Files/Autodesk/Maya2022/plug-ins/camd/scripts;D:/Sandbox/mgear/modules/scripts;C:/Program Files/Autodesk/Arnold/maya2022/scripts;C:/Program Files/Allegorithmic/Substance in Maya/2022/scripts;C:/Program Files/Autodesk/Maya2022/plug-ins/sweep/scripts;C:/Program Files/Autodesk/Bifrost/Maya2022/2.2.1.0/vnn/scripts;C:/Program Files/Autodesk/Maya2022/plug-ins/xgen/scripts;C:/Program Files/Autodesk/Arnold/maya2022/scripts/mtoa/mel;

なので

C:/Users/furcr/Documents/maya/2022/scripts/userSetup.mel

にこう書けばMAYA_SCRIPT_PATHに追加できる。

print("C:/Users/furcr/Documents/maya/2022/scripts/userSetup.mel\n");

///putenv Add---------------------------------------------------
//putenv "MAYA_SCRIPT_PATH";//パスを追加
proc Add_MAYA_SCRIPT_PATH(string $Add_Path)
{
    //$Add_Path="D:/furcraeaTokyo/furcraeaTool";
    $sMAYA_SCRIPT_PATH_StrArr=`getenv "MAYA_SCRIPT_PATH"`;
    print("$sMAYA_SCRIPT_PATH_StrArr= "+$sMAYA_SCRIPT_PATH_StrArr+"\n");
    //$sMAYA_SCRIPT_PATH_Arr[size($sMAYA_SCRIPT_PATH_Arr)] = $Add_Path; 
    $sMAYA_SCRIPT_PATH_StrArr=$sMAYA_SCRIPT_PATH_StrArr+";"+$Add_Path;
    $putenv_Result=`putenv "MAYA_SCRIPT_PATH" $sMAYA_SCRIPT_PATH_StrArr`;
    print("$putenv_Result= "+$putenv_Result+"\n");
}
Add_MAYA_SCRIPT_PATH("D:/furcraeaTokyo/furcraeaTool");
Add_MAYA_SCRIPT_PATH("D:/furcraeaTokyo/furcraeaTool/mel");
Add_MAYA_SCRIPT_PATH("D:/furcraeaTokyo/furcraeaTool/python");


///putenv Add-----------------------------------------------------
//---------------------------------------------------------
//getenv "MAYA_SCRIPT_PATH";//パスを確認

$sPath=`getenv "PATH"`;
print("$sPath= "+$sPath+"\n");
$sMAYA_SCRIPT_PATH=`getenv "MAYA_SCRIPT_PATH"`;
print("$sMAYA_SCRIPT_PATH= "+$sMAYA_SCRIPT_PATH+"\n");

$array = stringToStringArray($sMAYA_SCRIPT_PATH, ";");

for ($MSP in $array) {
    print($MSP+"\n");
}
//---------------------------------------------------------


python("import maya.cmds as cmds");
python("selection = cmds.ls(sl=True)");
python("print(selection)");


//Pythonのシステムに追加
python("import sys");
python("sys.path.append('D:/furcraeaTokyo/furcraeaTool/python')");

でさらに

D:/furcraeaTokyo/furcraeaTool/python に

__init__.py を置いて

PythonClassFile.py

# -*- coding: utf-8 -*-

def starter():
    print("starter")
print("__name__ = "+__name__)

melから
python_class_file.mel

global proc python_class_file(){
    print("PythonClassFile");
    python("import PythonClassFile");
	python("import importlib");
	python("importlib.reload(PythonClassFile)");
    python("PythonClassFile.starter()");
}

こんな感じで呼び出す。

C:/Users/furcr/Documents/maya/2022/scripts/userSetup.mel の最後に

python_class_file(); で呼べれば以下のデバックが出ればOK

PythonClassFile__name__ = PythonClassFile
__name__ = PythonClassFile
starter

[maya] scriptJob は実行中には中断できません。のエラーを回避する方法

scriptJob でMayaの状態を監視することができるが、その監視を終わらせる際にエラーが出る
日本語のエラー:scriptJob は実行中には中断できません。 #
英語のエラー:scriptJob cannot be killed while it is running. #

実行中のそれを回避するために、evalDeferredでコマンドを囲って遅延させて実行させる。

mel

global int $jobNum;
global proc myScriptJobFunctionName(){
      global int $jobNum;
      print("func $jobNum="+$jobNum+"\n");
      //scriptJob -kill $jobNum;  
      evalDeferred("myDeferredFunctionName();");  
}
global proc myDeferredFunctionName(){
      global int $jobNum;
      print("func Deferred  $jobNum="+$jobNum+"\n");
      scriptJob -kill $jobNum;  
}
$jobNum = `scriptJob -event "SceneOpened" "myScriptJobFunctionName();"`;
print("$jobNum="+$jobNum+"\n");
//scriptJob -kill $jobNum;


file -f -options "v=0;"  -ignoreVersion  -typ "mayaAscii" -o "D:/MOSADesign/WorkData/Avatar/005/Motion/Rig/PL_005_Reference_Model.ma";

python

import maya.cmds as cmds

class ScriptJobber():
    def starter(self):
    
        #scriptJoblistEvents=cmds.scriptJob(listEvents=True)
        #print(scriptJoblistEvents)
    
        #for EventName in scriptJoblistEvents:
        #    print(EventName)
        
        
        
        #self.jobNum = cmds.scriptJob(event=("idle", 'Class_ins.idleTimeFunc()'))
        self.jobNum = cmds.scriptJob(event=("SceneOpened", 'Class_ins.SceneOpenedTimeFunc()'))
        #self.jobNum = cmds.scriptJob(event=("SceneOpened", 'Class_ins.SceneOpenedTimeFunc()'),runOnce = True, killWithScene = True)
        print("self.jobNum= "+str(self.jobNum))
    
    
    def SceneOpenedTimeFunc(self):
        print("SceneOpenedTimeFunc")
        print("SceneOpenedTimeFunc self.jobNum= "+str(self.jobNum))
        #cmds.scriptJob( kill=Class_ins.jobNum, force=True)
        cmds.evalDeferred("cmds.scriptJob( kill=Class_ins.jobNum, force=True)")
    
    def idleTimeFunc(self):
        print("idleTimeFunc")
        print("idleTimeFunc self.jobNum= "+str(self.jobNum))
        #cmds.scriptJob( kill=self.jobNum, force=True)
        cmds.evalDeferred("cmds.scriptJob( kill=Class_ins.jobNum, force=True)")
        
Class_ins=ScriptJobber()
Class_ins.starter()


"""
linearUnitChanged
timeUnitChanged
angularUnitChanged
Undo
undoSupressed
Redo
customEvaluatorChanged
serialExecutorFallback
timeChanged
currentContainerChange
quitApplication
idleHigh
idle
idleVeryLow
RecentCommandChanged
ToolChanged
PostToolChanged
ToolDirtyChanged
ToolSettingsChanged
tabletModeChanged
DisplayRGBColorChanged
animLayerRebuild
animLayerRefresh
animLayerAnimationChanged
animLayerLockChanged
animLayerBaseLockChanged
animLayerGhostChanged
cteEventKeyingTargetForClipChanged
cteEventKeyingTargetForLayerChanged
cteEventKeyingTargetForInvalidChanged
teClipAdded
teClipModified
teClipRemoved
teCompositionAdded
teCompositionRemoved
teCompositionActiveChanged
teCompositionNameChanged
teMuteChanged
cameraChange
cameraDisplayAttributesChange
SelectionChanged
PreSelectionChangedTriggered
LiveListChanged
ActiveViewChanged
SelectModeChanged
SelectTypeChanged
SelectPreferenceChanged
DisplayPreferenceChanged
DagObjectCreated
transformLockChange
renderLayerManagerChange
renderLayerChange
displayLayerManagerChange
displayLayerAdded
displayLayerDeleted
displayLayerVisibilityChanged
displayLayerChange
renderPassChange
renderPassSetChange
renderPassSetMembershipChange
passContributionMapChange
DisplayColorChanged
lightLinkingChanged
lightLinkingChangedNonSG
UvTileProxyDirtyChangeTrigger
preferredRendererChanged
polyTopoSymmetryValidChanged
SceneSegmentChanged
PostSceneSegmentChanged
SequencerActiveShotChanged
ColorIndexChanged
deleteAll
NameChanged
symmetricModellingOptionsChanged
softSelectOptionsChanged
SetModified
xformConstraintOptionsChanged
metadataVisualStatusChanged
undoXformCmd
redoXformCmd
freezeOptionsChanged
linearToleranceChanged
angularToleranceChanged
nurbsToPolygonsPrefsChanged
nurbsCurveRebuildPrefsChanged
constructionHistoryChanged
threadCountChanged
SceneSaved
NewSceneOpened
SceneOpened
SceneImported
PreFileNewOrOpened
PreFileNew
PreFileOpened
PostSceneRead
workspaceChanged
nurbsToSubdivPrefsChanged
PolyUVSetChanged
PolyUVSetDeleted
selectionConstraintsChanged
startColorPerVertexTool
stopColorPerVertexTool
start3dPaintTool
stop3dPaintTool
DragRelease
ModelPanelSetFocus
modelEditorChanged
MenuModeChanged
gridDisplayChanged
interactionStyleChanged
axisAtOriginChanged
CurveRGBColorChanged
SelectPriorityChanged
snapModeChanged
activeHandleChanged
ChannelBoxLabelSelected
texWindowEditorImageBaseColorChanged
texWindowEditorCheckerDensityChanged
texWindowEditorCheckerDisplayChanged
texWindowEditorDisplaySolidMapChanged
texWindowEditorShowup
texWindowEditorClose
colorMgtOCIORulesEnabledChanged
colorMgtUserPrefsChanged
RenderSetupSelectionChanged
colorMgtEnabledChanged
colorMgtConfigFileEnableChanged
colorMgtConfigFilePathChanged
colorMgtConfigChanged
colorMgtWorkingSpaceChanged
colorMgtPrefsViewTransformChanged
colorMgtPrefsReloaded
colorMgtOutputChanged
colorMgtPlayblastOutputChanged
colorMgtRefreshed
selectionPipelineChanged
playbackRangeChanged
playbackSpeedChanged
playbackModeChanged
playbackRangeSliderChanged
glFrameTrigger
currentSoundNodeChanged
graphEditorChanged
graphEditorParamCurveSelected
graphEditorOutlinerHighlightChanged
graphEditorOutlinerListChanged
EditModeChanged
RenderViewCameraChanged
texScaleContextOptionsChanged
texRotateContextOptionsChanged
texMoveContextOptionsChanged
polyCutUVSteadyStrokeChanged
polyCutUVEventTexEditorCheckerDisplayChanged
polyCutUVShowTextureBordersChanged
polyCutUVShowUVShellColoringChanged
shapeEditorTreeviewSelectionChanged
poseEditorTreeviewSelectionChanged
sculptMeshCacheBlendShapeListChanged
sculptMeshCacheCloneSourceChanged
RebuildUIValues
cteEventClipEditModeChanged
teEditorPrefsChanged

"""

URL
https://forums.cgsociety.org/t/scriptjob-problems/942387

[Daz3D][Maya][Marvelous Designer] Das3D 4.22 Genesis9をMaya2022に持ってきてMarvelous Designerの服をスキニングしてコピースキンウェイトしたVol.02(まとめ)

このノード状態がキレイなので「bindPose1が一つだけ」キープしながらモデリング編集すること。

Genesis9 やったこと

—————————————-ここからはモデリングとする。——————————————–
Das3D 4.22 のGenesis9を
Maya2022に持ってきて

duplicateでスキンバインド外し=複製して
meshGroupのグループに
・genesis9のまつ毛や口のレイヤーも入れる(skinCluster初めから無いので)
・Marvelous Designerの服レイヤーも入れる
・highheelレイヤーも入れる
highheelの高さにhipとmeshGroupをmoveする。(オプション)
↑高さはBluePrintで変更可能

—————————————-ここまではモデリングとする。——————————————–

新しい方の骨とmeshGroupでバインド
↑ちゃんとしたバインドオプションが重要
cmds.skinBind()引数なしじゃclusterがダメ
genesis9からcopySkinWeightした

モデル編集後ファイル (自分用リンク)」

jennie9_6_v12z_v00122_dupGen9_Kihon.zip

#jennie9_6_v12z_v00122_dupGen9_Kihon__ModelEnd_SkinBindSkinWeight.py

def startSelectionToNewSkinCluster():
    selectList=cmds.ls(sl=1,long=1)
    print("selectList= "+str(selectList))
    # 全部必要だから引数にした
    Genesis9 = selectList[0]
    Genesis9_Mesh = selectList[1]
    Genesis9s = selectList[2]
    MeshGroup = selectList[3]
    #------------------------------------------------------------------------
    ModelEnd_SkinBind(Genesis9s,MeshGroup)
    ModelEnd_SkinWeight(Genesis9,Genesis9_Mesh,Genesis9s,MeshGroup)
    #------------------------------------------------------------------------
    
def ModelEnd_SkinBind(Genesis9s,MeshGroup):
    
    cmds.select(Genesis9s,MeshGroup)
    #MEL  (Script found in: C:/Program Files/Autodesk/Maya2022/scripts/others/newSkinCluster.mel)
    #newSkinCluster " -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0";
    
    #Python でMEL実行
    import maya.mel
    maya.mel.eval('newSkinCluster " -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0";')
    
    #Python  NG  'maya.cmds' has no attribute 'newSkinCluster' # 
    #cmds.newSkinCluster(" -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0")

    #import pymel.core as pm #OK
    #pm.mel.newSkinCluster(" -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0")
def ModelEnd_SkinWeight(Genesis9,Genesis9_Mesh,Genesis9s,MeshGroup):
    
    Genesis9_Low_skincluster = Get_SkinCluster(Genesis9_Mesh)
    print("Genesis9_Low_skincluster= "+str(Genesis9_Low_skincluster))
    
    MeshList = cmds.listRelatives(MeshGroup,shapes=0,fullPath=1)
    print("MeshList= "+str(MeshList))
    
    for closet_mesh in MeshList:
        closet_skinCluster = Get_SkinCluster(closet_mesh)
        print("closet_skinCluster= "+str(closet_skinCluster))
        
        # 元のスキンクラスターを服のスキンクラスターへコピースキンウェイト
        cmds.copySkinWeights(
            sourceSkin = Genesis9_Low_skincluster,
            destinationSkin = closet_skinCluster,
            noMirror=True,
            influenceAssociation="oneToOne",
            surfaceAssociation="closestPoint"
        )
    
def Get_SkinCluster(LowMeshTransformLong):
    # トランスフォームのシェイプノードを取得
    shapeList = cmds.listRelatives(LowMeshTransformLong, shapes=True, noIntermediate=True,fullPath=True)
    #print("shapeList= "+str(shapeList))
    # lowのヒストリーを取得し、スキンクラスターのみ取得
    historyList = cmds.listHistory(shapeList[0], pruneDagObjects=True, interestLevel=2)
    #print("historyList= "+str(historyList))
    skinclusterList = cmds.ls(historyList, type="skinCluster")
    #print("skinclusterList= "+str(skinclusterList))
    skincluster = skinclusterList[0]
    #print("skincluster= "+str(skincluster))
    return skincluster
    
startSelectionToNewSkinCluster()

完成ファイル (自分用リンク)

jennie9_6_v12z_v00127_Mouse_SW_Take2OK_Kihon_UE532ExportEnd.zip