Maya rigging / skinning problem

Maya rigging / skinning problem

Anonymous
Not applicable
1,681 Views
9 Replies
Message 1 of 10

Maya rigging / skinning problem

Anonymous
Not applicable

Hi,

 

I have a maya model attached in this post that I am trying to export.

 

I have my own rigged mesh representation.

In that, I export the

  • bind pose world matrices for each joint (from the bindPose attribute on a joint node)
  • the bind pose world vertex positions of the mesh
  • the joint world matrices of each joint (using the inclusiveMatrix()) for each animation frame (all keyed on translation/rotation/scale)
  • and the respective weights and joint indices for each vertex

 

I then perform skinning for frame i by doing:

skinned world vertex = (0, 0, 0)

skinned world vertex += (bind pose world vertex position) * (bindPose world matric inverse for joint k) * (world matrix for joint k on frame i) * (weight for joint k), for all joint k that influences that vertex

 

this approach works for some models but fails for the one I have (it just have one mesh with a hierarchy of joints)

 

I verify the approach by writing a command in maya that takes in a vertex idx and a frame idx and it outputs the world space bind pose points and world space skinned points by directly querying the maya mesh

 

this is the output from the command

// Selected mesh: |Ganfaul|GanfaulShape //
//     GanfaulShape is a riggedMesh, skin cluster name: skinCluster1 //
//     Checking mesh: GanfaulShape, vertexID: 4685, frameIdx: 3 //
//                Bind Pose Local Space Point: -1.702918, 182.58876, 8.60685 //
//                Bind Pose World Space Point: -1.702918, 182.58876, 8.60685 //
//     Calculated Bind Pose World Space Point: -1.702918, 182.58876, 8.60685 //
//     Num joint influence   : 65 //
//     Num weights for vertex: 511225 //
//     Num joints for vertex : 65 //
//    Valid joint idx: 59, name: Head, weight: 1, bind pose list name: Head //
//                Frame Local Space Point: -3.06953, 175.204819, 7.018704 //
//                Frame World Space Point: -3.06953, 175.204819, 7.018704 //
//     Calculated Frame World Space Point: 4.036224, 153.692543, 25.453149 //

 

