選択したMeshグループAからBへスキンウェイトを全部コピーMEL

Meshグループに無数にMeshがはいっててスキンウェイトをコピーするのがめんどくさくなったから書いたよ

Aのメッシュグループから
Bのメッシュグループにコピーしていく

動作はちょっと逆で
Bのグループのメッシュ名をループして
Aのグループのメッシュ名にあるか探す
あったらスキンウェイトコピー
なかったらrejectedリストに入れてます。
最後にrejectedListを表示するのでスキンウェイトしなかったメッシュのリストが出ます。

// SkinWeightCopy First Select MeshGroup to Second Select MeshGroup 
string $selectedArrFUllPath[] = `ls -long -sl`;
print($selectedArrFUllPath);

string $FirstSelect=$selectedArrFUllPath[0];

string $SecondSelect=$selectedArrFUllPath[1];

string $rejectArr[];

string $inputNodes[] = `ls -type transform -long -dag $FirstSelect`;
string $destNodes[] = `ls -type transform -long -dag $SecondSelect`;

$inputNodeslong=size($inputNodes);
$destNodeslong=size($destNodes);

string $buffer[];
string $buffer_i[];
$finded = 0;
for($d = 0; $d <$destNodeslong;$d++){
    string $destNode_name=$destNodes[$d];
    
    if($destNode_name==$SecondSelect){
            
    }else{
        print("$destNode_name= "+$destNode_name+"\n");
        
        $numTokens = `tokenize $destNode_name "|" $buffer`;
        $bufferlong=size($buffer);
        string $destNode_name_Short = $buffer[$bufferlong-1]+"";
        print("$destNode_name_Short= "+$destNode_name_Short+"\n");
        $finded = 0;
        for($i = 0; $i <$inputNodeslong;$i++){
            string $inputNode_name=$inputNodes[$i];
            $numTokens_i = `tokenize $inputNode_name "|" $buffer_i`;
            $bufferlong_i=size($buffer_i);
            string $inputNode_name_Short = $buffer_i[$bufferlong_i-1]+"";
            print("$inputNode_name_Short= "+$inputNode_name_Short+"\n");
                
            //$index=`gmatch $inputNode_name $destNode_name_Short`;
            //if($index > 0){
            if($inputNode_name_Short==$destNode_name_Short){
                //$blendShapeName = $blendshapeRet_name;
                print("$destNode_name= "+$destNode_name+" isHit!! "+"\n");
                select -r $inputNode_name;
                select -add $destNode_name;
                copySkinWeights  -noMirror -surfaceAssociation closestPoint -influenceAssociation closestJoint;
                //copySkinWeights -noMirror -surfaceAssociation closestPoint -influenceAssociation closestJoint -sourceSkin $inputNode_name -destinationSkin $destNode_name;
                $finded = 1;
            }
        }
        if($finded==0){
            $rejectArr[size($rejectArr)] = $destNode_name;
        }
    }
}
print("----rejected_list---start"+"\n");
print($rejectArr);
print("----rejected_list---end"+"\n");
select -r $FirstSelect ;
select -add $SecondSelect ;

メッシュグループ内のグループを無視できるように、MeshのTransformだけをフィルターした。

// SkinWeightCopy First Select MeshGroup to Second Select MeshGroup 
string $selectedArrFUllPath[] = `ls -long -sl`;
print($selectedArrFUllPath);

string $FirstSelect=$selectedArrFUllPath[0];

string $SecondSelect=$selectedArrFUllPath[1];

string $rejectArr[];

//string $inputNodes[] = `ls -type transform -long -dag $FirstSelect`;
//string $destNodes[] = `ls -type transform -long -dag $SecondSelect`;

string $inputNodes_mesh[] = `ls -type mesh -long -dag $FirstSelect`;
string $destNodes_mesh[] = `ls -type mesh -long -dag $SecondSelect`;

$inputNodes_meshlong=size($inputNodes_mesh);
$destNodes_meshlong=size($destNodes_mesh);

string $inputNodes[];
string $destNodes[];
clear $inputNodes;
clear $destNodes;
string $mesh;
string $parent;
for($d0 = 0; $d0 <$inputNodes_meshlong;$d0++){
    $mesh=$inputNodes_mesh[$d0];
    string $parentS[] = `listRelatives -parent -path -type transform $mesh`;
    $parent=$parentS[0];
    $inputNodes[size($inputNodes)] = $parent;
}
for($d0 = 0; $d0 <$destNodes_meshlong;$d0++){
    $mesh=$destNodes_mesh[$d0];
    string $parentS[] = `listRelatives -parent -path -type transform $mesh`;
    $parent=$parentS[0];
    $destNodes[size($destNodes)] = $parent;
}

print("$inputNodes= ------------------------------------------------ \n");
print($inputNodes);

print("$destNodes= ------------------------------------------------ \n");
print($destNodes);



$inputNodeslong=size($inputNodes);
$destNodeslong=size($destNodes);

string $buffer[];
string $buffer_i[];
$finded = 0;
for($d = 0; $d <$destNodeslong;$d++){
    string $destNode_name=$destNodes[$d];
    
    if($destNode_name==$SecondSelect){
            
    }else{
        print("$destNode_name= "+$destNode_name+"\n");
        
        $numTokens = `tokenize $destNode_name "|" $buffer`;
        $bufferlong=size($buffer);
        string $destNode_name_Short = $buffer[$bufferlong-1]+"";
        print("$destNode_name_Short= "+$destNode_name_Short+"\n");
        $finded = 0;
        for($i = 0; $i <$inputNodeslong;$i++){
            string $inputNode_name=$inputNodes[$i];
            $numTokens_i = `tokenize $inputNode_name "|" $buffer_i`;
            $bufferlong_i=size($buffer_i);
            string $inputNode_name_Short = $buffer_i[$bufferlong_i-1]+"";
            print("$inputNode_name_Short= "+$inputNode_name_Short+"\n");
                
            //$index=`gmatch $inputNode_name $destNode_name_Short`;
            //if($index > 0){
            if($inputNode_name_Short==$destNode_name_Short){
                //$blendShapeName = $blendshapeRet_name;
                print("$destNode_name= "+$destNode_name+" isHit!! "+"\n");
                select -r $inputNode_name;
                select -add $destNode_name;
                copySkinWeights  -noMirror -surfaceAssociation closestPoint -influenceAssociation closestJoint;
                //copySkinWeights -noMirror -surfaceAssociation closestPoint -influenceAssociation closestJoint -sourceSkin $inputNode_name -destinationSkin $destNode_name;
                $finded = 1;
            }//if
        }//for
        if($finded==0){
            $rejectArr[size($rejectArr)] = $destNode_name;
        }//if
    }//if
}//for
print("----rejected_list---start"+"\n");
print($rejectArr);
print("----rejected_list---end"+"\n");
select -r $FirstSelect ;
select -add $SecondSelect ;

[Daz3D][Maya][Marvelous Designer] Das3D 4.22 Genesis9をMaya2022に持ってきてMarvelous Designerの服をスキニングしてコピースキンウェイトしたVol.02(まとめ)

このノード状態がキレイなので「bindPose1が一つだけ」キープしながらモデリング編集すること。

Genesis9 やったこと

—————————————-ここからはモデリングとする。——————————————–
Das3D 4.22 のGenesis9を
Maya2022に持ってきて

duplicateでスキンバインド外し=複製して
meshGroupのグループに
・genesis9のまつ毛や口のレイヤーも入れる(skinCluster初めから無いので)
・Marvelous Designerの服レイヤーも入れる
・highheelレイヤーも入れる
highheelの高さにhipとmeshGroupをmoveする。(オプション)
↑高さはBluePrintで変更可能

—————————————-ここまではモデリングとする。——————————————–

