2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MayaAdvent Calendar 2023

Day 5

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

Last updated at Posted at 2023-12-04

mayaの標準でskinWeightをjsonとかxmlで書き出せるようになったんですよね、いつの間にか。

参考
https://area.autodesk.jp/column/tutorial/maya_atoz/save-load-skin-weight/

書き出してー
image.png

unBindしてー

読み込み・・・・
image.png
出来ないんですよねぇ

書き出したファイルに記載されてるインフルエンスでbind済みじゃないと、skinWeightを再現できないんですよね。

じゃぁどうすっかな

XMLファイルとバインドしてないjointとメッシュが送られてきて、
このスキンウェイトで再現できますんで!
って言われたら もう嫌になってダンゴムシになると思います。

なので、xmlをimportする際にバインドもしてしまいましょうや
というのが今回の趣旨です。

なぁに相手はXMLさ

諸事情で今回はXMLverで。

XMLの中身を見てみると・・・・

  • deformターゲットのコンポーネント情報(index と 座標) <shape> </shape>
  • インフルエンス毎のコンポーネントに対するウェイト値 <weights> </weights>

まずはインフルエンスを全部集めないとな

from xml.etree import ElementTree
targetFilePath = "C:/Users/9boz/Desktop/testWeight.xml"
tree = ElementTree.parse(targetFilePath)
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()):
        skinBindDict[deformer]["inf"].append(inf)
    else:
        skinBindDict[deformer] = {
                                    "inf":[inf],
                                    "shape":shape
                                    }


{'skinCluster1': {'inf': ['joint3', 'joint1', 'joint2'], 'shape': 'pSphereShape1'}}

読み込めましたわね。

バインドする

取得したインフルエンスで先にバインドしてからimportを実行すればいいので、

https://qiita.com/9boz/items/bb2e49ffef628a437bf6
ここで1年前の記事再利用

XMLからメッシュとインフルエスを取得して、
メッシュのskinClusterの有無を確認して、
有ならaddInfして、無ならbindして
copySkinWeights じゃなくて deformerWeightsな感じにして
という流れで

実装

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)            

unbindしたメッシュに実行すると
image.png

bind & import されました
image.png

違うjointでバインド済みのメッシュに実行すると
image.png

ノーマライズされてないな
image.png

ノーマライズを追加する

cmds.skinCluster(targetSkinNode,e =True,forceNormalizeWeights = True)

ノーマライズは出来たけど、既存のウェイトと折半してしまってるなぁ
これはこれで便利そうだけど、完全に置き換えられるようにしたいな
image.png

とりあえず完成

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)

importSkinWeight("C:/Users/9boz/Desktop/","testWeight.xml")

改修は・・・・・2024のアドベントカレンダーですかね!

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?