here is the code for the command

    MObject skinClusterObj;
    MObject skinnedMeshObj = skinnedMeshDag.node();
    if (!MayaHelper::isMeshRigged(skinnedMeshObj, skinClusterObj))
    {
        MayaLog::OutputInfo("    TestCmd, selected mesh is not rigged");
        return;
    }

    MStatus stats = MS::kSuccess;
    MayaHelper::animControlGoToFirstFrame();
    MayaHelper::setAllJointToBindPose();

    MFnMesh meshFn(skinnedMeshDag);
    MayaLog::OutputInfo(MString("    Checking mesh: ") + meshFn.name() + MString(", vertexID: ") + vertexId + MString(", frameIdx: ") + frameIdx);

    MPoint bindPoseLocalSpacePoint;
    MPoint bindPoseWorldSpacePoint;
    stats = meshFn.getPoint(vertexId, bindPoseLocalSpacePoint, MSpace::kObject);
    if (stats != MS::kSuccess)
    {
        MayaLog::OutputError("    Error getting bind pose local space point");
        return;
    }
    stats = meshFn.getPoint(vertexId, bindPoseWorldSpacePoint, MSpace::kWorld);
    if (stats != MS::kSuccess)
    {
        MayaLog::OutputError("    Error getting bind pose world space point");
        return;
    }

    MDagPath skinnedMeshParentDag = skinnedMeshDag;
    skinnedMeshParentDag.pop();
    const MPoint bindPoseWorldCalculated = bindPoseLocalSpacePoint * skinnedMeshParentDag.inclusiveMatrix();
    MayaHelper::printMPoint(MString("               Bind Pose Local Space Point: "), bindPoseLocalSpacePoint);
    MayaHelper::printMPoint(MString("               Bind Pose World Space Point: "), bindPoseWorldSpacePoint);
    MayaHelper::printMPoint(MString("    Calculated Bind Pose World Space Point: "), bindPoseWorldCalculated);

    MFnSkinCluster skinClusterFn(skinClusterObj);
    MDagPathArray jointDags;
    skinClusterFn.influenceObjects(jointDags);
    const unsigned int numJoints = jointDags.length();

    // get bind pose world transforms
    struct JointBindPoseInfo
    {
        std::string jointName;
        MTransformationMatrix bindPoseWorldTransMat;

        JointBindPoseInfo() :
            jointName(""),
            bindPoseWorldTransMat(MTransformationMatrix::identity),
        {}
    };
    std::vector<JointBindPoseInfo> jointsBindPoseWorld(numJoints);
    for (unsigned int i = 0; i < numJoints; ++i)
    {
        const MString jointName = jointDags[i].partialPathName();
        MFnIkJoint jointFn(jointDags[i]);

        // get the world bind pose matrix for this bone
        // and store it in the bone desc
        MPlug bindPosePlug = jointFn.findPlug(c_jointNodeBindPoseAttrName);
        const MFnMatrixData bindPoseMatrixDataFn(bindPosePlug.asMObject());

        // export bind pose world
        const MMatrix bindPoseMatWorld = bindPoseMatrixDataFn.matrix();
        jointsBindPoseWorld[i].jointName = jointName.asChar();
        jointsBindPoseWorld[i].bindPoseWorldTransMat = bindPoseMatWorld;

        MString transformName = jointName + MString("_bindPoseWorld");
    }

    MayaHelper::animControlGoToFrame(frameIdx);

    MPoint frameWorldCalculated(0, 0, 0);
    MPoint frameLocalSpacePoint;
    MPoint frameWorldSpacePoint;
    stats = meshFn.getPoint(vertexId, frameLocalSpacePoint, MSpace::kObject);
    if (stats != MS::kSuccess)
    {
        MayaLog::OutputError("    Error getting frame local space point");
        return;
    }
    stats = meshFn.getPoint(vertexId, frameWorldSpacePoint, MSpace::kWorld);
    if (stats != MS::kSuccess)
    {
        MayaLog::OutputError("    Error getting frame world space point");
        return;
    }

    MDoubleArray weights;
    {
        MIntArray elementArray;
        elementArray.append(vertexId);
        MFnSingleIndexedComponent vertices;
        vertices.addElements(elementArray);
        MObject vertComponents = vertices.create(MFn::kMeshVertComponent);

        // numJointInfluences will always be number of bones in the skeleton even if they have weight of 0
        // so weights will be numVerts * numJointInfluences big
        // however, joints not part of influence list are not counted
        unsigned int numJointInfluences = 0;
        skinClusterFn.getWeights(skinnedMeshDag, vertComponents, weights, numJointInfluences);

        const unsigned int numWeights = weights.length();
        MayaLog::OutputInfo(MString("    Num joint influence   : ") + numJointInfluences);
        MayaLog::OutputInfo(MString("    Num weights for vertex: ") + numWeights);
        MayaLog::OutputInfo(MString("    Num joints for vertex : ") + numJoints);

        std::vector<double> vertWeights(numJointInfluences, 0.0);
        for (unsigned int j = 0; j < numJointInfluences; ++j)
        {
            const double& weight = weights[vertexId * numJointInfluences + j];
            vertWeights[j] = weight;
        }

        struct JointWeightInfo
        {
            MString jointName;
            MDagPath jointDag;
            double weight;

            JointWeightInfo() :
                jointName(""),
                jointDag(),
                weight(0.0)
            {}
        };
        std::vector<JointWeightInfo> validJointAndWeights;
        for (unsigned int i = 0; i < numJointInfluences; ++i)
        {
            if (vertWeights[i] > 0.0)
            {
                JointWeightInfo weightInfo;
                weightInfo.jointName = jointDags[i].partialPathName();
                weightInfo.jointDag = jointDags[i];
                weightInfo.weight = vertWeights[i];
                validJointAndWeights.emplace_back(weightInfo);
                MayaLog::OutputInfo(MString("   Valid joint idx: ") + i + MString(", name: ") + jointDags[i].partialPathName() + MString(", weight: ") + vertWeights[i] + MString(", bind pose list name: ") + jointsBindPoseWorld[i].jointName.c_str());

                frameWorldCalculated += vertWeights[i] * (bindPoseWorldCalculated *
                                                          jointsBindPoseWorld[i].bindPoseWorldTransMat.asMatrixInverse() *
                                                          jointDags[i].inclusiveMatrix());
            }
        }
    }

    MayaHelper::printMPoint(MString("               Frame Local Space Point: "), frameLocalSpacePoint);
    MayaHelper::printMPoint(MString("               Frame World Space Point: "), frameWorldSpacePoint);
    MayaHelper::printMPoint(MString("    Calculated Frame World Space Point: "), frameWorldCalculated);

    MayaHelper::animControlGoToFirstFrame();
    MayaHelper::setAllJointToBindPose();