新しい方の骨とmeshGroupでバインド
↑ちゃんとしたバインドオプションが重要
cmds.skinBind()引数なしじゃclusterがダメ
genesis9からcopySkinWeightした

モデル編集後ファイル (自分用リンク)」

jennie9_6_v12z_v00122_dupGen9_Kihon.zip

#jennie9_6_v12z_v00122_dupGen9_Kihon__ModelEnd_SkinBindSkinWeight.py

def startSelectionToNewSkinCluster():
    selectList=cmds.ls(sl=1,long=1)
    print("selectList= "+str(selectList))
    # 全部必要だから引数にした
    Genesis9 = selectList[0]
    Genesis9_Mesh = selectList[1]
    Genesis9s = selectList[2]
    MeshGroup = selectList[3]
    #------------------------------------------------------------------------
    ModelEnd_SkinBind(Genesis9s,MeshGroup)
    ModelEnd_SkinWeight(Genesis9,Genesis9_Mesh,Genesis9s,MeshGroup)
    #------------------------------------------------------------------------
    
def ModelEnd_SkinBind(Genesis9s,MeshGroup):
    
    cmds.select(Genesis9s,MeshGroup)
    #MEL  (Script found in: C:/Program Files/Autodesk/Maya2022/scripts/others/newSkinCluster.mel)
    #newSkinCluster " -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0";
    
    #Python でMEL実行
    import maya.mel
    maya.mel.eval('newSkinCluster " -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0";')
    
    #Python  NG  'maya.cmds' has no attribute 'newSkinCluster' # 
    #cmds.newSkinCluster(" -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0")

    #import pymel.core as pm #OK
    #pm.mel.newSkinCluster(" -bindMethod 0  -normalizeWeights 1 -weightDistribution 0 -mi 3  -dr 4 -rui false -ihs , multipleBindPose, 0")
def ModelEnd_SkinWeight(Genesis9,Genesis9_Mesh,Genesis9s,MeshGroup):
    
    Genesis9_Low_skincluster = Get_SkinCluster(Genesis9_Mesh)
    print("Genesis9_Low_skincluster= "+str(Genesis9_Low_skincluster))
    
    MeshList = cmds.listRelatives(MeshGroup,shapes=0,fullPath=1)
    print("MeshList= "+str(MeshList))
    
    for closet_mesh in MeshList:
        closet_skinCluster = Get_SkinCluster(closet_mesh)
        print("closet_skinCluster= "+str(closet_skinCluster))
        
        # 元のスキンクラスターを服のスキンクラスターへコピースキンウェイト
        cmds.copySkinWeights(
            sourceSkin = Genesis9_Low_skincluster,
            destinationSkin = closet_skinCluster,
            noMirror=True,
            influenceAssociation="oneToOne",
            surfaceAssociation="closestPoint"
        )
    
def Get_SkinCluster(LowMeshTransformLong):
    # トランスフォームのシェイプノードを取得
    shapeList = cmds.listRelatives(LowMeshTransformLong, shapes=True, noIntermediate=True,fullPath=True)
    #print("shapeList= "+str(shapeList))
    # lowのヒストリーを取得し、スキンクラスターのみ取得
    historyList = cmds.listHistory(shapeList[0], pruneDagObjects=True, interestLevel=2)
    #print("historyList= "+str(historyList))
    skinclusterList = cmds.ls(historyList, type="skinCluster")
    #print("skinclusterList= "+str(skinclusterList))
    skincluster = skinclusterList[0]
    #print("skincluster= "+str(skincluster))
    return skincluster
    
startSelectionToNewSkinCluster()

完成ファイル (自分用リンク)

jennie9_6_v12z_v00127_Mouse_SW_Take2OK_Kihon_UE532ExportEnd.zip

[unrealEngine,Maya]で腕や足がスカートを貫通しないようにしたい

あくまで、自分の研究例ですと
スカートで足に追従させたいものは
「膝にスキニングしたほうが作業的に効率的」です。
ジャンプや走るモーションで
前側のスカートは膝で突き破るので、
膝にスキンウェイト当てておきます。
というより

タイトスカートのスキンウェイトは、まず足にスキンウェイトを足の一部のようにスキンウェイトをコピーします。
前側の又の部分は左右の足から同じ左0.5、右0.5になるようにスキンウェイトします。
ロングタイトスカートはこれでできます。

スカートのケージモデルが膝に追従する例です。
ただ、まだ、突き破っているので、スカートモデルと体の隙間をもっと大きくした方がいいでしょう


あとは物理で動かしたい頂点は下のようにします
さらに、フレアスカートの場合は
スカートの左右と後ろ部分は、放射状にジョイントをいれヒザのスキンウェイトとグラデーションするようにスキンウェイトします。あとは、おかずさんのkawaii physics で、マニュアル通り設定します。

関連

[maya]「スムーズ スキン サーフェスから未使用のインフルエンスを除去する」だけで、すごくいろんな動作が軽くなる。

Maya の処理スピードを向上させスキン ウェイト ペイント ツール(Paint Skin Weights Tool)を使いやすくするために、全てのスキン ウェイトが 0 であるスムーズ スキンから、ジョイントとインフルエンス オブジェクトを接続解除することができます。これにより未使用のインフルエンスがスキンのインフルエンス(Influence)リストに表示されなくなり、スキン ウェイト ペイント ツール(Paint Skin Weights Tool)が使いやすくなります。

たとえば、既定のオプションを使って、人間のスケルトンにストッキングをはいた左足をスムーズ スキニングするとします。スケルトン内のすべてのジョイントがポテンシャル インフルエンスとしてストッキングに接続されますが、ウェイトが 0 以外の値になるのは左足のストッキングに最も近いジョイントだけです。

肘を選択して回転させると、Maya はストッキングのスキンを計算して 0 以外の値をもつウェイトがないかどうかを調べます。ストッキングを未使用のインフルエンスから接続解除すると、肘とウェイトが 0 のその他のジョイントの回転を処理する必要がなくなり、パフォーマンスが向上します。

未使用のインフルエンスを除去するには

  1. スキンを選択します。
  2. スキン > 影響を編集 > 使われていないインフルエンスの除去(Skin > Edit Influences > Remove Unused Influences)を選択します。

[maya]ウェイトのリストを高速に取得してみる。

基本は

cmds.skinPercent( skincluster, vtx, transform=bone, query=True)
経過時間 = 00h:03m:16s

だけどgetAttrでとろうとするとこうなる
参考 http://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html

経過時間 = 00h:03m:38s  ちょっと遅いんかい。

#get
skincluster="skinCluster1"
vert=8155
influence='joint1'

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt))   
evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
resultVal=pm.getAttr(evalStr)
print("resultVal= "+str(resultVal))

setAttrするにもこう

#set
skincluster="skinCluster1"
vert=8155
influence='joint1'
weight=1

bones=pm.listConnections(str(skincluster) + ".matrix")

print("bones= "+str(bones))

boneInt=0
boneslen=len(bones)
for b in range(0,boneslen):
    bonename=bones[b]
    if influence in str(bonename):
        print("found hit")
        boneInt=b
print("boneInt= "+str(boneInt)) 

evalStr=str(skincluster)+'.weightList['+str(vert)+'].weights['+str(boneInt)+']'
#print("evalStr= "+str(evalStr))
#pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
pm.setAttr(evalStr,weight)

om2でとるとこうなる。参考URL https://jamesbdunlop.github.io/om2/2018/03/29/IOSkins.html

import logging
import time, os
#import simplejson as json
import maya.api.OpenMaya as om2
import maya.cmds as cmds
#from OM2core.plugs.utils import getPlugValue, findPlugOnNode

