copySkinWeightsを少し便利に

copySkinWeights　って便利なんですが、そのまま使うには少々イラっとする事も。


制限
-

- 転送先のオブジェクトはスキニングされている必要がある
- 転送元のインフルエンスは転送先にもすべて登録されていなければならない

smoothBindをselected joints で実行して add influenceを繰り返して調整していく身としては、
とても面倒なので1クリックで実行したいです。

設計
-

- 転送元のskinClusterからinfluenceを取得
- 転送先のオブジェクトがスキニング済みかチェック
- 未スキニングならsmoothBind実行
- バインド済みならば転送元influenceをaddInf
- copySkinWeights実行

んー個別の処理はそんなに問題ない気がしますね。

実装
-

- 転送元のskinClusterからinfluenceを取得

まずはskinClusterを取得して・・・
なんかskinClusterを狙い撃ちで検索するコマンドがあったような

https://help.autodesk.com/cloudhelp/2022/JPN/Maya-Tech-Docs/Commands/findRelatedSkinCluster.html

あった！　けど！　melのみか！

あとは使えそうなのはこの辺かしら

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

とりあえず　listHistory　でいいか。

```python
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 copySkinWeights(source,target):
    sourceSkinNode = getSkinClusterNode(source)
    sourceInfs = cmds.skinCluster(sourceSkinNode, q =True, inf =True) 

```

- 転送先のオブジェクトがスキニング済みかチェック

これはさっきのskinCluster取得を再利用ですね。

```python
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 copySkinWeights(source,target):
    sourceSkinNode = getSkinClusterNode(source)
    sourceInfs = cmds.skinCluster(sourceSkinNode, q =True, inf =True) 

    targetSkinNode = getSkinClusterNode(target)

    if targetSkinNode == None:
        pass
    else:
        pass
```

- 未スキニングならsmoothBind実行
こっちはskinClsuterのオプションに注意しつつ実行
**skinMethod**　とか　**normalizeWeights**　とか　**toSelectedBones**　とか
真面目にやるなら転送元のskinClusterから取得するんでしょうな。

- バインド済みならば転送元influenceをaddInf
なにも考えずにaddInfでも良い気がするけど、転送先の既存influenceと重複すると怒られるので
念のため差分取って必要なinfluenceだけaddInfに。

```python
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 copySkinWeights(source,target):
    sourceSkinNode = getSkinClusterNode(source)
    sourceInfs = cmds.skinCluster(sourceSkinNode, q =True, inf =True) 

    targetSkinNode = getSkinClusterNode(target)

    if targetSkinNode == None:
        targetSkinNode = cmds.skinCluster(sourceInfs,target,normalizeWeights = 1,toSelectedBones =True)[0]
    else:
        targetInfs = cmds.skinCluster(targetSkinNode, q =True, inf =True) 
        addInfs = list(set(sourceInfs) - set(targetInfs))
 
        for inf in addInfs:
            cmds.skinCluster(targetSkinNode, e =True, ai = inf, weight = 0)

```

一旦テストしてみる

sphere1を雑にバインドし、
未バインド状態のsphere2に対して実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/bf2d43f9-5358-fa16-0d1c-844cefe8b140.png)

```
copySkinWeights("pSphere1","pSphere2")

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/475716c6-cacd-af39-d4cc-fbd912296070.png)

バインドされましたね。

次に別のジョイントであらかじめsphere2をバインドして実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/deaae7e5-c5a9-2595-e55b-61282c9a16c2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/91739c81-a1e3-caac-cddc-69c37f947635.png)

追加されましたね。

- copySkinWeights実行

念のためオプションを確認してみる

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

ツール化するなら　sampleSpace とか　uvSpace　とか色々使えそうだけれども
ひとまずいつも使っているオプションで固定

```python
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 copySkinWeights(source,target):
    sourceSkinNode = getSkinClusterNode(source)
    sourceInfs = cmds.skinCluster(sourceSkinNode, q =True, inf =True) 

    targetSkinNode = getSkinClusterNode(target)

    if targetSkinNode == None:
        targetSkinNode = cmds.skinCluster(sourceInfs,target,normalizeWeights = 1,toSelectedBones =True)[0]
    else:
        targetInfs = cmds.skinCluster(targetSkinNode, q =True, inf =True) 
        addInfs = list(set(sourceInfs) - set(targetInfs))
 
        for inf in addInfs:
            cmds.skinCluster(targetSkinNode, e =True, ai = inf, weight = 0)

    cmds.copySkinWeights(
                            ss=sourceSkinNode,
                            ds=targetSkinNode, 
                            sampleSpace = 0,
                            noMirror = True,
                            smooth = False,
                            normalize =True,
                            surfaceAssociation = "closestPoint",
                            influenceAssociation = ["name","closestJoint","closestBone"]
                        )

```

sphere2(未バインド)をハイポリにして実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/eea5e16b-e4ec-0953-6afa-e054a2272411.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/34419793-79cf-39b2-ba3b-4df83813daa5.png)

を大丈夫そうかな？

ひとまず完成。

不具合
-

ポリゴン -> ポリゴン OK
ナーブスカーブ -> ナーブスカーブ OK
ポリゴン -> ナーブスカーブ OK

ポリゴン　-> ナーブスサーフェス　うなくいかない
ナーブスサーフェス -> ポリゴン　うなくいかない
ナーブスサーフェス -> ナーブスサーフェス うなくいかない

で　やばいのが

**ナーブスサーフェス -> ナーブスカーブ　落ちる**

図らずも地雷を発見。
コマンドとか関わらず

**nurbsSurface　から nurbsCurveに対してcopySkinWeightsを実行するとmayaが即落ちする**

気を付けてくださいね！

※この時、スクリプトエディタの内容も飛んだのですが　記事書きつつだったのでセーフ！