Is there any transform that I could have possibly not gotten from Maya to perform the skinning? It works well for most rigged meshs I created myself but for this model it doesn't. I would appreciate any help on this thanks!

 

 

 

 

0 Likes
Accepted solutions (1)
1,682 Views
9 Replies
Replies (9)
Message 2 of 10

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

I've tried to test your code with Maya 2017 Update 3, but I can't reproduce the issue.

 

There are several helper functions in your code I don't have, so I made some replacement in mine. Here is my code:

 

        MStatus stat;			// Status code
	unsigned vertexId = 4685;
	//Frame idx?
	auto frameIdx = MTime(3 , MTime::k24FPS);
	MObject skinClusterObj;
	MDagPath skinnedMeshDag;
	MSelectionList slist;
	MGlobal::getActiveSelectionList( slist );	
	slist.getDagPath(0, skinnedMeshDag);
	slist.getDependNode(1, skinClusterObj);
	skinnedMeshDag.extendToShape();
	
	MObject skinnedMeshObj = skinnedMeshDag.node();

	MStatus stats = MS::kSuccess;
	auto start = MAnimControl::animationStartTime();
	MAnimControl::setCurrentTime(start);
	MGlobal::executeCommand("select -hi hips;");
	MGlobal::executeCommand("gotoBindPose;");

	MFnMesh meshFn(skinnedMeshObj);
	MGlobal::displayInfo(MString("    Checking mesh: ") + meshFn.name() + MString(", vertexID: ") + vertexId + MString(", frameIdx: ") + 3);

	MPoint bindPoseLocalSpacePoint;
	MPoint bindPoseWorldSpacePoint;
	stats = meshFn.getPoint(vertexId, bindPoseLocalSpacePoint, MSpace::kObject);
	
	stats = meshFn.getPoint(vertexId, bindPoseWorldSpacePoint, MSpace::kWorld);
	

	MDagPath skinnedMeshParentDag = skinnedMeshDag;
	skinnedMeshParentDag.pop();
	char buffer[256];
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseLocalSpacePoint.x,bindPoseLocalSpacePoint.y,bindPoseLocalSpacePoint.z );
	const MPoint bindPoseWorldCalculated = bindPoseLocalSpacePoint * skinnedMeshParentDag.inclusiveMatrix();
	MGlobal::displayInfo(MString("               Bind Pose Local Space Point: ") + buffer);
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldSpacePoint.x,bindPoseWorldSpacePoint.y,bindPoseWorldSpacePoint.z );
	MGlobal::displayInfo(MString("               Bind Pose World Space Point: ") + buffer);
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldCalculated.x,bindPoseWorldCalculated.y,bindPoseWorldCalculated.z );
	MGlobal::displayInfo(MString("    Calculated Bind Pose World Space Point: ") +buffer);
	
	MFnSkinCluster skinClusterFn(skinClusterObj);
	MDagPathArray jointDags;
	skinClusterFn.influenceObjects(jointDags);
	const unsigned int numJoints = jointDags.length();

	// get bind pose world transforms
	
	std::vector<JointBindPoseInfo> jointsBindPoseWorld(numJoints);
	for (unsigned int i = 0; i < numJoints; ++i)
	{
		const MString jointName = jointDags[i].partialPathName();
		MFnIkJoint jointFn(jointDags[i]);

		// get the world bind pose matrix for this bone
		// and store it in the bone desc
		MPlug bindPosePlug = jointFn.findPlug("bindPose");
		const MFnMatrixData bindPoseMatrixDataFn(bindPosePlug.asMObject());

		// export bind pose world
		const MMatrix bindPoseMatWorld = bindPoseMatrixDataFn.matrix();
		jointsBindPoseWorld[i].jointName = jointName.asChar();
		jointsBindPoseWorld[i].bindPoseWorldTransMat = bindPoseMatWorld;

		MString transformName = jointName + MString("_bindPoseWorld");
	}

	MAnimControl::setCurrentTime(frameIdx);

	MPoint frameWorldCalculated(0, 0, 0);
	MPoint frameLocalSpacePoint;
	MPoint frameWorldSpacePoint;
	stats = meshFn.getPoint(vertexId, frameLocalSpacePoint, MSpace::kObject);

	MDoubleArray weights;
	{
		MIntArray elementArray;
		elementArray.append(vertexId);
		MFnSingleIndexedComponent vertices;
		vertices.addElements(elementArray);
		MObject vertComponents = vertices.create(MFn::kMeshVertComponent);

		// numJointInfluences will always be number of bones in the skeleton even if they have weight of 0
		// so weights will be numVerts * numJointInfluences big
		// however, joints not part of influence list are not counted
		unsigned int numJointInfluences = 0;
		skinClusterFn.getWeights(skinnedMeshDag, vertComponents, weights, numJointInfluences);

		const unsigned int numWeights = weights.length();
		MGlobal::displayInfo(MString("    Num joint influence   : ") + numJointInfluences);
		MGlobal::displayInfo(MString("    Num weights for vertex: ") + numWeights);
		MGlobal::displayInfo(MString("    Num joints for vertex : ") + numJoints);

		std::vector<double> vertWeights(numJointInfluences, 0.0);
		for (unsigned int j = 0; j < numJointInfluences; ++j)
		{
			const double& weight = weights[vertexId * numJointInfluences + j];
			vertWeights[j] = weight;
		}

		struct JointWeightInfo
		{
			MString jointName;
			MDagPath jointDag;
			double weight;

			JointWeightInfo() :
				jointName(""),
				jointDag(),
				weight(0.0)
			{}
		};
		std::vector<JointWeightInfo> validJointAndWeights;
		for (unsigned int i = 0; i < numJointInfluences; ++i)
		{
			if (vertWeights[i] > 0.0)
			{
				JointWeightInfo weightInfo;
				weightInfo.jointName = jointDags[i].partialPathName();
				weightInfo.jointDag = jointDags[i];
				weightInfo.weight = vertWeights[i];
				validJointAndWeights.emplace_back(weightInfo);
				MGlobal::displayInfo(MString("   Valid joint idx: ") + i + MString(", name: ") + jointDags[i].partialPathName() + MString(", weight: ") + vertWeights[i] + MString(", bind pose list name: ") + jointsBindPoseWorld[i].jointName.c_str());

				frameWorldCalculated += vertWeights[i] * (bindPoseWorldCalculated *
					jointsBindPoseWorld[i].bindPoseWorldTransMat.asMatrixInverse() *
					jointDags[i].inclusiveMatrix());
			}
		}
	}
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", frameLocalSpacePoint.x,frameLocalSpacePoint.y,frameLocalSpacePoint.z );
	MGlobal::displayInfo(MString("               Frame Local Space Point: ") + buffer);
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldSpacePoint.x,bindPoseWorldSpacePoint.y,bindPoseWorldSpacePoint.z );
	MGlobal::displayInfo(MString("               Frame World Space Point: ") + buffer);

	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldCalculated.x,bindPoseWorldCalculated.y,bindPoseWorldCalculated.z );
	MGlobal::displayInfo(MString("    Calculated Frame World Space Point: ") + buffer);

	MAnimControl::setCurrentTime(start);
	MGlobal::executeCommand("select -hi hips;");
	MGlobal::executeCommand("gotoBindPose;");
	
	return MS::kSuccess;