def findPlugOnNode(node, plugName):
    """
    :param node: MObjectHandle
    :return: MPlug
    """
    if not node.isValid():
        raise Exception("Node is no longer valid!")

    mFn = om2.MFnDependencyNode(node.object())
    for x in xrange(mFn.attributeCount()):
        attr = om2.MFnAttribute(mFn.attribute(x))
        if attr.name == plugName:
            attr = mFn.attribute(plugName)
            plug = om2.MPlug(node.object(), attr)
            return plug

    raise Exception("PlugName {} is not valid!".format(plugName))


def getPlugValue(plug):
    """
    :param plug: MPlug. The node plug.
    :return: The value of the passed in node plug or None
    """
    pAttribute = plug.attribute()
    apiType = pAttribute.apiType()

    # Float Groups - rotate, translate, scale; Com2pounds
    if apiType in [om2.MFn.kAttribute3Double, om2.MFn.kAttribute3Float, om2.MFn.kCompoundAttribute]:
        result = []
        if plug.isCompound:
            for c in xrange(plug.numChildren()):
                result.append(getPlugValue(plug.child(c)))
            return result
    # Distance
    elif apiType in [om2.MFn.kDoubleLinearAttribute, om2.MFn.kFloatLinearAttribute]:
        return plug.asMDistance().asCentimeters()
        # Angle
    elif apiType in [om2.MFn.kDoubleAngleAttribute, om2.MFn.kFloatAngleAttribute]:
        return plug.asMAngle().asDegrees()
        # TYPED
    elif apiType == om2.MFn.kTypedAttribute:
        pType = om2.MFnTypedAttribute(pAttribute).attrType()
        # Matrix
        if pType == om2.MFnData.kMatrix:
            return om2.MFnMatrixData(plug.asMObject()).matrix()
            # String
        elif pType == om2.MFnData.kString:
            return plug.asString()
            # MATRIX
    elif apiType == om2.MFn.kMatrixAttribute:
        return om2.MFnMatrixData(plug.asMObject()).matrix()
        # NUMBERS
    elif apiType == om2.MFn.kNumericAttribute:
        pType = om2.MFnNumericAttribute(pAttribute).numericType()
        if pType == om2.MFnNumericData.kBoolean:
            return plug.asBool()
        elif pType in [om2.MFnNumericData.kShort, om2.MFnNumericData.kInt, om2.MFnNumericData.kLong,
                       om2.MFnNumericData.kByte]:
            return plug.asInt()
        elif pType in [om2.MFnNumericData.kFloat, om2.MFnNumericData.kDouble, om2.MFnNumericData.kAddr]:
            return plug.asDouble()
    # Enum
    elif apiType == om2.MFn.kEnumAttribute:
        return plug.asInt()

    return None

def _iterForSkinCluster(node):
    """
    :param node: MObject for the source connection
    :return: MObject
    """
    if node.apiType() == om2.MFn.kSkinClusterFilter:
        return om2.MObjectHandle(node)

    iterDg = om2.MItDependencyGraph(node,
                                    om2.MItDependencyGraph.kDownstream,
                                    om2.MItDependencyGraph.kPlugLevel)
    while not iterDg.isDone():
        currentItem = iterDg.currentNode() # use currentItem for 2017 and below
        if currentItem.hasFn(om2.MFn.kSkinClusterFilter):
            return om2.MObjectHandle(currentItem)

        iterDg.next()
def _findSkinCluster(mesh=None):
    """
    Returns a skinCluster attached to the kMesh or kNurbsCurve
    @:param mesh: MObjectHandle. Not the shape! Use the transform.
    :return: MObject
    """
    if not mesh.isValid():
        logger.warning("Destination is no longer valid!")
        return

    dagPath = om2.MDagPath()
    geo = dagPath.getAPathTo(mesh.object())

    ## Does it have a valid number of shapes?
    if geo.numberOfShapesDirectlyBelow() != 0:
        ## Fetch the shape of the geo now.
        shapeMobj = geo.extendToShape().node()
        mFn_shape = om2.MFnDependencyNode(shapeMobj)
        apiType = shapeMobj.apiType()
        if apiType == om2.MFn.kMesh:
            ## Look at the inMesh attr for the source
            inMesh_attr = mFn_shape.attribute('inMesh')
        elif apiType == om2.MFn.kNurbsCurve:
            inMesh_attr = mFn_shape.attribute('create')
        else:
            logger.warning("This type of om2.MFn node is not supported! int: {}".format(apiType))
            return

        inMesh_plug = om2.MPlug(shapeMobj, inMesh_attr)
        getSource = inMesh_plug.source().node()

        ## Now use the iterForSkinCluster() function to find the skinCluster in the connected network.
        skinClusterNode_MObjH = _iterForSkinCluster(getSource)

        if skinClusterNode_MObjH is not None:
            return skinClusterNode_MObjH
        else:
            return None

    return None

def _findInfluences(skinClusterMobjH=None):
    """
    Returns all the valid influences from the .matrix attribute on the skinCluster node.
    @:param mesh: MObjectHandle for the skinCluster. Using the handles here may be playing it a little too safe. But meh.
    :return: MObject
    """
    if not skinClusterMobjH.isValid():
        logger.warning("Skincluster is no longer valid! Did it get deleted?")
        return

    skClsMFnDep = om2.MFnDependencyNode(skinClusterMobjH.object())
    mtxAttr = skClsMFnDep.attribute("matrix")
    matrixPlug = om2.MPlug(skinClusterMobjH.object(), mtxAttr)

    ## Get a list of all the valid connected indices in the matrix array now.
    indices = matrixPlug.getExistingArrayAttributeIndices()
    influences = []
    for idx in indices:
        name = om2.MFnDependencyNode(matrixPlug.elementByLogicalIndex(idx).source().node()).absoluteName()
        influences.append(str(om2.MNamespace.stripNamespaceFromName(name)))

    return influences

def fileExists(filePath):
    if filePath is not None and os.path.isfile(filePath):
        logger.info("File exists!")
        return True

    return False

def writetoJSON(filePath, data):
    with open(filePath, 'w') as outfile:
        outfile.write(json.dumps(data))

    return True

def readFromJSON(filePath):
    with open(filePath) as infile:
        data = json.load(infile)
        return data

    return None

def _fetchSkinWeights(geoList=None, skipZeroWeights=True):
    """
    If you send in a list of geo, we'll use that. Else we assume we're working off selected.
    :param geoList: list() of string names for geometry to fetch data for
    :param skipZeroWeights: if you want to avoid saving all 0.0 weight data
    :return:
    """
    geo = om2.MSelectionList()
    if geoList is not None:
        for eachGeo in geoList:
            geo.add(eachGeo)
    else: #Assume selected
        for eachGeo in cmds.ls(sl=True):
            geo.add(eachGeo)

    weightData = {}
    for x in range(geo.length()):
        geoMObjH = om2.MObjectHandle(geo.getDependNode(x))
        geoName = om2.MFnDependencyNode(geoMObjH.object()).name()
        skinClusterMObjH = _findSkinCluster(geoMObjH)
        if skinClusterMObjH is None:
            logger.warning("Skipping {} has no skinCluster!".format(geoName))
            continue

        skName = str(om2.MFnDependencyNode(skinClusterMObjH.object()).name())

        influences = _findInfluences(skinClusterMObjH)
        ## Add the data to the dict
        weightData[geoName] = {}
        weightData[geoName][skName] = {}
        weightData[geoName][skName]['influences'] = influences
        weightData[geoName][skName]['maxInf'] = cmds.skinCluster(skName, q=True, maximumInfluences=True)
        weightData[geoName][skName]['weights'] = {}

        ## Fetch the weights now
        weightPlug = findPlugOnNode(skinClusterMObjH, 'weightList')
        weightCount = weightPlug.getExistingArrayAttributeIndices()
        for x in range(len(weightCount)):
            # .weightList[x]
            p = weightPlug.elementByLogicalIndex(weightCount[x])
            # .weights
            c = p.child(0)

            ## Now fetch the list of idx numbers that should relate to the inf [23, 66, 99]
            w = c.getExistingArrayAttributeIndices()

            ## For each idx we're going to build a tuple (idx, infName, weightVal)
            weightList = list()
            for i in range(len(w)):
                childPlug = c.elementByLogicalIndex(w[i])
                weightValue = getPlugValue(childPlug)

                if skipZeroWeights and weightValue == 0.0:
                    continue

                idx = w[i]
                weightList.append((idx, weightValue))

            weightData[geoName][skName]['weights'][str(x)] = weightList
            print("weightData["+str(geoName)+"]["+str(skName)+"][weights]["+str(x)+"]"+"= "+str(weightList))
    return weightData

