[UnrealEngine] UE Python で TGAを書き出す方法

task = unreal.AssetExportTask()
task.set_editor_property('automated', True)
task.set_editor_property('filename', outfilepath)
task.set_editor_property('object', texture2d)
task.set_editor_property('prompt', False)
task.set_editor_property('exporter', unreal.TextureExporterTGA())

check = unreal.Exporter.run_asset_export_task(task)
      
if check==True:
    pass
else:
    alert(u"tga イメージの生成に失敗しました")

参考

https://zhuanlan.zhihu.com/p/240826602

[Maya] PysideでMayaにDockingするWindowの作り方

MayaにDockingするWindowを作ってみた。


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

"""
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(long(OpenMayaUI.MQtUtil.mainWindow()), QWidget)

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

from maya.app.general.mayaMixin import MayaQWidgetBaseMixin, MayaQWidgetDockableMixin

#class Example_connectAttr(MayaQWidgetDockableMixin, QScrollArea):
class Example_connectAttr(MayaQWidgetDockableMixin, QMainWindow):
    def __init__(self, node=None, *args, **kwargs):
        super(Example_connectAttr, self).__init__(*args, **kwargs)
        # Member Variables
        self.nodeName = node               # Node name for the UI
        self.attrUI = None                 # Container widget for the attr UI widgets
        self.attrWidgets = {}              # Dict key=attrName, value=widget
        
        randomInt=random.randint(0,9999)
        self.setObjectName("MyDock_Window"+str(randomInt))
        self.setWindowTitle("MyDock Window")
        self._initUI()
        
        
    def _initUI(self):
        wrapper = QWidget()
        self.setCentralWidget(wrapper)

        mainLayout = QVBoxLayout()
        wrapper.setLayout(mainLayout)
        

def start():
    maya_win = get_maya_pointer()
    ui = Example_connectAttr(node = maya_win)
    ui.show(dockable=True, floating=True)
    return ui

print("__name__ = "+__name__)
if __name__ == '__main__' or __name__ == "NppMaya" or __name__ == "main":

    app = QApplication.instance()
    if app is None:
        app = QApplication([])
    ui = start()
    app.exec_()

[maya]ウェイトのリストを高速に取得してみる。

基本は

cmds.skinPercent( skincluster, vtx, transform=bone, query=True)
経過時間 = 00h:03m:16s

だけどgetAttrでとろうとするとこうなる
参考 http://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html

経過時間 = 00h:03m:38s  ちょっと遅いんかい。

#get
skincluster="skinCluster1"
vert=8155
influence='joint1'

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt))   
evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
resultVal=pm.getAttr(evalStr)
print("resultVal= "+str(resultVal))

setAttrするにもこう

#set
skincluster="skinCluster1"
vert=8155
influence='joint1'
weight=1

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt)) 

evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
#print("evalStr= "+str(evalStr))
#pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
pm.setAttr(evalStr,weight)

om2でとるとこうなる。参考URL https://jamesbdunlop.github.io/om2/2018/03/29/IOSkins.html

import logging
import time, os
#import simplejson as json
import maya.api.OpenMaya as om2
import maya.cmds as cmds
#from OM2core.plugs.utils import getPlugValue, findPlugOnNode

def findPlugOnNode(node, plugName):
    """
    :param node: MObjectHandle
    :return: MPlug
    """
    if not node.isValid():
        raise Exception("Node is no longer valid!")

    mFn = om2.MFnDependencyNode(node.object())
    for x in xrange(mFn.attributeCount()):
        attr = om2.MFnAttribute(mFn.attribute(x))
        if attr.name == plugName:
            attr = mFn.attribute(plugName)
            plug = om2.MPlug(node.object(), attr)
            return plug

    raise Exception("PlugName {} is not valid!".format(plugName))


def getPlugValue(plug):
    """
    :param plug: MPlug. The node plug.
    :return: The value of the passed in node plug or None
    """
    pAttribute = plug.attribute()
    apiType = pAttribute.apiType()

    # Float Groups - rotate, translate, scale; Com2pounds
    if apiType in [om2.MFn.kAttribute3Double, om2.MFn.kAttribute3Float, om2.MFn.kCompoundAttribute]:
        result = []
        if plug.isCompound:
            for c in xrange(plug.numChildren()):
                result.append(getPlugValue(plug.child(c)))
            return result
    # Distance
    elif apiType in [om2.MFn.kDoubleLinearAttribute, om2.MFn.kFloatLinearAttribute]:
        return plug.asMDistance().asCentimeters()
        # Angle
    elif apiType in [om2.MFn.kDoubleAngleAttribute, om2.MFn.kFloatAngleAttribute]:
        return plug.asMAngle().asDegrees()
        # TYPED
    elif apiType == om2.MFn.kTypedAttribute:
        pType = om2.MFnTypedAttribute(pAttribute).attrType()
        # Matrix
        if pType == om2.MFnData.kMatrix:
            return om2.MFnMatrixData(plug.asMObject()).matrix()
            # String
        elif pType == om2.MFnData.kString:
            return plug.asString()
            # MATRIX
    elif apiType == om2.MFn.kMatrixAttribute:
        return om2.MFnMatrixData(plug.asMObject()).matrix()
        # NUMBERS
    elif apiType == om2.MFn.kNumericAttribute:
        pType = om2.MFnNumericAttribute(pAttribute).numericType()
        if pType == om2.MFnNumericData.kBoolean:
            return plug.asBool()
        elif pType in [om2.MFnNumericData.kShort, om2.MFnNumericData.kInt, om2.MFnNumericData.kLong,
                       om2.MFnNumericData.kByte]:
            return plug.asInt()
        elif pType in [om2.MFnNumericData.kFloat, om2.MFnNumericData.kDouble, om2.MFnNumericData.kAddr]:
            return plug.asDouble()
    # Enum
    elif apiType == om2.MFn.kEnumAttribute:
        return plug.asInt()

    return None

def _iterForSkinCluster(node):
    """
    :param node: MObject for the source connection
    :return: MObject
    """
    if node.apiType() == om2.MFn.kSkinClusterFilter:
        return om2.MObjectHandle(node)

    iterDg = om2.MItDependencyGraph(node,
                                    om2.MItDependencyGraph.kDownstream,
                                    om2.MItDependencyGraph.kPlugLevel)
    while not iterDg.isDone():
        currentItem = iterDg.currentNode() # use currentItem for 2017 and below
        if currentItem.hasFn(om2.MFn.kSkinClusterFilter):
            return om2.MObjectHandle(currentItem)

        iterDg.next()
def _findSkinCluster(mesh=None):
    """
    Returns a skinCluster attached to the kMesh or kNurbsCurve
    @:param mesh: MObjectHandle. Not the shape! Use the transform.
    :return: MObject
    """
    if not mesh.isValid():
        logger.warning("Destination is no longer valid!")
        return

    dagPath = om2.MDagPath()
    geo = dagPath.getAPathTo(mesh.object())

    ## Does it have a valid number of shapes?
    if geo.numberOfShapesDirectlyBelow() != 0:
        ## Fetch the shape of the geo now.
        shapeMobj = geo.extendToShape().node()
        mFn_shape = om2.MFnDependencyNode(shapeMobj)
        apiType = shapeMobj.apiType()
        if apiType == om2.MFn.kMesh:
            ## Look at the inMesh attr for the source
            inMesh_attr = mFn_shape.attribute('inMesh')
        elif apiType == om2.MFn.kNurbsCurve:
            inMesh_attr = mFn_shape.attribute('create')
        else:
            logger.warning("This type of om2.MFn node is not supported! int: {}".format(apiType))
            return

        inMesh_plug = om2.MPlug(shapeMobj, inMesh_attr)
        getSource = inMesh_plug.source().node()

        ## Now use the iterForSkinCluster() function to find the skinCluster in the connected network.
        skinClusterNode_MObjH = _iterForSkinCluster(getSource)

        if skinClusterNode_MObjH is not None:
            return skinClusterNode_MObjH
        else:
            return None

    return None

def _findInfluences(skinClusterMobjH=None):
    """
    Returns all the valid influences from the .matrix attribute on the skinCluster node.
    @:param mesh: MObjectHandle for the skinCluster. Using the handles here may be playing it a little too safe. But meh.
    :return: MObject
    """
    if not skinClusterMobjH.isValid():
        logger.warning("Skincluster is no longer valid! Did it get deleted?")
        return

    skClsMFnDep = om2.MFnDependencyNode(skinClusterMobjH.object())
    mtxAttr = skClsMFnDep.attribute("matrix")
    matrixPlug = om2.MPlug(skinClusterMobjH.object(), mtxAttr)

    ## Get a list of all the valid connected indices in the matrix array now.
    indices = matrixPlug.getExistingArrayAttributeIndices()
    influences = []
    for idx in indices:
        name = om2.MFnDependencyNode(matrixPlug.elementByLogicalIndex(idx).source().node()).absoluteName()
        influences.append(str(om2.MNamespace.stripNamespaceFromName(name)))

    return influences

def fileExists(filePath):
    if filePath is not None and os.path.isfile(filePath):
        logger.info("File exists!")
        return True

    return False

def writetoJSON(filePath, data):
    with open(filePath, 'w') as outfile:
        outfile.write(json.dumps(data))

    return True

def readFromJSON(filePath):
    with open(filePath) as infile:
        data = json.load(infile)
        return data

    return None

def _fetchSkinWeights(geoList=None, skipZeroWeights=True):
    """
    If you send in a list of geo, we'll use that. Else we assume we're working off selected.
    :param geoList: list() of string names for geometry to fetch data for
    :param skipZeroWeights: if you want to avoid saving all 0.0 weight data
    :return:
    """
    geo = om2.MSelectionList()
    if geoList is not None:
        for eachGeo in geoList:
            geo.add(eachGeo)
    else: #Assume selected
        for eachGeo in cmds.ls(sl=True):
            geo.add(eachGeo)

    weightData = {}
    for x in range(geo.length()):
        geoMObjH = om2.MObjectHandle(geo.getDependNode(x))
        geoName = om2.MFnDependencyNode(geoMObjH.object()).name()
        skinClusterMObjH = _findSkinCluster(geoMObjH)
        if skinClusterMObjH is None:
            logger.warning("Skipping {} has no skinCluster!".format(geoName))
            continue

        skName = str(om2.MFnDependencyNode(skinClusterMObjH.object()).name())

        influences = _findInfluences(skinClusterMObjH)
        ## Add the data to the dict
        weightData[geoName] = {}
        weightData[geoName][skName] = {}
        weightData[geoName][skName]['influences'] = influences
        weightData[geoName][skName]['maxInf'] = cmds.skinCluster(skName, q=True, maximumInfluences=True)
        weightData[geoName][skName]['weights'] = {}

        ## Fetch the weights now
        weightPlug = findPlugOnNode(skinClusterMObjH, 'weightList')
        weightCount = weightPlug.getExistingArrayAttributeIndices()
        for x in range(len(weightCount)):
            # .weightList[x]
            p = weightPlug.elementByLogicalIndex(weightCount[x])
            # .weights
            c = p.child(0)

            ## Now fetch the list of idx numbers that should relate to the inf [23, 66, 99]
            w = c.getExistingArrayAttributeIndices()

            ## For each idx we're going to build a tuple (idx, infName, weightVal)
            weightList = list()
            for i in range(len(w)):
                childPlug = c.elementByLogicalIndex(w[i])
                weightValue = getPlugValue(childPlug)

                if skipZeroWeights and weightValue == 0.0:
                    continue

                idx = w[i]
                weightList.append((idx, weightValue))

            weightData[geoName][skName]['weights'][str(x)] = weightList
            print("weightData["+str(geoName)+"]["+str(skName)+"][weights]["+str(x)+"]"+"= "+str(weightList))
    return weightData

weightData=_fetchSkinWeights(None,False)
#print("weightData= "+str(weightData))
_Weights=weightData[dupMesh][skincluster]["weights"][str(vert)]
print("_Weights= "+str(_Weights))


boneInt=0
        bones = pm.listConnections(str(skincluster) + ".matrix")
        boneslen=len(bones)
        for b in range(0,boneslen):
            bonename=bones[b]
            if influence in str(bonename):
                #print("found hit")
                boneInt=b


print("boneInt= "+str(boneInt))
weight=0
for _Weight in _Weights:
     #_Weight=(0, 0.8388942003250122)
     boneNum=_Weight[0]
     if(boneNum==boneInt):
           weight=_Weight[1]
print("weight= "+str(weight))

経過時間 = 00h:07m:10s om2なのに遅い。。。。
データ参照するためにfor分2個使うせいだな。
print消しても
経過時間 = 00h:04m:17s  おそい。。。

もっと早く取りたい

skincluster.getPointsAffectedByInfluence

インフルエンス骨基準で頂点のウェイトを問い合わせ回数を減らすことで早くなる。

getData = skincluster.getPointsAffectedByInfluence(InfluenceJoint)  

で取れるみたい。

詳しくはこちら。

https://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html


こんな感じで minidomに保存してそこからロードして使う。


import xml.dom.minidom as minidom

class SkinWeight_To_MiniDom():
    def getMeshVertex(self,objName):
        vtx = cmds.ls(objName+'.vtx[*]', fl=True)    
        return vtx
    def _showProgressDialog(self):
        self.WindowRef._showProgressDialog()#---------------------ProgressBar Starting--------------------------
        
    def setProgress(self,count):
        self.WindowRef.setProgress(count)

    def fnFindSkinCluster(self,mesh):
        skincluster = None
        for each in pm.listHistory(mesh):  
            if type(each)==pm.nodetypes.SkinCluster:   
                skincluster = each
        return skincluster
    def fnSaveSkinning(self,mesh,path): 
        print("SkinWeight_To_MiniDom---------fnSaveSkinning("+mesh+" path: "+path+")")
        # 次は、スキンウェイトの保存機能から始めましょう。
        ##skinClusterクラスには、influenceObjects()と呼ばれる関数があり、
        ##skinclusterにバインドされているすべてのジョイントを返します。
        ##次に、基本的に各ジョイントを反復処理し、各インフルエンスに対して関数getPointsAffectedByInfluence()を実行します。
        ##これにより、各頂点とその重みを含むリストが返されます。
        ##これらすべての値を適切なリストに保存し、minidomモジュールを利用してxmlファイルに保存できるようにします。
        
        ## データを収集します
        skincluster = self.fnFindSkinCluster(mesh)
     
        ## スキンクラスターが存在するかどうかを確認します
        if skincluster!=None:
            print(u"スキンクラスターがありました!")
            ## XMLxml_documentを準備します
            xml_doc = minidom.Document()
            xml_header = xml_doc.createElement("influences") 
            xml_doc.appendChild(xml_header)   

            ## ジョイントID/名前テーブルを書き出す  
            for each in skincluster.getInfluence():
                getData = skincluster.getPointsAffectedByInfluence(each)  
                tmpJoint= xml_doc.createElement(each)
                vertData = []
                if len(getData[0])>0:
                    ## すべての頂点IDを収集し、vertDataリストに保存します
                    for each in getData[0][0]:
                        vertData.append(each.currentItemIndex())
                    ## 次に、vertDataリストを「vertices」属性値として保存します
                    tmpJoint.setAttribute("vertices",str(vertData))
                    tmpJoint.setAttribute("weights",str(getData[1]))
                    xml_header.appendChild(tmpJoint)
         
            ## Save XML
            file = open(path, 'w')
            file.write(xml_doc.toprettyxml())
            pm.warning("Saved '%s.skinning' to '%s'"%(mesh,path))
        else:
            print(u"スキンクラスターがありません!")
            pm.warning('No skincluster connected to %s'%mesh)
 

    def fnLoadSkinning(self,mesh,path):  
        
        ##次に、いくつかの変数を使用して関数を設定し、メッシュがすでにスキンされている場合は、そのスキンクラスターを削除するようにします。
        ##後で新しいジョイントを作成し、スキンウェイトファイルに基づいてすべてのジョイントを自動的に追加します。
        
        ## 変数
        jointData = []
        skinData = []

        ### メッシュがすでにスキンされている場合は、メッシュをクリーンアップします
        skincluster = fnFindSkinCluster(mesh)
        if skincluster!=None:
            pm.runtime.DetachSkin(skincluster)
        
        ## 次に、xmlファイルを解析して、すべてのデータを整理しましょう。カスタムクラスcSkinningに基づいてオブジェクトを作成し、
        ## skinDataというリストに保存します。
        
        
        ## ドキュメントを解析し、XML形式に変換して、メモリにロードします
        xml_doc = minidom.parse(path)
        xml_doc.toxml()
         
        ## ルートノードを取得
        joints = xml_doc.childNodes[0].childNodes
    
        ## すべてのデータを収集し、cSkinningオブジェクトをskinDataリストに保存します
        for joint in joints:
            if joint.localName!=None:
                vertices = []
                weights = []
                jointData.append(joint.localName)   
                vertices = eval(joint.attributes.item(1).nodeValue)
                weights = eval(joint.attributes.item(0).nodeValue)
                skinData.append(cSkinning(vertices,joint.localName,weights))
        
        ##skinDataからアイテムをPrintすると、
        ##item.id、item.influence、またはitem.weightsを印刷すると、そのクラスに格納されているデータを確認できます。
        ##インフルエンスとウェイトはコヒーレントテーブルであるため、.weightsのインデックス15はインフルエンス15のウェイトを表すことがわかります。
        ##次に、スキンクラスターを作成し、すべてのジョイントを追加します。ウェイト属性を適用する前に、
        ##normalizeWeights属性を0に設定する必要があります。そうしないと、Mayaはウェイトを追加するたびにスキンウェイトを正規化します。
        ##また、skinPercentを使用してスキンをバインドする場合は、マヤの標準スキンウェイトを削除する必要があります。

        
        skincluster = pm.animation.skinCluster(mesh,jointData)
        skincluster.setNormalizeWeights(0)
        pm.skinPercent(skincluster, mesh, nrm=False, prw=100)
        
        ##ウェイトを適用する前に、最後に行う必要があることが1つあります。MayaはIDに基づいてWeightを保存します。新しいスキンクラスターを追加したため、
        ##これらのIDは古いIDと一致しなくなりました。ここでのこのコードは、skinDataリストでそれらを更新するだけです。
        
        tmpJoint = []
        for storedJoint in jointData:
            for skinnedJoint in skincluster.influenceObjects():
                if skinnedJoint==storedJoint:
                    tmpJoint.append(skincluster.indexForInfluenceObject(storedJoint))
             
        for each in range(0,len(skinData)):  
            skinData[each].influence = tmpJoint[each]
        
        ##素晴らしい、今ここに楽しい部分があります。setAttrを使用してスキンウェイトを追加しましょう。それが終わったら、スキンウェイトの正規化を再度オンにすることを忘れないでください。
        
        for each in range(0,len(skinData)):  
            for vertex in range(0,len(skinData[each].id)):
                vert = skinData[each].id[vertex]
                weights = skinData[each].weights[vertex]   
                pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
                
        ##約30kの頂点を持つメッシュの場合、約3秒かかりました。かなり許容できる約6秒の読み込み。スクリプトはMaya2012でテストされ、
        ##Maya 2013でこれを機能させるのに問題があると聞きましたが、残念ながらまだ調査する時間がありませんでした。聞いてくれてありがとう。
        
        #--------------------------------------------------

class cSkinning(): 
    def __init__(self,id,infl,weights):
        
        ##これでデータを保存できますが、ロードすることもできます。これはもう少し苦痛であることが判明しました。
        ##skinPercentを使用すると、スキンウェイトの設定が非常に遅くなる可能性があります。したがって、この場合、 
        ##setAttrを使用して値を直接設定しました。これはかなり高速です。
        ##少しずつ見ていきましょう。まず、データを効率的に保存するためのクラスを設定します。
    
        self.id = id  
        self.influence = infl
        self.weights = weights



SkinWeight_To_MiniDomClass=SkinWeight_To_MiniDom()
BaseMesh="Mesh"
#cmds.select(BaseMesh)
SkinWeight_To_MiniDomClass.fnSaveSkinning(BaseMesh,"baseMesh_SkinWeight_"+BaseMesh+".txt")

Texturing XYZ で購入したTextureを使用するためのディスプレイスメントツールの使用方法 For Maya2022

この文章は「https://texturing.xyz/pages/texturing-xyz-displacement-tool」を日本語に翻訳し 再編成したものです。

これはRichardTrouveによって作成されたスクリプトで、TexturingXYZワークフローを容易にし、Lookdevシーンの設定にかかる時間を節約します。

リチャードさん、ありがとうございます。

これはMaya2022のPython3に対応されてなかったので個人的に修正してアップしました。
[Maya2022+/ Arnold ]

https://drive.google.com/file/d/1rmbFkdWXMKl0l1gTE_X5XmnOnsLJKjMd/view?usp=sharing

1. ZIPファイルを解凍し、script.melをmayaにドロップして開始します。

2.これにより、現在のシェルフにXYZロゴが配置されます。

3.スクリプトを開くと、UIが表示されます。

オブジェクトを選択し、[選択]をクリックして、ベースメッシュを選択します。

※:そのオブジェクトのシェーダーが既にある場合は、[現在のシェーダーを保持する]にチェックマークを付けます。

4. texturingXYZディスプレイスメントを選択し
今回は(XYZ_dispMultiChannel_mid50_lin_srgb.1001.exr)
フロートディスプレイスメントがある場合はそれを選択します。(ZbrushまたはMudboxの変位)(今回はなし)

5. [セットアップ]をクリックすると、

ハイパーシェードですべてのノードが接続され、ベースメッシュの形状のサブディビジョン設定も接続されます。あなたが今する必要があるのはあなたのコンテンツにブレンドを調整することだけであり、あなたは準備ができています!

翻訳はここまで

さーて違いが出ないので、肌のテクスチャ入れてからkeep current shader をオンにしてみた。わからん。

Arnorldでプレビューしないとだめにきまってるやん。

Arnoldでレンダリングしてみた。、違いがわからん。けどきれいやねalbedだけで。
左:albed 右:albed + (今回のtexturingXYZ DisplacementMap)

1行コードを分解するサンプルたくさん。

個人的に大嫌いな1行forや1行ifをつぶしていくサンプルコードたち。

class Acla:
    
    def unite_selection(self):
        #selected = [x for x in cmds.ls(sl=True) if cmds.listRelatives(x, type="mesh")]
        selected=[]
        for x in cmds.ls(sl=True):
            xx= cmds.listRelatives(x, type="mesh")
            if xx:
                selected.append(xx)
        
        
        if not selected:
            print("not selected")
            return
        #invalid_meshes = [x for x in cmds.listRelatives(selected, type="mesh", f=True) if not cmds.listConnections(x)]
        
        invalid_meshes = []
        for x in cmds.listRelatives(selected, type="mesh", f=True):
            xx= cmds.listConnections(x)
            if not xx:
                invalid_meshes.append(xx)
        
        if invalid_meshes:
            print("invalid", invalid_meshes)
            return
        res = cmds.polyUnite(*cmds.ls(sl=True), ch=0, op=True, muv=1)
        print(res)

ClassIns=Acla()
ClassIns.unite_selection()

Maya get Mesh Width Height Depth 幅,高さ、奥行きを測る

バウンディングボックスの関数をつかって測る

あくまでMayaの座標系での話だけど、まあ一緒か。

def get_MeshWidthHeightDepth(MeshName):
    boundingBox=cmds.polyEvaluate(MeshName, boundingBox=True )
    print("boundingBox= "+str(boundingBox))
    tapleX=boundingBox[0]
    tapleY=boundingBox[1]
    tapleZ=boundingBox[2]
    
    minX=tapleX[0]
    maxX=tapleX[1]
    depth=maxX-minX
    print("depth= "+str(depth))

    minY=tapleY[0]
    maxY=tapleY[1]
    height=maxY-minY
    print("height= "+str(height))
    
    minZ=tapleZ[0]
    maxZ=tapleZ[1]
    width=maxZ-minZ
    print("width= "+str(width))
    
    return width,height,depth

width,height,depth = get_MeshWidthHeightDepth("pCube2")