And here is result:

 

//     Checking mesh: GanfaulShape, vertexID: 4685, frameIdx: 3 // 
//                Bind Pose Local Space Point: x:-1.702918,y:182.588760,z:8.606850 // 
//                Bind Pose World Space Point: x:-1.702918,y:182.588760,z:8.606850 // 
//     Calculated Bind Pose World Space Point: x:-1.702918,y:182.588760,z:8.606850 // 
//     Num joint influence   : 65 // 
//     Num weights for vertex: 511225 // 
//     Num joints for vertex : 65 // 
//    Valid joint idx: 59, name: Head, weight: 1, bind pose list name: Head // 
//                Frame Local Space Point: x:-3.069530,y:175.204819,z:7.018703 // 
//                Frame World Space Point: x:-1.702918,y:182.588760,z:8.606850 // 
//     Calculated Frame World Space Point: x:-1.702918,y:182.588760,z:8.606850 // 

If I've missed something, please let me know.

 

Yours,

Li

0 Likes
Message 3 of 10

Anonymous
Not applicable

Hi,

 

thanks for your reply. I am travelling and have no access to Maya this week.

However, here's something I think you missed.

 

 

sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", frameLocalSpacePoint.x,frameLocalSpacePoint.y,frameLocalSpacePoint.z );
	MGlobal::displayInfo(MString("               Frame Local Space Point: ") + buffer);
	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldSpacePoint.x,bindPoseWorldSpacePoint.y,bindPoseWorldSpacePoint.z );
	MGlobal::displayInfo(MString("               Frame World Space Point: ") + buffer);

	sprintf_s(buffer,256,"x:%lf,y:%lf,z:%lf", bindPoseWorldCalculated.x,bindPoseWorldCalculated.y,bindPoseWorldCalculated.z );
	MGlobal::displayInfo(MString("    Calculated Frame World Space Point: ") + buffer);

	MAnimControl::setCurrentTime(start);
	MGlobal::executeCommand("select -hi hips;");
	MGlobal::executeCommand("gotoBindPose;");
	
	return MS::kSuccess;

 