weightData=_fetchSkinWeights(None,False)
#print("weightData= "+str(weightData))
_Weights=weightData[dupMesh][skincluster]["weights"][str(vert)]
print("_Weights= "+str(_Weights))


boneInt=0
        bones = pm.listConnections(str(skincluster) + ".matrix")
        boneslen=len(bones)
        for b in range(0,boneslen):
            bonename=bones[b]
            if influence in str(bonename):
                #print("found hit")
                boneInt=b


print("boneInt= "+str(boneInt))
weight=0
for _Weight in _Weights:
     #_Weight=(0, 0.8388942003250122)
     boneNum=_Weight[0]
     if(boneNum==boneInt):
           weight=_Weight[1]
print("weight= "+str(weight))

経過時間 = 00h:07m:10s om2なのに遅い。。。。
データ参照するためにfor分2個使うせいだな。
print消しても
経過時間 = 00h:04m:17s  おそい。。。

もっと早く取りたい

skincluster.getPointsAffectedByInfluence

インフルエンス骨基準で頂点のウェイトを問い合わせ回数を減らすことで早くなる。

getData = skincluster.getPointsAffectedByInfluence(InfluenceJoint)  

で取れるみたい。

詳しくはこちら。

https://www.marcuskrautwurst.com/2012/12/skinweights-savingloading-in-pymel.html


こんな感じで minidomに保存してそこからロードして使う。


import xml.dom.minidom as minidom

class SkinWeight_To_MiniDom():
    def getMeshVertex(self,objName):
        vtx = cmds.ls(objName+'.vtx[*]', fl=True)    
        return vtx
    def _showProgressDialog(self):
        self.WindowRef._showProgressDialog()#---------------------ProgressBar Starting--------------------------
        
    def setProgress(self,count):
        self.WindowRef.setProgress(count)

    def fnFindSkinCluster(self,mesh):
        skincluster = None
        for each in pm.listHistory(mesh):  
            if type(each)==pm.nodetypes.SkinCluster:   
                skincluster = each
        return skincluster
    def fnSaveSkinning(self,mesh,path): 
        print("SkinWeight_To_MiniDom---------fnSaveSkinning("+mesh+" path: "+path+")")
        # 次は、スキンウェイトの保存機能から始めましょう。
        ##skinClusterクラスには、influenceObjects()と呼ばれる関数があり、
        ##skinclusterにバインドされているすべてのジョイントを返します。
        ##次に、基本的に各ジョイントを反復処理し、各インフルエンスに対して関数getPointsAffectedByInfluence()を実行します。
        ##これにより、各頂点とその重みを含むリストが返されます。
        ##これらすべての値を適切なリストに保存し、minidomモジュールを利用してxmlファイルに保存できるようにします。
        
        ## データを収集します
        skincluster = self.fnFindSkinCluster(mesh)
     
        ## スキンクラスターが存在するかどうかを確認します
        if skincluster!=None:
            print(u"スキンクラスターがありました!")
            ## XMLxml_documentを準備します
            xml_doc = minidom.Document()
            xml_header = xml_doc.createElement("influences") 
            xml_doc.appendChild(xml_header)   

            ## ジョイントID/名前テーブルを書き出す  
            for each in skincluster.getInfluence():
                getData = skincluster.getPointsAffectedByInfluence(each)  
                tmpJoint= xml_doc.createElement(each)
                vertData = []
                if len(getData[0])>0:
                    ## すべての頂点IDを収集し、vertDataリストに保存します
                    for each in getData[0][0]:
                        vertData.append(each.currentItemIndex())
                    ## 次に、vertDataリストを「vertices」属性値として保存します
                    tmpJoint.setAttribute("vertices",str(vertData))
                    tmpJoint.setAttribute("weights",str(getData[1]))
                    xml_header.appendChild(tmpJoint)
         
            ## Save XML
            file = open(path, 'w')
            file.write(xml_doc.toprettyxml())
            pm.warning("Saved '%s.skinning' to '%s'"%(mesh,path))
        else:
            print(u"スキンクラスターがありません!")
            pm.warning('No skincluster connected to %s'%mesh)
 

    def fnLoadSkinning(self,mesh,path):  
        
        ##次に、いくつかの変数を使用して関数を設定し、メッシュがすでにスキンされている場合は、そのスキンクラスターを削除するようにします。
        ##後で新しいジョイントを作成し、スキンウェイトファイルに基づいてすべてのジョイントを自動的に追加します。
        
        ## 変数
        jointData = []
        skinData = []

        ### メッシュがすでにスキンされている場合は、メッシュをクリーンアップします
        skincluster = fnFindSkinCluster(mesh)
        if skincluster!=None:
            pm.runtime.DetachSkin(skincluster)
        
        ## 次に、xmlファイルを解析して、すべてのデータを整理しましょう。カスタムクラスcSkinningに基づいてオブジェクトを作成し、
        ## skinDataというリストに保存します。
        
        
        ## ドキュメントを解析し、XML形式に変換して、メモリにロードします
        xml_doc = minidom.parse(path)
        xml_doc.toxml()
         
        ## ルートノードを取得
        joints = xml_doc.childNodes[0].childNodes
    
        ## すべてのデータを収集し、cSkinningオブジェクトをskinDataリストに保存します
        for joint in joints:
            if joint.localName!=None:
                vertices = []
                weights = []
                jointData.append(joint.localName)   
                vertices = eval(joint.attributes.item(1).nodeValue)
                weights = eval(joint.attributes.item(0).nodeValue)
                skinData.append(cSkinning(vertices,joint.localName,weights))
        
        ##skinDataからアイテムをPrintすると、
        ##item.id、item.influence、またはitem.weightsを印刷すると、そのクラスに格納されているデータを確認できます。
        ##インフルエンスとウェイトはコヒーレントテーブルであるため、.weightsのインデックス15はインフルエンス15のウェイトを表すことがわかります。
        ##次に、スキンクラスターを作成し、すべてのジョイントを追加します。ウェイト属性を適用する前に、
        ##normalizeWeights属性を0に設定する必要があります。そうしないと、Mayaはウェイトを追加するたびにスキンウェイトを正規化します。
        ##また、skinPercentを使用してスキンをバインドする場合は、マヤの標準スキンウェイトを削除する必要があります。

        
        skincluster = pm.animation.skinCluster(mesh,jointData)
        skincluster.setNormalizeWeights(0)
        pm.skinPercent(skincluster, mesh, nrm=False, prw=100)
        
        ##ウェイトを適用する前に、最後に行う必要があることが1つあります。MayaはIDに基づいてWeightを保存します。新しいスキンクラスターを追加したため、
        ##これらのIDは古いIDと一致しなくなりました。ここでのこのコードは、skinDataリストでそれらを更新するだけです。
        
        tmpJoint = []
        for storedJoint in jointData:
            for skinnedJoint in skincluster.influenceObjects():
                if skinnedJoint==storedJoint:
                    tmpJoint.append(skincluster.indexForInfluenceObject(storedJoint))
             
        for each in range(0,len(skinData)):  
            skinData[each].influence = tmpJoint[each]
        
        ##素晴らしい、今ここに楽しい部分があります。setAttrを使用してスキンウェイトを追加しましょう。それが終わったら、スキンウェイトの正規化を再度オンにすることを忘れないでください。
        
        for each in range(0,len(skinData)):  
            for vertex in range(0,len(skinData[each].id)):
                vert = skinData[each].id[vertex]
                weights = skinData[each].weights[vertex]   
                pm.setAttr('%s.weightList[%s].weights[%s]'%(skincluster,vert,skinData[each].influence),weights)
                
        ##約30kの頂点を持つメッシュの場合、約3秒かかりました。かなり許容できる約6秒の読み込み。スクリプトはMaya2012でテストされ、
        ##Maya 2013でこれを機能させるのに問題があると聞きましたが、残念ながらまだ調査する時間がありませんでした。聞いてくれてありがとう。
        
        #--------------------------------------------------

