0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MayaAdvent Calendar 2023

Day 18

maya skinWeight import をちょっと何とかする2

Last updated at Posted at 2023-12-19

もうちょっと何とかしたくなりました。

具体的には

objectA がスキニングされてる状態で、
同一メッシュのobjectB,objectCにもjoint名を変えて
ウェイト情報を転送したい

考える

objectAのスキニング情報をXMLで書き出して、
XMLファイルをテキストデータとして扱って、中身をreplaceして読ませるとか?

ただ予期せぬ箇所のreplaceが発生すると困る。

ちゃんと?やるなら

  • objectAのスキニング情報をXMLファイルで書き出して、
  • XMLファイルをXMLのデータとしてパースして、
  • 対象となるアトリビュートを書き換えて、
  • 書き換えた内容をどこかにXMLとして保存して、
  • 前回作った importSkinWeight に渡す。

とかかなぁ

雑に実装

import maya.cmds as cmds
from xml.etree import ElementTree

def getSkinClusterNode(target):
    history = cmds.listHistory(target,pruneDagObjects =True)    
    skinNode = cmds.ls(history,type = "skinCluster") or None
    
    if skinNode != None:
        return skinNode[0]

    return None

def getBindInfo(filePath):
    tree = ElementTree.parse(filePath)
    root = tree.getroot()
    skinBindDict = {}
    
    ##weights を見つける
    for e in root.findall('weights'):
        #それぞれのパラメーターを取得
        inf = e.get("source")
        shape = e.get("shape")
        deformer = e.get("deformer")
    
        if deformer in list(skinBindDict.keys()):
            if inf not in skinBindDict[deformer]["inf"]:
                skinBindDict[deformer]["inf"].append(inf)
        else:
            skinBindDict[deformer] = {
                                        "inf":[inf],
                                        "shape":shape
                                        }
    return skinBindDict
                                        
def importSkinWeight(filePath,fileName):
    skinBindDict = getBindInfo(filePath+fileName)

    for deformerNode in list(skinBindDict.keys()):        
        target = skinBindDict[deformerNode]["shape"]
        infs = skinBindDict[deformerNode]["inf"]
        
        #skinClusterの有無確認
        targetSkinNode = getSkinClusterNode(target)

        if targetSkinNode == None:
            targetSkinNode = cmds.skinCluster(infs,target,normalizeWeights = 1,toSelectedBones =True,name = deformerNode)[0]
        else:
            #現在のインフルエンスを取得して、addInfするための差分を取る
            curInfs = cmds.skinCluster(targetSkinNode, q =True, inf =True) 
            addInfs = list(set(infs) - set(curInfs))
 
            for inf in addInfs:
                cmds.skinCluster(targetSkinNode, e =True, ai = inf, weight = 0)

        cmds.deformerWeights(fileName, path = filePath, deformer = targetSkinNode, method = "index",im = True)            
        cmds.skinCluster(targetSkinNode,e =True,forceNormalizeWeights = True)

#ここから今回のネタ-----
def substituteSkinWeight(source,target,searchString,replaceString):
    #sourceのスキニング情報を書き出す
    sourceSkinNode = getSkinClusterNode(source)
    if sourceSkinNode == None:
        return

    #書き出し場所はひとまずmayaのuserAppDir
    tmpExportPath = cmds.internalVar(userAppDir=True) + 'temp/'
    tmpFileName = "tempSkinWeight.xml"
    cmds.deformerWeights(
                            tmpFileName, 
                            path = tmpExportPath, 
                            deformer = sourceSkinNode, 
                            format ="XML",ex = True
                            )        

    targetShape = cmds.listRelatives(target,type = "shape")[0]

    #sourceのXMLを読み込む
    tree = ElementTree.parse(tmpExportPath+tmpFileName)
    root = tree.getroot()    

    #各アトリビュートを書き換える
    #<shape> の name と
    #<weights> の deformer / source / shape  を最低限書き換えれば行けるかな?    
    for e in root.findall('shape'):
        e.set("name",targetShape)
        
    for e in root.findall('weights'):
        targetInf = e.get("source")
        replaceInf = targetInf.replace(searchString,replaceString)            
        e.set("source",replaceInf)
        e.set("shape",targetShape)
        
        #skinCluster名も念のため調整
        e.set("deformer",target + "_skinCluster")
    
    #XMLファイルとして保存する(上書き)
    tree.write(tmpExportPath + tmpFileName, encoding='UTF-8')

    #XMLファイルを読み込ませる
    importSkinWeight(tmpExportPath,tmpFileName)

    #一応一時ファイルとしては削除
    os.remove(tmpExportPath+tmpFileName)

こんな感じのデータを用意して、pCube1 のスキンウェイトをpCube2へ
image.png

substituteSkinWeight("pCube1","pCube2","cubeA","cubeB")
# Exported deformer weights to 'C:/Users/kubo/Documents/maya/temp/tempSkinWeight.xml'. # 

お、行けたっぽい。
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?