You should be printing frameWorldCalculated instead of bindPoseWorldCalculated. Similarly, you should be printing frameWorldSpacePoint instead of bindPoseWorldSpacePoint.

 

You are also missing the call to meshFn to retrieve frameWorldSpacePoint.

stats = meshFn.getPoint(vertexId, frameWorldSpacePoint, MSpace::kWorld);

 

Do you get the same value for frameWorldCalculated and frameWorldSpacePoint after making this change?

 

Regards

Alvin

0 Likes
Message 4 of 10

cheng_xi_li
Autodesk Support
Autodesk Support

Hi,

 

Thanks for pointing it out, should write a function instead of copying & pasting. I could reproduce now. I'll be back if I've found something.

 

Yours,

Li

0 Likes
Message 5 of 10

Anonymous
Not applicable

Thanks Li!

 

I'm stuck too. I have not been able to figure what else am I missing.

Please let me know if you found something that I overlooked. Thanks!

 

Regards

Alvin

0 Likes
Message 6 of 10

cheng_xi_li
Autodesk Support
Autodesk Support
Accepted solution

Hi,

 

After checking your code. You should use the vertex location of original shape(GanfaulShapeOrig) instead of the one after deforming(GanfaulShape).

 

I guess your other models don't have deformation at the beginning, so the vertices of bindPoseWorldSpace have same position as the original mesh.

 