class cSkinning(): 
    def __init__(self,id,infl,weights):
        
        ##これでデータを保存できますが、ロードすることもできます。これはもう少し苦痛であることが判明しました。
        ##skinPercentを使用すると、スキンウェイトの設定が非常に遅くなる可能性があります。したがって、この場合、 
        ##setAttrを使用して値を直接設定しました。これはかなり高速です。
        ##少しずつ見ていきましょう。まず、データを効率的に保存するためのクラスを設定します。
    
        self.id = id  
        self.influence = infl
        self.weights = weights



SkinWeight_To_MiniDomClass=SkinWeight_To_MiniDom()
BaseMesh="Mesh"
#cmds.select(BaseMesh)
SkinWeight_To_MiniDomClass.fnSaveSkinning(BaseMesh,"baseMesh_SkinWeight_"+BaseMesh+".txt")

SkinWeight Map export/import By FurcraeaTokyo Vol.02

SkinWeight Mapが画像じゃ精度がでないのでCSVにしたらうまくいった。

SkinWeight Map export

def GetSkinCluster(mesh):
	history = cmds.listHistory(mesh)
	for h in history:
		if cmds.objectType(h, isType='skinCluster'):
			return h
	return None
def GetSkinPercent(SkinCluster,vtx,mJoint):
    # vtx[100] の joint1 の weight を取得
    skinWeightV=cmds.skinPercent( SkinCluster, vtx, t= mJoint, query=True, value=True)
    return skinWeightV
    

def GetPolyCount(mesh):
	return cmds.polyEvaluate(mesh, v=True)
	

from PySide.QtCore import QByteArray, QBuffer, QIODevice, QFile
from PySide import QtGui



jointName="neckUpper|head"	
mesh="Design_model|Mesh|Face_Only_Beauty"
poly_count = GetPolyCount(mesh)
skin_cluster = GetSkinCluster(mesh)

imagePath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.png"


WeightArray=[]
for i in range(poly_count):
    vtx_attr_name = mesh + ".vtx[" + str(i) + "]"
    
    weightV=GetSkinPercent(skin_cluster,vtx_attr_name,jointName)
    WeightArray.append(weightV)


print("WeightArray="+str(WeightArray))
lenWeightArr=len(WeightArray)
print("lenWeightArr= "+str(lenWeightArr))

width=lenWeightArr
height=1
"""
#buffer = QImage(pageSize, QImage.Format_ARGB32)
buffer = QtGui.QImage(width,height,QtGui.QImage.Format_ARGB32_Premultiplied)
def setDrowPixels(MyImage,WeightArray,width,height):
    for x in range(0, width ):
        for y in range(0, height ):
            gValue=0
            if(y==0):
                gValue = WeightArray[x]   
            else:
                gValue = WeightArray[x*y]
            print("x= "+str(x)+" y= "+str(y)+" gValue= "+str(gValue))
            MyImage.setPixel( x, y, QtGui.QColor( gValue, gValue, gValue ).rgb() )
    return MyImage
buffer=setDrowPixels(buffer,WeightArray,width,height)
buffer.save(imagePath)
"""
CSVPath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.csv"
import codecs
fout = codecs.open(CSVPath, 'w', 'utf_8')
for i in range(poly_count):
    line = str(WeightArray[i])+","
    fout.write(line)

SkinWeight Map import

def GetSkinCluster(mesh):
	history = cmds.listHistory(mesh)
	for h in history:
		if cmds.objectType(h, isType='skinCluster'):
			return h
	return None
def GetSkinPercent(SkinCluster,vtx,mJoint):
    # vtx[100] の joint1 の weight を取得
    skinWeightV=cmds.skinPercent( SkinCluster, vtx, t= mJoint, query=True, value=True)
    return skinWeightV
    
def SetSkinPercent(SkinCluster,vtx,mJoint,skinWeightV):
    # vtx[100] の weight を. joint を指定して設定
    cmds.skinPercent( SkinCluster, vtx, transformValue=[(mJoint, skinWeightV)])
    

def GetPolyCount(mesh):
	return cmds.polyEvaluate(mesh, v=True)
	

from PySide.QtCore import QByteArray, QBuffer, QIODevice, QFile
from PySide import QtGui
"""
def image_to_array(imagePath):
    source = QtGui.QImage(imagePath)

    # バイナリとメタデータを読み込み
    #bits = source.constBits()
    width = source.width()
    height = source.height()
    print("width= "+str(width))
    print("height= "+str(height))
    '''
    return array of integer 0-255 rgba values
    [(r, g, b, a)]
    '''
    img = QtGui.QImage(width, height, QtGui.QImage.Format.Format_ARGB32)
    img.load(imagePath)
    colorArray = []
    kidoArray=[]
    for y in range(height):
        for x in range(width):
            color = QtGui.QColor()
            color.setRgba(img.pixel(x,y))
            colorArray.append(color.getRgb())
            kidoArray.append(color.getRgb()[0])
    return kidoArray
"""
def csv_to_array(CSVPath):
    import codecs
    fin  = codecs.open(CSVPath, 'r', 'utf_8')
    image_arr=[]
    for line in fin:
        #line=line.replace("\n","")
        #line=line.replace("\r","")
        #line=line.replace(',','')
        lineArr=line.split(',')
        for strV in lineArr:
            if(strV!=""):
                print("strV= "+strV)
                floatStrV=float(strV)
                image_arr.append(floatStrV)
    return image_arr
    
jointName="ALS_Mannequin|root|pelvis|spine_01|spine_02|spine_03|neck_01|head"	
mesh="ALS_Mannequin|Mesh|Face_Only_Beauty"
poly_count = GetPolyCount(mesh)
skin_cluster = GetSkinCluster(mesh)

#imagePath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.png"
CSVPath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.csv"


#image_arr=image_to_array(imagePath)
image_arr = csv_to_array(CSVPath)
print("image_arr= "+str(image_arr))


ArrLeng=len(image_arr)
for i in range(ArrLeng):
    vtx_attr_name = mesh + ".vtx[" + str(i) + "]"
    weightV=image_arr[i]
    #SetSkinPercent(skin_cluster,vtx_attr_name,jointName,1)
    SetSkinPercent(skin_cluster,vtx_attr_name,jointName,weightV)

元がこう

結果がこれ

ふーばっちりうまくいった様子。やったね!

SkinWeight Map export/import By FurcraeaTokyo

Maya2016でSkinWhight Mapのインポートが壊れているので

SkinWeight Mapのエクスポートとインポートを自作してみた。ほんとテスト段階

SkinWeight Map export

