maya-rigging-skinning-problem 2

maya-rigging-skinning-problem 2

Anonymous
Not applicable
2,448 Views
18 Replies
Message 1 of 19

maya-rigging-skinning-problem 2

Anonymous
Not applicable

@cheng_xi_li

 

I had a problem with exporting and skinning a rigged mesh 2 months ago and Li helped me with my problem. here's the original post

https://forums.autodesk.com/t5/maya-programming/maya-rigging-skinning-problem/td-p/7126289

 

My rigged mesh export pipeline has been working fine since.

However, I recently had problem with exporting and rendering a rigged mesh and I still can't figure out what's the problem.

I have attached the maya scene with the mesh in this post

 

I can't seem to perform skinning on this mesh properly. The problem appears to be with the thigh bone.

If you run code for the command I created in the previous post, on vertex 497 on frame 1 of the animation, you will find that the skinned vertex world position is totally wrong. My skinning code has been working fine for other models but I'm not sure what I'm missing out with this.

 

CheckSkinnedVertex 497 1;
// Selected mesh: |Bottoms|BottomsShape //
//     BottomsShape is a riggedMesh, skin cluster name: skinCluster5 //
//     original mesh: |Bottoms|BottomsShapeOrig1 //
//     Checking original mesh: BottomsShapeOrig1, vertexID: 497, frameIdx: 1 //
//                Bind Pose Local Space Point: 35.274235, 140.669479, -1.059694 //
//                Bind Pose World Space Point: 35.274235, 140.669479, -1.059694 //
//     Calculated Bind Pose World Space Point: 35.274235, 140.669479, -1.059694 //
//     Num joint influence   : 14 //
//     Num weights for vertex: 28700 //
//     Num joints for vertex : 14 //
//    Valid joint idx: 0, name: mixamorig_Hips, weight: 0.0106997, bind pose list name: mixamorig_Hips //
//    Valid joint idx: 1, name: mixamorig_Spine, weight: 0.00154575, bind pose list name: mixamorig_Spine //
//    Valid joint idx: 4, name: mixamorig_LeftUpLeg, weight: 0.96815, bind pose list name: mixamorig_LeftUpLeg //
//    Valid joint idx: 7, name: mixamorig_LeftLeg, weight: 0.0196045, bind pose list name: mixamorig_LeftLeg //
//    Valid joint idx: 8, name: mixamorig_LeftFoot, weight: 1.74396e-008, bind pose list name: mixamorig_LeftFoot //
//                Frame Local Space Point: 51.799335, 123.358627, 91.601463 //
//                Frame World Space Point: 51.799335, 123.358627, 91.601463 //
//     Calculated Frame World Space Point: 40.697622, 61.462135, 46.450646 //

 

Regards

Alvin

0 Likes
Accepted solutions (1)
2,449 Views
18 Replies
Replies (18)
Message 2 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Does the code remain same? If it doesn't, please send an update version to me. I'll do some research next week.

 

Yours,

Li

0 Likes
Message 3 of 19

Anonymous
Not applicable

Thanks for replying. The code is the same. I don't know what is the difference between this model and those that worked.

It would be great if you can find out. Thanks!

 

Alvin

0 Likes
Message 4 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I've checked your code again and I think there are several mistakes in your previous code.

 

LBS should be inner product of skincluster.bindPreMatrix[]*joint.world.

 

So the code should be like below

 

MFnSkinCluster skinClusterFn(skinClusterObj);
auto bindPreMatrix = skinClusterFn.findPlug("bindPreMatrix");
...

for (unsigned int i = 0; i < numJoints; ++i)
{
...
	auto bindPosePlug = bindPreMatrix.elementByLogicalIndex(i);
...
}

for (unsigned int i = 0; i < numJointInfluences; ++i)
{
...
      auto left = jointsBindPoseWorld[i].bindPoseWorldTransMat.asMatrix();
      auto right = jointDags[i].inclusiveMatrix();
      MMatrix newMat;
      newMat.setToProduct(left, right);
...
}

It should be working for you in most of the scenarios.

 

BTW: The other factors may contribute to the results are transform on the vertices, envelope etc...

 

Yours,

Li

0 Likes
Message 5 of 19

Anonymous
Not applicable

That seems to do the trick. Thanks for your help.

 

Can you explain what is the relationship between the bindPreMatrix on the skinCluster and the bindPose on the joint node.

Is the bindPreMatrix the same for the same joint but on different skinCluster?

How do you get the bindPreMatrix given the joint node?

 

The reason I'm asking is because I have a mesh with multiple skin cluster sharing the same skeleton.

0 Likes
Message 6 of 19

Anonymous
Not applicable

Another question,

 

the bindPreMatrix should be set to the inverse world matrix of the joint. However, in the model is it not the same.

 

What is the reason they could be different and how can I know what causes the changes and what can I do to either

  1. reset the bindPreMatrix to the inverseWorldMatrix of the joint
  2. or calculate the bindPreMatrix given a joint
0 Likes
Message 7 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

According to the Skinning document:

 

The dagPose node stores the worldMatrix for all of the influences at the time of the bind. It also stores the local matrix as a full transformation matrix (MTransformationMatrix), and stores the parenting information. Only the worldMatrix is used by the skinning algorithm and is contained in the skinCluster node of the bindPreMatrix attribute. The bindPreMatrix is a multi-attribute that correlates its multi-index to the related influence object.

 

