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

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

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

書き出してー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/f93a78fa-9595-4ead-84b3-03a8bef3cf72.png)

unBindしてー

読み込み・・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/36d3c716-8cc9-0dca-0bff-cdc535f58ec6.png)
出来ないんですよねぇ

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


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

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

なぁに相手はXMLさ
-
諸事情で今回はXMLverで。

XMLの中身を見てみると・・・・
- deformターゲットのコンポーネント情報（index と　座標) \<shape> \</shape>
- インフルエンス毎のコンポーネントに対するウェイト値　\<weights> \</weights>

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

```python
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な感じにして
という流れで

実装
-

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/438f58dd-ba87-326b-e8f4-0b4d0ee71ad5.png)

bind & import されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/304d0d08-8ef2-788d-12ae-a7eddf96c058.png)

違うjointでバインド済みのメッシュに実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/0358ffb2-ecd1-3d88-afea-1e69ed747da5.png)

ノーマライズされてないな
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/c2bd67d8-fef5-d718-7faf-bad86bf47aa5.png)

ノーマライズを追加する
```python
cmds.skinCluster(targetSkinNode,e =True,forceNormalizeWeights = True)
```

ノーマライズは出来たけど、既存のウェイトと折半してしまってるなぁ
これはこれで便利そうだけど、完全に置き換えられるようにしたいな
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/9061dcbf-637b-a0f9-5511-4a68bd3deaf9.png)


https://help.autodesk.com/cloudhelp/2022/JPN/Maya-Tech-Docs/CommandsPython/deformerWeights.html

とりあえず完成
-

```python
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のアドベントカレンダーですかね！