def GetSkinCluster(mesh):
	history = cmds.listHistory(mesh)
	for h in history:
		if cmds.objectType(h, isType='skinCluster'):
			return h
	return None
def GetSkinPercent(SkinCluster,vtx,mJoint):
    # vtx[100] の joint1 の weight を取得
    skinWeightV=cmds.skinPercent( SkinCluster, vtx, t= mJoint, query=True, value=True)
    return skinWeightV
    

def GetPolyCount(mesh):
	return cmds.polyEvaluate(mesh, v=True)
	

from PySide.QtCore import QByteArray, QBuffer, QIODevice, QFile
from PySide import QtGui



jointName="neckUpper|head"	
mesh="Design_model|Mesh|Face_Only_Beauty"
poly_count = GetPolyCount(mesh)
skin_cluster = GetSkinCluster(mesh)

imagePath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.png"


WeightArray=[]
for i in range(poly_count):
    vtx_attr_name = mesh + ".vtx[" + str(i) + "]"
    weightV=image_arr[i]

    weightV=GetSkinPercent(skin_cluster,vtx_attr_name,jointName)
    WeightArray.append(weightV)


print("WeightArray="+str(WeightArray))
lenWeightArr=len(WeightArray)
print("lenWeightArr= "+str(lenWeightArr))

width=lenWeightArr
height=1

#buffer = QImage(pageSize, QImage.Format_ARGB32)
buffer = QtGui.QImage(width,height,QtGui.QImage.Format_ARGB32_Premultiplied)
def setDrowPixels(MyImage,WeightArray,width,height):
    for x in range(0, width ):
        for y in range(0, height ):
            gValue=0
            if(y==0):
                gValue = WeightArray[x]   
            else:
                gValue = WeightArray[x*y]
            print("x= "+str(x)+" y= "+str(y)+" gValue= "+str(gValue))
            MyImage.setPixel( x, y, QtGui.QColor( gValue, gValue, gValue ).rgb() )
    return MyImage
buffer=setDrowPixels(buffer,WeightArray,width,height)
buffer.save(imagePath)

skinWeight Map import

def GetSkinCluster(mesh):
	history = cmds.listHistory(mesh)
	for h in history:
		if cmds.objectType(h, isType='skinCluster'):
			return h
	return None
def GetSkinPercent(SkinCluster,vtx,mJoint):
    # vtx[100] の joint1 の weight を取得
    skinWeightV=cmds.skinPercent( SkinCluster, vtx, t= mJoint, query=True, value=True)
    return skinWeightV
    
def SetSkinPercent(SkinCluster,vtx,mJoint,skinWeightV):
    # vtx[100] の weight を. joint を指定して設定
    cmds.skinPercent( SkinCluster, vtx, transformValue=[(mJoint, skinWeightV)])
    

def GetPolyCount(mesh):
	return cmds.polyEvaluate(mesh, v=True)
	

from PySide.QtCore import QByteArray, QBuffer, QIODevice, QFile
from PySide import QtGui

def image_to_array(imagePath):
    source = QtGui.QImage(imagePath)

    # バイナリとメタデータを読み込み
    #bits = source.constBits()
    width = source.width()
    height = source.height()
    print("width= "+str(width))
    print("height= "+str(height))
    '''
    return array of integer 0-255 rgba values
    [(r, g, b, a)]
    '''
    img = QtGui.QImage(width, height, QtGui.QImage.Format.Format_ARGB32)
    img.load(imagePath)
    colorArray = []
    kidoArray=[]
    for y in range(height):
        for x in range(width):
            color = QtGui.QColor()
            color.setRgba(img.pixel(x,y))
            colorArray.append(color.getRgb())
            kidoArray.append(color.getRgb()[0])
    return kidoArray

jointName="ALS_Mannequin|root|pelvis|spine_01|spine_02|spine_03|neck_01|head"	
mesh="ALS_Mannequin|Mesh|Face_Only_Beauty"
poly_count = GetPolyCount(mesh)
skin_cluster = GetSkinCluster(mesh)

imagePath="C:/Download/Game/AdvansedLocoMotionSystem/AnimMan/SkinWeight_neck01_to_Head/SkinWeight_002simple/render.png"

image_arr=image_to_array(imagePath)
print("image_arr= "+str(image_arr))



for i in range(poly_count):
    vtx_attr_name = mesh + ".vtx[" + str(i) + "]"
    weightV=image_arr[i]
    #SetSkinPercent(skin_cluster,vtx_attr_name,jointName,1)
    SetSkinPercent(skin_cluster,vtx_attr_name,jointName,weightV)

元がこれ

結果がこれ  値が飛んじゃってる気がする。 CSVとかのほうがいいかも

なんだかスムージング処理がいるのかもしれない。

■参考にさせてもらった記事

Maya python で, 特定の mesh 頂点の 特定の joint の skin weight の値を取得, 設定する – Qiita

https://qiita.com/syoyo/items/5252ac7244b4f40b2cac

Python API 2.0 MImage

https://forums.autodesk.com/t5/maya-programming/python-api-2-0-mimage/td-p/6340749

Python QImage.fill Examples

https://python.hotexamples.com/examples/PySide.QtGui/QImage/fill/python-qimage-fill-method-examples.html

Add Twist Joint Auto -ツイストジョイントの追加を自動化したよ-