For joints only, the bindMatrix is also stored in the bindPose attribute. The joint has some other bind-related attributes, but they are obsolete in Maya 4.0 and remain only for backward compatibility.

 

 

You should be able to get influencedObjects by MFnSkinCluster::influenceObjects and the bindPreMatrix is related to it according to its index.

 

Yours,

Li

0 Likes
Message 8 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I am not sure about what you means here:

 

the bindPreMatrix should be set to the inverse world matrix of the joint. However, in the model is it not the same.

 

According to document, it is not inverse world matrix of the joint.

 

bindPreMatrix (pm) matrix arrayoutputinputconnectablestorable
 

The inclusive matrix inverse of the driving transform at the time of bind

 

Yours,
Li

0 Likes
Message 9 of 19

Anonymous
Not applicable

according to the docs

 

Untitled.png

 

the matrix array is the driving driving transforms array and the

worldMatrix attribute of a jointNode is connected to the matrix attribute on the skinCluster

 

 

0 Likes
Message 10 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

It should be bind influence inverse matrix and it will be updated when bindings are updated.

 

Yours,

Li

0 Likes
Message 11 of 19

Anonymous
Not applicable

How  then is the bind influence inverse matrix calculated from the joint/influence before being updated on the skinCluster?

0 Likes
Message 12 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I don't have document about it right now. I have to ask the engineers about it.

 

According to the code, my guess it could be connected or set by users or Maya.

 

Yours,

Li

0 Likes
Message 13 of 19

Anonymous
Not applicable

yeah I would like to know how it gets passed from Joint to SkinCluster before becoming the bindPreMatrix. What is the formula to do that and what users can do to to set it up and is there any special cases?

 

it would be good if you can check with the engineers and let me know. Thanks!

0 Likes
Message 14 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Well, for the LBS formula, it won't be changed. 

 

It is based on the code how Maya calculates the positon without transform on vertices and envelope.

 

I think the question is how bindPreMatrix is set in Maya here...

 

Yours,

Li

 

0 Likes
Message 15 of 19

Anonymous
Not applicable

Ya that's what I want to find out. How the bindPreMatrix is set.

0 Likes
Message 16 of 19

cheng_xi_li
Autodesk Support
Autodesk Support
Accepted solution

Hi,

 

You were right about bindPreMatrix, it should be same as the inverseWorldMatrix. I've checked code again to confirm it.

 

About the scene you've uploaded, our engineer thinks the dagPose might be corrupted. He believes that somehow dagPose (ls -type dagPose) got modified and doesn't match the actual binding pose because gotobind pose the leg remains sitting.

 

If you run the script below to restore the matrix from bindPreMatrix from the skinCluster, you'll find the people is standing.

 

import maya.cmds as cmds
import maya.api.OpenMaya as om
#import numpy as np

def extractBindPose(deformerName):
    bindPose = dict()
    
    storedInfluences = cmds.skinCluster(deformerName, q=True, inf=True)
    for i in range(len(storedInfluences)):
        storedname = storedInfluences[i]
        bindPose[storedname] = cmds.getAttr('{0}.bindPreMatrix[{1}]'.format(deformerName, i))
    
    return bindPose
    

cmds.select( 'mixamorig_Hips', hi=True )

#you must set world matrix following hierarchy order
orderedHierarchy = cmds.ls(sl=True)

skinClusterBindPose = extractBindPose('skinCluster5')
for jointName in orderedHierarchy:
    if jointName not in skinClusterBindPose:
        continue
    cmds.select(jointName)
    invMat = skinClusterBindPose[jointName]
    mm = om.MMatrix([[invMat[0],invMat[1],invMat[2],invMat[3]],
                     [invMat[4],invMat[5],invMat[6],invMat[7]],
                     [invMat[8],invMat[9],invMat[10],invMat[11]],
                     [invMat[12],invMat[13],invMat[14],invMat[15]]])
    mm = mm.inverse()
    print mm
    """m = np.matrix( [[invMat[0],invMat[1],invMat[2],invMat[3]],
                    [invMat[4],invMat[5],invMat[6],invMat[7]],
                    [invMat[8],invMat[9],invMat[10],invMat[11]],
                    [invMat[12],invMat[13],invMat[14],invMat[15]] ] )"""
    #print m.I.A1
    cmds.xform(ws=True, matrix=mm)

for member in cmds.dagPose( 'bindPose1', query=True, members=True ):
    cmds.dagPose( member, reset=True, n='bindPose1' ) 

So, it could be somehow the bindPose is incorrect in this scene, according to the document of dagPose:

 

...Each hierarchy can have only a single bindPose, which is saved automatically at the time of a skin bind. The bindPose is used when adding influence objects, binding new skins, or adding flexors. Take care when modifying the bindPose with the -rs/-reset or -rm/-remove flags, since if the bindPose is ill-defined it can cause problems with subsequent skinning operations.

 

Yours,

Li

 

0 Likes
Message 17 of 19

Anonymous
Not applicable

Thanks for the detailed explanation.

 

Is there any way in the API to check whether the dagPose node is different from the actual binding pose?

 

Or do I have to check the joint's .bindPose attribute against the skinCluster's .bindPreMatrix attribute to ensure one is the inverse of the other?

0 Likes
Message 18 of 19

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I think there isn't any APIs for this and you need to check it by yourself(.bindPose/.bindPreMatrix)

 

Yours,

Li

0 Likes
Message 19 of 19

Anonymous
Not applicable

Thanks for all your help, Li!

0 Likes