0
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 2022

Day 10

copySkinWeightsを少し便利に

Posted at

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

制限

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

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

設計

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

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

実装

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

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

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

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

とりあえず listHistory でいいか。

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取得を再利用ですね。

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に。

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

copySkinWeights("pSphere1","pSphere2")

image.png

バインドされましたね。

次に別のジョイントであらかじめsphere2をバインドして実行
image.png

image.png

追加されましたね。

  • copySkinWeights実行

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

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

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

image.png

を大丈夫そうかな?

ひとまず完成。

不具合

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

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

で やばいのが

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

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

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

気を付けてくださいね!

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

0
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
0
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?