このビデオの腕のツイストジョイントの追加を自動化したよ
腕を回転させれば肘ジョイントが伸びスキニングした際に肘が丸くなるのを防ぎます
import maya.cmds as cmds
import pymel.core as pm
import os
class TwistJointClass:


    def MainWay(self):
        
        self.Selected_Joint_Check()
        
    def Selected_Joint_Check(self):
        # need elbowJoint select
        selected = cmds.ls(sl=True,long=True)
        print("01 selected= "+str(selected))
        if(str(selected)=="[]"):
            print("Need Select Elbow Joint!!!!!!!!!!!!!!!!!!")
        else:
            self.elbowJoint_to_twistjoint(selected)
            
            self.elbowJoint_to_drivenkey(selected)
        
    def elbowJoint_to_drivenkey(self,selected):
        elbow_joint_full=selected[0]
        print("02 elbow_joint_full= "+str(elbow_joint_full))
        
        self.select_fullname(elbow_joint_full)
        
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_togeJointName = self.make_elbow_toge_joint(elbow_joint_full)
        
        elbow_mode="Genesis8"
        if(elbow_mode=="Genesis8"):
            elbow_way_rz=".ry"# my model
        else:
            elbow_way_rz=".rz"# tutorial
        print("elbow_way_rz= "+elbow_way_rz)

        
        # Key Value 1
        
        destArr=elbow_joint_name+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        
        
        
        
        destArr=elbow_joint_togeJointName+".tx"
        cmds.setAttr( destArr, 0 )    

        destArr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        
        # Set DrivenKey
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.translateX;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+'.tx'
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.rotateZ;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        # Key Value 2
        SideWay=self.check_Left_Or_Right(elbow_joint_name)
        print("64 SideWay= "+SideWay)
        if(SideWay=="R"):
            destArr=elbow_joint_name+elbow_way_rz
            cmds.setAttr( destArr, 180 )
            
            #setAttr "lowerarm_toge_r.translateX" 4;
            destArr=elbow_joint_togeJointName+".tx"
            cmds.setAttr( destArr, 4 )
            
        if(SideWay=="L"):
            destArr=elbow_joint_name+elbow_way_rz
            cmds.setAttr( destArr, -180 )
            
            #setAttr "lowerarm_toge_r.translateX" 4;
            destArr=elbow_joint_togeJointName+".tx"
            cmds.setAttr( destArr, -4 )
        #setAttr "lowerarm_toge_r.rotateZ" 90;
        #destArr=elbow_joint_togeJointName+elbow_way_rz
        #cmds.setAttr( destArr, 90 )
        
        # Set DrivenKey
        
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.translateX;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+'.tx'
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        #setDrivenKeyframe -currentDriver lowerarm_r.rotateZ lowerarm_toge_r.rotateZ;
        fromAttr=elbow_joint_name+elbow_way_rz
        DestAttr=elbow_joint_togeJointName+elbow_way_rz
        cmds.setDrivenKeyframe( DestAttr, currentDriver= fromAttr)
        
        # reset joint rz
        
        destArr=elbow_joint_name+elbow_way_rz
        cmds.setAttr( destArr, 0 )
        

        
    def check_Left_Or_Right(self,elbow_joint_name):
        SideWay=""
        jointName_arr=elbow_joint_name.split("_")
        if(jointName_arr[0].lower()=="left"):
            SideWay="L"
        if(jointName_arr[0].lower()=="l"):
            SideWay="L"    
        if(jointName_arr[1].lower()=="left"):
            SideWay="L"
        if(jointName_arr[1].lower()=="l"):
            SideWay="L" 
        if(jointName_arr[0].lower()=="right"):
            SideWay="R"
        if(jointName_arr[0].lower()=="r"):
            SideWay="R"    
        if(jointName_arr[1].lower()=="right"):
            SideWay="R"
        if(jointName_arr[1].lower()=="r"):
            SideWay="R"     
        print("SideWay= "+SideWay)
        return SideWay
    def make_elbow_toge_joint(self,elbow_joint_full):
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_togeJointName=self.makeName_togejoint(elbow_joint_name)
        
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        print("elbow_pos=" +str(elbow_pos))
        jointName2=cmds.joint( p=(elbow_pos[0], elbow_pos[1], elbow_pos[2]-3) ,absolute=True)
        cmds.rename(jointName2,elbow_joint_togeJointName);
        #cmds.parent( elbow_joint_togeJointName, elbow_joint_full )
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        return elbow_joint_togeJointName
        
    def elbowJoint_to_twistjoint(self,selected):
        elbow_joint_full=selected[0]
        print("02 elbow_joint_full= "+str(elbow_joint_full))
        
        hand_joint_full=self.get_one_child_node(elbow_joint_full)
        print("03 hand_joint_full= "+str(hand_joint_full))
        
        upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        upperarm_joint_full=upperarm_joint_arr[0]
        print("04 upperarm_joint_full= "+str(upperarm_joint_full))

        #shoulder_joint_arr = cmds.listRelatives(str(upperarm_joint_full),parent=True,fullPath=True)
        #shoulder_joint_full= shoulder_joint_arr[0]
        #print("05 shoulder_joint_full= "+str(shoulder_joint_full))

        self.Elbow_Func(hand_joint_full,elbow_joint_full)
        
        self.Hand_Func(hand_joint_full,elbow_joint_full)
        #---------------------------------------------------------------------------------------
        #---------------------------------  upperarm_joint_full  -------------------------------
        #---------------------------------------------------------------------------------------
        self.UpperArm_Func(elbow_joint_full,upperarm_joint_full)
        
        self.Shoulder_Func(upperarm_joint_full)
            
    def Hand_Func(self,hand_joint_full,elbow_joint_full):
        hand_joint_name =self.get_fullname_to_name(hand_joint_full)
        hand_joint_twistJointName=self.makeName_twistjoint(hand_joint_name)
        
        
        hand_pos=cmds.xform(hand_joint_full,q=1,ws=1,rp=1)
        print("hand_pos=" +str(hand_pos))
        jointName2=cmds.joint( p=(hand_pos[0], hand_pos[1], hand_pos[2]) ,absolute=True)
        cmds.rename(jointName2,hand_joint_twistJointName);
        cmds.parent( hand_joint_twistJointName, elbow_joint_full )
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        # -------------Hand CONNECT -----------------------------------------------------
        fromAtt=hand_joint_name+".rotateX"
        destArr=hand_joint_twistJointName+".rotateX"
        cmds.connectAttr( fromAtt, destArr )
        #--------------------------------------------------------------------------------
        
    def Elbow_Func(self,hand_joint_full,elbow_joint_full):
        # make joint
        elbow_joint_name =self.get_fullname_to_name(elbow_joint_full)
        elbow_joint_twistJointName=self.makeName_twistjoint(elbow_joint_name)
        
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        hand_pos=cmds.xform(hand_joint_full,q=1,ws=1,rp=1)
        print("elbow_pos=" +str(elbow_pos))
        print("hand_pos=" +str(hand_pos))
        
        average_x=(elbow_pos[0]+hand_pos[0])/2
        average_y=(elbow_pos[1]+hand_pos[1])/2
        average_z=(elbow_pos[2]+hand_pos[2])/2
        
        jointName=cmds.joint( p=(average_x, average_y, average_z) ,absolute=True)
        cmds.rename(jointName,elbow_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #cmds.joint( elbow_joint_twistJointName, e=True,position=(0, 0, 0) )
    
    
        #-----------------elbow divide --------------------------------------------------
        # 1 
        DivideName=elbow_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName)
        
        fromAtt=hand_joint_full+".rotateX"
        destArr=DivideName+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2 
        fromAtt=DivideName+".outputX"
        destArr=elbow_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3 ------------- setAttr --------------------------
        destArr=DivideName+".input2X"
        self.setAttr_FullPath( destArr, 0.5 )
        
        
    def UpperArm_Func(self,elbow_joint_full,upperarm_joint_full):
        #upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        #upperarm_joint_full=upperarm_joint_arr[0]
        self.select_fullname(upperarm_joint_full)
        
        # make joint -----------------------------------------
        upperarm_joint_name =self.get_fullname_to_name(upperarm_joint_full)
        upperarm_joint_twistJointName=self.makeName_twistjoint(upperarm_joint_name)
        
        upperarm_pos=cmds.xform(upperarm_joint_full,q=1,ws=1,rp=1)
        elbow_pos=cmds.xform(elbow_joint_full,q=1,ws=1,rp=1)
        print("upperarm_pos=" +str(upperarm_pos))
        print("elbow_pos=" +str(elbow_pos))
        
        average_x=(elbow_pos[0]+upperarm_pos[0])/2
        average_y=(elbow_pos[1]+upperarm_pos[1])/2
        average_z=(elbow_pos[2]+upperarm_pos[2])/2
        
        jointName=cmds.joint( p=(average_x, average_y, average_z) ,absolute=True)
        cmds.rename(jointName,upperarm_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #-----------------Upperarm divide2 --------------------------
        #hand_joint_name=fullName_to_ShortName(hand_joint_full)
        DivideName2=upperarm_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName2)
        # 1  
        fromAtt=upperarm_joint_name+".rotateX"
        destArr=DivideName2+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2  
        fromAtt=DivideName2+".outputX"
        destArr=upperarm_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3  ------------- setAttr --------------------------
        destArr=DivideName2+".input2X"
        self.setAttr_FullPath( destArr, -0.5 )
        #-----------------Upperarm divide2 --------------------------END
        
    def Shoulder_Func(self,upperarm_joint_full):
        #upperarm_joint_arr = cmds.listRelatives(str(elbow_joint_full),parent=True,fullPath=True)
        #upperarm_joint_full=upperarm_joint_arr[0]
        self.select_fullname(upperarm_joint_full)
        
        # make joint -----------------------------------------
        upperarm_joint_name =self.get_fullname_to_name(upperarm_joint_full)
        shoulder_joint_twistJointName=self.makeName_twistjoint("shoulder_"+upperarm_joint_name)
        
        upperarm_pos=cmds.xform(upperarm_joint_full,q=1,ws=1,rp=1)
        print("upperarm_pos=" +str(upperarm_pos))
        
        jointName=cmds.joint( p=(upperarm_pos[0], upperarm_pos[1], upperarm_pos[2]) ,absolute=True)
        cmds.rename(jointName,shoulder_joint_twistJointName);
        #makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 -pn 1;
        cmds.makeIdentity( apply=True, t=1, r=1, s=1, n=0,pn=1,jointOrient=1)
        
        #-----------------Upperarm divide3 --------------------------
        #hand_joint_name=fullName_to_ShortName(hand_joint_full)
        DivideName3="shoulder_"+upperarm_joint_name+"_Divide"
        cmds.shadingNode('multiplyDivide', asUtility=True, name=DivideName3)
        # 1  
        fromAtt=upperarm_joint_name+".rotateX"
        destArr=DivideName3+".input1X"
        self.connectAttr_FullPath( fromAtt, destArr )
        # ------------- CONNECT ----------
        # 2  
        fromAtt=DivideName3+".outputX"
        destArr=shoulder_joint_twistJointName+".rotateX"
        self.connectAttr_FullPath( fromAtt, destArr )
        # 3  ------------- setAttr --------------------------
        destArr=DivideName3+".input2X"
        self.setAttr_FullPath( destArr, -1 )
        #-----------------Upperarm divide2 --------------------------END
        
    def select_fullname(self,fullname):
        import sys
        
        try:
            cmds.select( fullname)
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise

    def setAttr_FullPath(self, destArr ,value):
        import sys
        
        try:
            cmds.setAttr( destArr, value )
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise

    def fullName_to_ShortName(fullName):
        shortName=""
        fullName_index=fullName.find("|")
        if(fullName_index==-1):
            pass
        else:
            fullName_Arr=fullName.split("|")
            fullName_Len=len(fullName_Arr)
            shortName = fullName_Arr[fullName_Len-1]
            print("shortName= "+shortName)
        return shortName

    def connectAttr_FullPath(self, fromAtt, destArr ):
        import sys

        try:
            cmds.connectAttr( fromAtt, destArr )
        except OSError as err:
            print("OS error: {0}".format(err))
        except ValueError:
            print("Could not convert data to an integer.")
        except:
            print("Unexpected error:", sys.exc_info()[0])
            #raise
        
        
    def get_one_child_node(self,elbow_joint_full):
        hand_joint_full=""
        
        hand_joint_arr = cmds.listRelatives(str(elbow_joint_full),children=True,fullPath=True)
        
        print("02 hand_joint_arr= "+str(hand_joint_arr))
        temp_child_name=hand_joint_arr[0]
        elbow_arr=elbow_joint_full.split("|")
        elbow_len=len(elbow_arr)-1
        elbow_last=elbow_arr[elbow_len]
        print("elbow_last= "+elbow_last)
        temp_arr=temp_child_name.split("|")
        temp_len=len(temp_arr)-1
        temp_elbowlastlen_name=temp_arr[elbow_len]
        temp_elbowlastlen_plusone_name=temp_arr[elbow_len+1]
        print("temp_elbowlastlen_name= "+temp_elbowlastlen_name)
        if(elbow_last==temp_elbowlastlen_name):
            print("same OK temp_elbowlastlen_name= "+temp_elbowlastlen_name)
            print("temp_elbowlastlen_plusone_name= "+temp_elbowlastlen_plusone_name)
            
            #for jname in temp_arr
            buildStr=""
            #for(int i = 0; i < elbow_len+1; i++)
            for i in range(1,elbow_len+1+1):
                jname = temp_arr[i]
                buildStr=buildStr+"|"+jname
            print("buildStr= "+buildStr)
            hand_joint_full=buildStr
        return hand_joint_full
            
    def handJoint_to_twistjoint(self):
        # need hand select
        selected = cmds.ls(sl=True,long=True)
        
        print("01 selected= "+str(selected))
        hand_joint_full=selected[0]
        
        print("02 hand_joint_full= "+str(hand_joint_full))
        """
        hiji_joint_arr = cmds.listRelatives(str(hand_joint_full),parent=True,fullPath=True)
        hiji_joint_full=hiji_joint_arr[0]
        print("03 hiji_joint_full= "+str(hiji_joint_full))
        """
        #hand_joint_name =self.get_fullname_to_name(hand_joint_full)
        #hiji_joint_name =self.get_fullname_to_name(hiji_joint_full)
        
        
        #hiji_twistJointName=self.makeName_twistjoint(hiji_joint_name)
        
        #cmds.select(hiji_joint_full)
        #cmds.insertJoint( 'joint2' )
        
        #あとで復帰
        #cmds.select(selected)
        #cmds.select(hand_joint_full)
        
        
    def makeName_twistjoint(self,joint_name):
        
        joint_name_arr=  joint_name.split("_")
        twistJointName=joint_name_arr[0]+"_twist_"+joint_name_arr[1]
        print("twistJointName= "+twistJointName)
        return twistJointName
        
    def makeName_togejoint(self,joint_name):
        
        joint_name_arr=  joint_name.split("_")
        togeJointName=joint_name_arr[0]+"_toge_"+joint_name_arr[1]
        print("togeJointName= "+togeJointName)
        return togeJointName
     
    def get_fullname_to_name(self,fullname):
        hand_joint_full_arr=fullname.split("|")
        print("04 hand_joint_full_arr= "+str(hand_joint_full_arr))
        hand_joint_full_len=len(hand_joint_full_arr)
        hand_joint_jointName=hand_joint_full_arr[hand_joint_full_len-1]
        print("05 hand_joint_jointName= "+str(hand_joint_jointName))
        return hand_joint_jointName

