mayaの標準でskinWeightをjsonとかxmlで書き出せるようになったんですよね、いつの間にか。
参考
https://area.autodesk.jp/column/tutorial/maya_atoz/save-load-skin-weight/
unBindしてー
書き出したファイルに記載されてるインフルエンスで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)
ノーマライズを追加する
cmds.skinCluster(targetSkinNode,e =True,forceNormalizeWeights = True)
ノーマライズは出来たけど、既存のウェイトと折半してしまってるなぁ
これはこれで便利そうだけど、完全に置き換えられるようにしたいな
とりあえず完成
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のアドベントカレンダーですかね!