MStatus nodeInfo::doIt( const MArgList& args )
//
// Description
//     This method performs the action of the command.
//
//     This method iterates over all selected items and
//     prints out connected plug and dependency node type
//     information.
//
{
	MStatus stat;			// Status code
	unsigned vertexId = 4685;
	MGlobal::executeCommand("select GanfaulShape skinCluster1 GanfaulShapeOrig;");
	//Frame idx?
	auto frameIdx = MTime(3 , MTime::k20FPS);
	MObject skinClusterObj;
	MDagPath skinnedMeshDag;
	MDagPath skinnedMeshDagOrig;
	MSelectionList slist;
	MGlobal::getActiveSelectionList( slist );	
	slist.getDagPath(0, skinnedMeshDag);
	slist.getDependNode(1, skinClusterObj);
	skinnedMeshDag.extendToShape();
	slist.getDagPath(2, skinnedMeshDagOrig);
	
	MObject skinnedMeshObj = skinnedMeshDag.node();

	MStatus stats = MS::kSuccess;
	auto start = MAnimControl::animationStartTime();
	MAnimControl::setCurrentTime(start);
	MGlobal::executeCommand("select -hi Hips;");
	MGlobal::executeCommand("gotoBindPose;");

	MFnMesh meshFn(skinnedMeshDag);
	MGlobal::displayInfo(MString("    Checking mesh: ") + meshFn.name() + MString(", vertexID: ") + vertexId + MString(", frameIdx: ") + 3);

	MPoint bindPoseLocalSpacePoint;
	MPoint localSpacePoint;
	MPoint bindPoseWorldSpacePoint;
	stats = meshFn.getPoint(vertexId, bindPoseLocalSpacePoint, MSpace::kObject);
	
	stats = meshFn.getPoint(vertexId, bindPoseWorldSpacePoint, MSpace::kWorld);
	MFnMesh meshFnOrig(skinnedMeshDagOrig);

	stats = meshFnOrig.getPoint(vertexId, localSpacePoint, MSpace::kObject);


	MDagPath skinnedMeshParentDag = skinnedMeshDag;
	skinnedMeshParentDag.pop();	
	const MPoint bindPoseWorldCalculated = bindPoseLocalSpacePoint * skinnedMeshParentDag.inclusiveMatrix();
	printMPoint(bindPoseLocalSpacePoint, "               Bind Pose Local Space Point: ");
	printMPoint(bindPoseWorldSpacePoint, "               Bind Pose World Space Point: ");
	printMPoint(bindPoseWorldCalculated, "    Calculated Bind Pose World Space Point: ");
	
	MFnSkinCluster skinClusterFn(skinClusterObj);
	MDagPathArray jointDags;
	skinClusterFn.influenceObjects(jointDags);
	const unsigned int numJoints = jointDags.length();

	
	// get bind pose world transforms
	std::vector<JointBindPoseInfo> jointsBindPoseWorld(numJoints);
	for (unsigned int i = 0; i < numJoints; ++i)
	{
		const MString jointName = jointDags[i].partialPathName();
		MFnIkJoint jointFn(jointDags[i]);

		// get the world bind pose matrix for this bone
		// and store it in the bone desc

		MPlug bindPosePlug = jointFn.findPlug("bindPose");

		const MFnMatrixData bindPoseMatrixDataFn(bindPosePlug.asMObject());

		// export bind pose world*/		
		const MMatrix bindPoseMatWorld = bindPoseMatrixDataFn.matrix();
		jointsBindPoseWorld[i].jointName = jointName.asChar();
		jointsBindPoseWorld[i].bindPoseWorldTransMat = bindPoseMatWorld;
		jointsBindPoseWorld[i].jointTransformMatrix = jointDags[i].inclusiveMatrix();

		MString transformName = jointName + MString("_bindPoseWorld");
	}
	
	MAnimControl::setCurrentTime(frameIdx);
	
	MPoint frameWorldCalculated(0, 0, 0);
	MPoint frameLocalSpacePoint;
	MPoint frameWorldSpacePoint;
	stats = meshFn.getPoint(vertexId, frameLocalSpacePoint, MSpace::kObject);
	stats = meshFn.getPoint(vertexId, frameWorldSpacePoint, MSpace::kWorld);
	
	MDoubleArray weights;
	{
		MIntArray elementArray;
		elementArray.append(vertexId);
		MFnSingleIndexedComponent vertices;
		vertices.addElements(elementArray);
		MObject vertComponents = vertices.create(MFn::kMeshVertComponent);

		// numJointInfluences will always be number of bones in the skeleton even if they have weight of 0
		// so weights will be numVerts * numJointInfluences big
		// however, joints not part of influence list are not counted
		unsigned int numJointInfluences = 0;
		skinClusterFn.getWeights(skinnedMeshDag, vertComponents, weights, numJointInfluences);

		const unsigned int numWeights = weights.length();
		MGlobal::displayInfo(MString("    Num joint influence   : ") + numJointInfluences);
		MGlobal::displayInfo(MString("    Num weights for vertex: ") + numWeights);
		MGlobal::displayInfo(MString("    Num joints for vertex : ") + numJoints);

		std::vector<double> vertWeights(numJointInfluences, 0.0);
		for (unsigned int j = 0; j < numJointInfluences; ++j)
		{
			const double& weight = weights[vertexId * numJointInfluences + j];
			vertWeights[j] = weight;
		}

		struct JointWeightInfo
		{
			MString jointName;
			MDagPath jointDag;
			double weight;

			JointWeightInfo() :
				jointName(""),
				jointDag(),
				weight(0.0)
			{}
		};
		std::vector<JointWeightInfo> validJointAndWeights;
		for (unsigned int i = 0; i < numJointInfluences; ++i)
		{
			if (vertWeights[i] > 0.0)
			{
				JointWeightInfo weightInfo;
				weightInfo.jointName = jointDags[i].partialPathName();
				weightInfo.jointDag = jointDags[i];
				weightInfo.weight = vertWeights[i];
				validJointAndWeights.emplace_back(weightInfo);
				MGlobal::displayInfo(MString("   Valid joint idx: ") + i + MString(", name: ") + jointDags[i].partialPathName() + MString(", weight: ") + vertWeights[i] + MString(", bind pose list name: ") + jointsBindPoseWorld[i].jointName.c_str());
				auto newMat = jointsBindPoseWorld[i].bindPoseWorldTransMat.asMatrixInverse() * jointDags[i].inclusiveMatrix();				
				frameWorldCalculated += vertWeights[i] * (localSpacePoint *	newMat);
			}
		}
	}
	printMPoint(frameLocalSpacePoint, "               Frame Local Space Point: ");
	printMPoint(frameWorldSpacePoint, "               Frame World Space Point: ");
	printMPoint(frameWorldCalculated, "    Calculated Frame World Space Point: ");

	MAnimControl::setCurrentTime(start);
	MGlobal::executeCommand("select -hi Hips;");
	MGlobal::executeCommand("gotoBindPose;");
	
	return MS::kSuccess;
}

 