ClassIns= TwistJointClass()
ClassIns.MainWay()

だめなスキンバインド設定とマシなスキンバインド設定

デフォルトがかなりダメ

・複数のバインドポーズはエラーの元なのでオフ

・最大インフルエンス数が5は多すぎ3でいい。

・最大インフルエンス数の保持は 無駄にインフルエンスジョイントに影響するのでオフ

・スケルトンのカラー化 無駄いらない オフ

・作成時に非表示の選択項目を含める 非表示のメッシュもバインドしたいので オン

参考URL

http://3dcgr2lab.com/2019/11/30/easy-skin-weight-paint-tool/

スキンウェイトからなくなってるインフルエンスジョイントの追加方法

スキンウェイト 全く抜け落ちた インフルエンスの追加方法

インフルエンス オブジェクトを追加するには
0,バインドポーズにします

2,オブジェクトが作用するスキン メッシュを選択します。
3,インフルエンスジョイントをCtrl押しながら追加選択します。
4,スキン > 影響を編集 > インフルエンスの追加(Skin > Edit Influences > Add Influences) > □ を選択します。

5,インフルエンスの追加オプション(Add Influence options)設定で、
  ウェイトのロッキング:オン にします。
6,適用をクリックします。

7,スキンウェイトペイントツールのインフルエンスの欄に追加されます。

8、ロックを解除してスキンウェイトペイントします。

追加したインフルエンスにウェイトをペイントするとモデルが壊れる

バインド ポーズ以外でスムーズ スキンしたジオメトリにインフルエンス オブジェクトを追加すると、バインド ポーズに戻ったときにわずかに異なるスキン結果となります。たとえば、バインド ポーズでないジオメトリにインフルエンス オブジェクトを追加すると、その領域のウェイト値の再配分によってインフルエンス オブジェクトの配置場所で変形が生じることがあります

https://knowledge.autodesk.com/ja/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2016/JPN/Maya/files/GUID-1BEC5727-E97F-40A1-9F26-1B1E6A4E8848-htm.html

より。

スキン>バインドポーズにしてみたらずれてた
バインドポーズにしてからやり直したら大丈夫だった。