Yours,

Li

Message 7 of 10

Anonymous
Not applicable

Thanks for getting back so quick. I'll give this a shot when I get back.

 

Out of curiousity, I thought the original shape is way before the joints are bound to the mesh and the deformed mesh is the mesh in bind pose?

It doesn't make sense if I take the vertex world position from the original shape and multiply it by the inverse world bind pose matrix.

Maybe I am not understanding how the skin cluster node works properly. Could you explain further?

 

Regards

Alvin

0 Likes
Message 8 of 10

cheng_xi_li
Autodesk Support
Autodesk Support

Hi, 

 

It is linear blend skinning(LBS) method for linear skinning in your scene.

 

So, for each vertex P[i] having n joints J, weights W and bindPose B, deformed vertex P'[i] should be 

 

P'[i] = W[0] * P[i]* B[0].inverseMatrix * J[0] + ...... W[n-1] * P[i] * B[n-1].inverseMatrix * J[n-1]

 

in local space.

 

It is impossible to use P'[i] for the next calculation if there are more than one weights, because you can't get it's original position and apply new LBSmatrix on it. 

 

So, when you asking for position of a deformed mesh(GanfaulShape in your case). Maya will calculate it based from original shape(GanfaulShapeOrig) and apply world transform on it if you are getting world position. When frame has been changed, Maya will calculate it again on demand. 

 

 

Yours,

Li

0 Likes
Message 9 of 10

Anonymous
Not applicable

Thanks.

 

I'll verify this next week when I'm back in office and get back to you.

 

Regards

Alvin

0 Likes
Message 10 of 10

Anonymous
Not applicable

Hi

 

using the original shape works. Thanks this fixes the problem I was having!

 

Regards

Alvin

0 Likes