Esempio n. 1
0
		void GameEngine::FbxLoader::FbxLoader::ProcessAnimCurveR(FbxAnimCurve* curve[3], AnimTransformCurve& animCurve, FbxAMatrix & preRotation)
		{
			if(!curve) return;

			auto& curve3 = animCurve.rotation;

			int xKeys = curve[0]->KeyGetCount();
			int yKeys = curve[1]->KeyGetCount();
			int zKeys = curve[2]->KeyGetCount();

			// check key sync
			if(xKeys != yKeys || xKeys != zKeys)
				return;

			int nKeys = xKeys;

			curve3.curves[0].keyframes.resize(nKeys);
			curve3.curves[1].keyframes.resize(nKeys);
			curve3.curves[2].keyframes.resize(nKeys);

			animCurve.end = (float)curve[0]->KeyGetTime(nKeys - 1).GetSecondDouble();

			for(int ki = 0; ki < nKeys; ++ki) {
				auto& xkey = curve3.curves[0].keyframes[ki];
				auto& ykey = curve3.curves[1].keyframes[ki];
				auto& zkey = curve3.curves[2].keyframes[ki];

				curve[0]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				curve[1]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				curve[2]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				auto xvalue = curve[0]->KeyGetValue(ki);
				auto yvalue = curve[1]->KeyGetValue(ki);
				auto zvalue = curve[2]->KeyGetValue(ki);

				auto xlt = curve[0]->KeyGetLeftAuto(ki);
				auto xrt = curve[0]->KeyGetRightAuto(ki);
				auto ylt = curve[1]->KeyGetLeftAuto(ki);
				auto yrt = curve[1]->KeyGetRightAuto(ki);
				auto zlt = curve[2]->KeyGetLeftAuto(ki);
				auto zrt = curve[2]->KeyGetRightAuto(ki);

				FbxAMatrix temp;
				temp.SetR(FbxVector4(xvalue, yvalue, zvalue));
				auto R = (preRotation* temp).GetR();
				xvalue = (float)R[0]; yvalue = (float)R[1]; zvalue = (float)R[2];

				float t = (float)curve[0]->KeyGetTime(ki).GetSecondDouble();

				if(axismode == eLeftHanded) {
					yvalue *= -1; ylt *= -1; yrt *= -1;
					zvalue *= -1; zlt *= -1; zrt *= -1;
				}

				xkey.time = t; ykey.time = t; zkey.time = t;
				xkey.value = xvalue; ykey.value = yvalue; zkey.value = zvalue;
				xkey.leftTangent = xlt; xkey.rightTangent = xrt;
				ykey.leftTangent = ylt; ykey.rightTangent = yrt;
				zkey.leftTangent = zlt; zkey.rightTangent = zrt;
			}
		}
/*
The result of this function is a matrix which transforms the verts from their position (where they were when the skeleton was bound to them) to the space of the bone when the verts were bound.
We can then append the bone's current transform in the animation to get the verts into worls space at the current point in the animation.
*/
void Cluster::computeClusterInitTransforms(FbxMesh* mesh, FbxCluster* cluster)
{
	FbxCluster::ELinkMode lClusterMode = cluster->GetLinkMode();

	FbxAMatrix lReferenceGlobalInitPosition;
	FbxAMatrix lAssociateGlobalInitPosition;
	FbxAMatrix lClusterGlobalInitPosition;

	FbxAMatrix lClusterGeometry;
	FbxAMatrix lReferenceGeometry;

	if (lClusterMode == FbxCluster::eAdditive && cluster->GetAssociateModel())
	{
		throw "Addative skinning mode not supported";
	}
	else
	{
		// Transform from the verts' local position at bind time (which is their position when loaded from file) to world space.
		cluster->GetTransformMatrix(lReferenceGlobalInitPosition);
		

		lReferenceGeometry = getGeometry(mesh->GetNode());
		lReferenceGlobalInitPosition *= lReferenceGeometry;
		// Get the link initial global position and the link current global position.
		cluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
		// Transform from world space to bones space at binding time
		FbxAMatrix globalInitPosInv = lClusterGlobalInitPosition.Inverse();
		FbxAMatrix initTransform = globalInitPosInv * lReferenceGlobalInitPosition;
		meshToBoneTransform = Matrix44<float>(
			initTransform[0][0], initTransform[0][1], initTransform[0][2], initTransform[0][3],
			initTransform[1][0], initTransform[1][1], initTransform[1][2], initTransform[1][3],
			initTransform[2][0], initTransform[2][1], initTransform[2][2], initTransform[2][3],
			initTransform[3][0], initTransform[3][1], initTransform[3][2], initTransform[3][3]);
	}
}
Esempio n. 3
0
void MeshEntry::LoadTransform(FbxMesh *mesh)
{





    FbxVector4 T = mesh->GetNode()->GetGeometricTranslation (FbxNode::eSourcePivot);
    FbxVector4 R = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot);
    FbxVector4 S = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot);
    FbxAMatrix geometric_offset_transform(T, R, S);





    FbxAMatrix transform = mesh->GetNode()->GetScene()->GetAnimationEvaluator()->GetNodeGlobalTransform(mesh->GetNode()) *
            geometric_offset_transform;





    for (qint32 i = 0; i < 4; i++)
        for (qint32 j = 0; j < 4; j++)
            m_local_transform(i, j) = transform.Transpose().Get(i, j);




}
void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node)
{
    FbxAMatrix matrix;
    float m[16];
    
    if (fbxNode->GetCamera() || fbxNode->GetLight())
    {
        FbxAMatrix rotateAdjust;
        
        if(fbxNode->GetLight())
        {
            /*
             * according to the fbx-documentation the light's forward vector
             * points along a node's negative Y axis.
             * so we have to rotate it by 90° around the X-axis to correct it.
             */
            if(fbxNode->RotationActive.Get())
            {
                const FbxVector4& postRotation = fbxNode->PostRotation.Get();
                fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0] + 90.0,
                                                                           postRotation.mData[1],
                                                                           postRotation.mData[2])
                                         );
            }
            else
            {
                // if the rotation is deactivated we have to rotate it anyway to get the correct transformation in the end
                rotateAdjust.SetR(FbxVector4(-90.0, 0.0, 0.0));
            }
            
            matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust;
        }
        else if(fbxNode->GetCamera())
        {
            // TODO: use the EvaluateLocalTransform() function for the transformations for the camera
            /*
             * the current implementation ignores pre- and postrotation among others (usually happens with fbx-export from blender)
             *
             * Some info for a future implementation:
             * according to the fbx-documentation the camera's forward vector
             * points along a node's positive X axis.
             * so we have to correct it if we use the EvaluateLocalTransform-function
             * just rotating it by 90° around the Y axis (similar to above) doesn't work
             */
            matrix.SetTRS(fbxNode->LclTranslation.Get(), fbxNode->LclRotation.Get(), fbxNode->LclScaling.Get());
        }
        
        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
    else
    {
        matrix = fbxNode->EvaluateLocalTransform();
        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
}
FbxAMatrix	LoaderFbxMesh::getGeometry(FbxNode* node)
{
	FbxAMatrix fbxGeometry;
	FbxVector4 fbxTranslation, fbxRotation, fbxScaling;

	fbxTranslation	= node->GetGeometricTranslation(FbxNode::eSourcePivot);
	fbxRotation		= node->GetGeometricRotation(FbxNode::eSourcePivot);
	fbxScaling		= node->GetGeometricScaling(FbxNode::eSourcePivot);
	fbxGeometry.SetTRS(fbxTranslation, fbxRotation, fbxScaling);

	return fbxGeometry;
}
Esempio n. 6
0
void FbxFileLoader::print_matrix( const FbxAMatrix& m ) const
{
	std::cout.setf( std::ios_base::fixed, std::ios_base::floatfield );
	std::cout.precision( 4 );

	std::cout << "\tT : " << m.GetT()[ 0 ] << ", " << m.GetT()[ 1 ] << ", " << m.GetT()[ 2 ] << std::endl;
	std::cout << "\tR : " << m.GetR()[ 0 ] << ", " << m.GetR()[ 1 ] << ", " << m.GetR()[ 2 ] << std::endl;
	std::cout << "\tS : " << m.GetS()[ 0 ] << ", " << m.GetS()[ 1 ] << ", " << m.GetS()[ 2 ] << std::endl;
}
Esempio n. 7
0
bool ParseMeshSkinning( FbxMesh* pMesh, SkinData* pSkinData )
{
    DWORD dwDeformerCount = pMesh->GetDeformerCount( FbxDeformer::eSkin );
    if( dwDeformerCount == 0 )
        return false;

    ExportLog::LogMsg( 4, "Parsing skin weights on mesh %s", pMesh->GetName() );

    const DWORD dwVertexCount = pMesh->GetControlPointsCount();
    const DWORD dwStride = 4;
    pSkinData->Alloc( dwVertexCount, dwStride );

    for( DWORD dwDeformerIndex = 0; dwDeformerIndex < dwDeformerCount; ++dwDeformerIndex )
    {
        auto pSkin = reinterpret_cast<FbxSkin*>( pMesh->GetDeformer( dwDeformerIndex, FbxDeformer::eSkin ) );
        DWORD dwClusterCount = pSkin->GetClusterCount();

        for( DWORD dwClusterIndex = 0; dwClusterIndex < dwClusterCount; ++dwClusterIndex )
        {
            auto pCluster = pSkin->GetCluster( dwClusterIndex );
            DWORD dwClusterSize = pCluster->GetControlPointIndicesCount();
            if( dwClusterSize == 0 )
                continue;

            auto pLink = pCluster->GetLink();

            DWORD dwBoneIndex = pSkinData->GetBoneCount();
            pSkinData->InfluenceNodes.push_back( pLink );
            ExportLog::LogMsg( 4, "Influence %u: %s", dwBoneIndex, pLink->GetName() );
            
            FbxAMatrix matXBindPose;
            pCluster->GetTransformLinkMatrix( matXBindPose );
            FbxAMatrix matReferenceGlobalInitPosition;
            pCluster->GetTransformMatrix(matReferenceGlobalInitPosition);
 
            FbxMatrix matBindPose = matReferenceGlobalInitPosition.Inverse() * matXBindPose;

            CaptureBindPoseMatrix( pLink, matBindPose );

            INT* pIndices = pCluster->GetControlPointIndices();
            DOUBLE* pWeights = pCluster->GetControlPointWeights();

            for( DWORD i = 0; i < dwClusterSize; ++i )
            {
                pSkinData->InsertWeight( pIndices[i], dwBoneIndex, (float)pWeights[i] );
            }
        }
    }

    return true;
}
Esempio n. 8
0
FTransform FFbxDataConverter::ConvertTransform(FbxAMatrix Matrix)
{
	FTransform Out;

	FQuat Rotation = ConvertRotToQuat(Matrix.GetQ());
	FVector Origin = ConvertPos(Matrix.GetT());
	FVector Scale = ConvertScale(Matrix.GetS());

	Out.SetTranslation(Origin);
	Out.SetScale3D(Scale);
	Out.SetRotation(Rotation);

	return Out;
}
FbxAMatrix LoaderFbxMesh::convertToLeftHanded(FbxAMatrix fbxMatrix)
{
	FbxAMatrix convertionMatrix;
	FbxVector4 rowX(1.0, 0.0, 0.0, 0.0);
	FbxVector4 rowY(0.0, 1.0, 0.0, 0.0);
	FbxVector4 rowZ(0.0, 0.0, -1.0, 0.0);
	FbxVector4 rowW(0.0, 0.0, 0.0, 1.0);

	convertionMatrix.SetRow(0, rowX);
	convertionMatrix.SetRow(1, rowY);
	convertionMatrix.SetRow(2, rowZ);
	convertionMatrix.SetRow(3, rowW);

	FbxAMatrix convertedMatrix = fbxMatrix * convertionMatrix;
	return convertedMatrix;
}
Esempio n. 10
0
FMatrix FFbxDataConverter::ConvertMatrix(FbxAMatrix Matrix)
{
	FMatrix UEMatrix;

	for(int i=0; i<4; ++i)
	{
		FbxVector4 Row = Matrix.GetRow(i);
		if(i==1)
		{
			UEMatrix.M[i][0] = -Row[0];
			UEMatrix.M[i][1] = Row[1];
			UEMatrix.M[i][2] = -Row[2];
			UEMatrix.M[i][3] = -Row[3];
		}
		else
		{
			UEMatrix.M[i][0] = Row[0];
			UEMatrix.M[i][1] = -Row[1];
			UEMatrix.M[i][2] = Row[2];
			UEMatrix.M[i][3] = Row[3];
		}
	}
	
	return UEMatrix;
}
Esempio n. 11
0
void fbxLoader2::setBindPoseCluster(FbxNode *node)
{
	if( node->GetNodeAttribute())
	{
		switch(node->GetNodeAttribute()->GetAttributeType())
		{
		case FbxNodeAttribute::eMesh: 
			FbxMesh *mesh = node->GetMesh();

			for (int j = 0; j<mesh->GetDeformerCount(); j++)
			{
				FbxSkin *skin = (FbxSkin*) mesh->GetDeformer(j,FbxDeformer::eSkin);
				int clusters = skin->GetClusterCount();
				for(int k = 0; k<clusters; k++)
				{
					FbxCluster* cluster = skin->GetCluster(k);
					FbxNode* boneLink = cluster->GetLink();

					if(boneLink)
					{
						std::string nameLink = boneLink->GetName();
						FbxAMatrix translationM;
						FbxAMatrix invert;
						cluster->GetTransformLinkMatrix(translationM);
						cluster->GetTransformMatrix(invert);

						translationM = translationM * invert.Inverse();

						D3DXMATRIX mat = D3DXMATRIX((float)translationM.mData[0].mData[0], (float)translationM.mData[0].mData[1], (float)translationM.mData[0].mData[2], (float)translationM.mData[3].mData[0],
													(float)translationM.mData[1].mData[0], (float)translationM.mData[1].mData[1], (float)translationM.mData[1].mData[2], (float)translationM.mData[3].mData[1],
													(float)translationM.mData[2].mData[0], (float)translationM.mData[2].mData[1], (float)translationM.mData[2].mData[2], (float)translationM.mData[3].mData[2],
													0,0,0,1);

						skeleton->GetBone(skeleton->GetBoneByName(nameLink))->SetTransformation(mat);
					}
				}
			}
			break;
		}
	}
	for (int i = 0; i<node->GetChildCount(); i++)
	{
		FbxNode* child = node->GetChild(i);
		setBindPoseCluster(child);
	}
}
Esempio n. 12
0
void FBXSceneEncoder::loadSkin(FbxMesh* fbxMesh, Model* model)
{
    const int deformerCount = fbxMesh->GetDeformerCount();
    for (int i = 0; i < deformerCount; ++i)
    {
        FbxDeformer* deformer = fbxMesh->GetDeformer(i);
        if (deformer->GetDeformerType() == FbxDeformer::eSkin)
        {
            FbxSkin* fbxSkin = FbxCast<FbxSkin>(deformer);

            MeshSkin* skin = new MeshSkin();

            vector<string> jointNames;
            vector<Node*> joints;
            vector<Matrix> bindPoses;

            const int clusterCount = fbxSkin->GetClusterCount();
            for (int j = 0; j < clusterCount; ++j)
            {
                FbxCluster* cluster = fbxSkin->GetCluster(j);
                assert(cluster);
                FbxNode* linkedNode = cluster->GetLink();
                if (linkedNode && linkedNode->GetSkeleton())
                {
                    const char* jointName = linkedNode->GetName();
                    assert(jointName);
                    jointNames.push_back(jointName);
                    Node* joint = loadNode(linkedNode);
                    assert(joint);
                    joints.push_back(joint);

                    FbxAMatrix matrix;
                    cluster->GetTransformLinkMatrix(matrix);
                    Matrix m;
                    copyMatrix(matrix.Inverse(), m);
                    bindPoses.push_back(m);
                }
            }
            skin->setJointNames(jointNames);
            skin->setJoints(joints);
            skin->setBindPoses(bindPoses);
            model->setSkin(skin);
            break;
        }
    }
}
Esempio n. 13
0
FbxMatrix FBXScene::GetGeometricOffset2(FbxNode* pNode)
{
	if( !pNode )
	{
		FbxAMatrix mat;
		mat.SetIdentity();
		return mat;
	}

	// CheckMe: E Source Set = E Source Pivot?
	FbxVector4 T = pNode->GetGeometricTranslation(FbxNode::eSourcePivot);
	FbxVector4 R = pNode->GetGeometricRotation(FbxNode::eSourcePivot);
	FbxVector4 S = pNode->GetGeometricScaling(FbxNode::eSourcePivot);

	FbxAMatrix matFBXGeometryOffset;
	matFBXGeometryOffset.SetIdentity();
	matFBXGeometryOffset.SetTRS(T,R,S);

	return matFBXGeometryOffset;
}
Esempio n. 14
0
CU::Matrix44f CreateMatrix(FbxAMatrix& aOriention)
{
	CU::Matrix44f returnMatrix;
	for(int y = 0;y < 4;++y)
	{
		for(int x = 0;x < 4;++x)
		{
			returnMatrix.myMatrix[y * 4 + x] = (float)aOriention.Get(x, y);
		}
	}
	return returnMatrix;
}
FbxAMatrix  LoaderFbxMesh::parseTransformMatrix_debug(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition)
{
	FbxAMatrix transform;
	FbxAMatrix bindPoseTransform;
	FbxAMatrix bindPoseTransformInverse;
	FbxAMatrix boneReferenceTransform;
	FbxAMatrix boneReferenceTransformInverse;
	FbxAMatrix meshGeometryMatrix;

	cluster->GetTransformLinkMatrix(bindPoseTransform);
	cluster->GetTransformMatrix(boneReferenceTransform);

	bindPoseTransformInverse		= bindPoseTransform.Inverse();
	boneReferenceTransformInverse	= boneReferenceTransform.Inverse(); 

	meshGeometryMatrix = getGeometry(mesh->GetNode());

	transform = bindPoseTransformInverse * boneReferenceTransform;

	return transform;
}
FbxAMatrix	LoaderFbxMesh::parseTransformMatrixOther(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition)
{
	FbxAMatrix referenceGeometry;
	FbxAMatrix referenceGlobalInitPosition;
	FbxAMatrix referenceGlobalCurrentPosition;

	FbxAMatrix clusterGeometry;
	FbxAMatrix clusterGlobalInitPosition;
	FbxAMatrix clusterGlobalCurrentPosition;

	FbxAMatrix clusterRelativeInitPosition;
	FbxAMatrix clusterRelativeCurrentPositionInverse;

	FbxTime time(0);

	FbxAMatrix fbxMatrixIdentity;
	fbxMatrixIdentity.SetIdentity();

	cluster->GetTransformMatrix(referenceGlobalInitPosition);
	referenceGlobalCurrentPosition = globalPosition;
	referenceGeometry = getGeometry(mesh->GetNode());
	referenceGlobalInitPosition *= referenceGeometry;

	cluster->GetTransformLinkMatrix(clusterGlobalInitPosition);
	clusterGlobalCurrentPosition = getGlobalPosition(cluster->GetLink(), time, fbxPose, nullptr);

	clusterRelativeInitPosition = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition;
	clusterRelativeCurrentPositionInverse = referenceGlobalCurrentPosition.Inverse() * clusterGlobalCurrentPosition;
	
	FbxAMatrix offsetMatrix;
	offsetMatrix = clusterRelativeCurrentPositionInverse * clusterRelativeInitPosition;
	
	return offsetMatrix;
}
Esempio n. 17
0
		void FbxLoader::ComputeNodeMatrix(FbxNode* node, Node& meshNode, bool local)
		{
			if(!node)
				return;
			FbxAnimEvaluator* evaluator = scene->GetAnimationEvaluator();
			FbxAMatrix global;
			global.SetIdentity();

			FbxTime time;
			time.SetSecondDouble(0.0);
			
			if(node != scene->GetRootNode()) {
				if(local) {
					global = evaluator->GetNodeLocalTransform(node, time);
				}
				else {
					global = evaluator->GetNodeGlobalTransform(node, time);
				}
			}
			auto T = global.GetT() * factor;
			
			if(axismode == eLeftHanded) {
				auto R = global.GetR();
				R[1] *= -1; R[2] *= -1;
				T[0] *= -1;
				global.SetR(R);
			}
			global.SetT(T);

			meshNode.matrix = Matrix(
				(float)global[0][0], (float)global[0][1], (float)global[0][2], (float)global[0][3],
				(float)global[1][0], (float)global[1][1], (float)global[1][2], (float)global[1][3],
				(float)global[2][0], (float)global[2][1], (float)global[2][2], (float)global[2][3],
				(float)global[3][0], (float)global[3][1], (float)global[3][2], (float)global[3][3]);
		}
Esempio n. 18
0
//----------------------------------------------------------------------------
HMatrix Utilities::FbxMatrixToPX2(FbxAMatrix &fbxMat)
{
	HMatrix mat;

	for (int row = 0; row < 4; row++)
	{
		for (int col = 0; col < 4; col++)
		{
			mat(col, row) = (float)fbxMat.Get(row, col);
		}
	}

	return mat;
}
FbxAMatrix	LoaderFbxMesh::parseTransformMatrixAssociateModel(FbxCluster* cluster, FbxMesh* mesh, FbxPose* fbxPose, FbxAMatrix globalPosition)
{
	FbxAMatrix associateGeometry;
	FbxAMatrix associateGlobalInitPosition;
	FbxAMatrix associateGlobalCurrentPosition;

	FbxAMatrix referenceGeometry;
	FbxAMatrix referenceGlobalInitPosition;
	FbxAMatrix referenceGlobalCurrentPosition;

	FbxAMatrix clusterGeometry;
	FbxAMatrix clusterGlobalInitPosition;
	FbxAMatrix clusterGlobalCurrentPosition;

	FbxTime time(0);

	cluster->GetTransformAssociateModelMatrix(associateGlobalInitPosition);
	associateGeometry = getGeometry(cluster->GetAssociateModel());
	associateGlobalInitPosition *= associateGeometry;
	associateGlobalCurrentPosition = getGlobalPosition(cluster->GetAssociateModel(), time, fbxPose, nullptr);

	cluster->GetTransformMatrix(referenceGlobalInitPosition);
	referenceGeometry = getGeometry(mesh->GetNode());
	referenceGlobalInitPosition *= referenceGeometry;
	referenceGlobalCurrentPosition = globalPosition;

	cluster->GetTransformLinkMatrix(clusterGlobalInitPosition);
	clusterGeometry = getGeometry(cluster->GetLink());
	clusterGlobalInitPosition *= clusterGeometry;
	clusterGlobalCurrentPosition = getGlobalPosition(cluster->GetLink(), time, fbxPose, nullptr);

	FbxAMatrix offsetMatrix;
	offsetMatrix = referenceGlobalInitPosition.Inverse() * associateGlobalInitPosition * associateGlobalCurrentPosition.Inverse() *
			clusterGlobalCurrentPosition * clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition;

	return offsetMatrix;
}
Esempio n. 20
0
void FbxParser::ProcessLight(FbxNode* pNode, std::vector<GS::Light*>& lights)
{
   FbxLight* llight = (FbxLight*) pNode->GetNodeAttribute();
   if (!llight)
      return  ;

    // Get the light color.
   FbxDouble3 c = llight->Color.Get();
   GS::float4 lcolor( c[0], c[1], c[2], 1.0 );
   float intensity = llight->Intensity.Get();
   if (intensity)
     lcolor= lcolor*(intensity/100);
  
    // to do so far, we only process directional light
    if (llight->LightType.Get() == FbxLight::eDirectional)
	{
		//FbxDouble3 dir = pNode->LclRotation.Get(); 
		FbxAnimEvaluator* lEvaluator = mpFbxScene->GetAnimationEvaluator();

        FbxAMatrix lGlobal;
        lGlobal= lEvaluator->GetNodeGlobalTransform( pNode);

		FbxVector4 rotation = lGlobal.GetR();

		 FbxVector4 tran = lGlobal.GetT();
		 FbxQuaternion quaternion = lGlobal.GetQ();
		 GS::float4 q(quaternion[0], quaternion[1], quaternion[2],quaternion[3]);
		 GS::float4x4 rotMat = GS::quat_rotation_matrix(q);
		 GS::float4 dir(mul(rotMat, GS::float4(0, 0, -1, 1)));
    /* dir(0,0,-1);
   FbxQuaternion quaternion = lGlobal.GetQ();
   quaternion.
   LcLRotation3f quaternion3f(quaternion[0], quaternion[1], quaternion[2], quaternion[3]);
   LcLTransform3f rot3f(quaternion3f);
   LcLVec3f rot_dir = dir * rot3f;*/
	}
}
Esempio n. 21
0
// Deform the vertex array in classic linear way.
void fbxLoader2::ComputeLinearDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh,  FbxTime& pTime, FbxPose* pPose, int frame)
{
	// All the links must have the same link mode.
	FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();

	int lVertexCount = pMesh->GetControlPointsCount();
	FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount];
	memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix));

	double* lClusterWeight = new double[lVertexCount];
	memset(lClusterWeight, 0, lVertexCount * sizeof(double));

	if (lClusterMode == FbxCluster::eAdditive)
	{
		for (int i = 0; i < lVertexCount; ++i)
		{
			lClusterDeformation[i].SetIdentity();
		}
	}

	// For all skins and all clusters, accumulate their deformation and weight
	// on each vertices and store them in lClusterDeformation and lClusterWeight.
	int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);
	for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)
	{
		FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);
		
		int lClusterCount = lSkinDeformer->GetClusterCount();
		for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)
		{
			FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);
			if (!lCluster->GetLink())
				continue;

			FbxAMatrix lVertexTransformMatrix;

			ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, frame);

			//lVertexTransformMatrix.Transpose();
			FbxAMatrix identityM;
			identityM.SetIdentity();

			FbxVector4 rotation = lVertexTransformMatrix.GetROnly();
			FbxVector4 translation = lVertexTransformMatrix.GetT();
			FbxVector4 scaling = lVertexTransformMatrix.GetS();

			//rotation = FbxVector4(rotation.mData[0], rotation.mData[1], rotation.mData[2], rotation.mData[3]);
			//translation = FbxVector4 (translation.mData[0], translation.mData[1], translation.mData[2], translation.mData[3]);
			//scaling = FbxVector4 (scaling.mData[0], scaling.mData[1], scaling.mData[2], scaling.mData[3]);

			//lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling);			
			//lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling);	


			identityM = lVertexTransformMatrix * identityM;

			D3DXMATRIX convert = D3DXMATRIX(1,0,0,0,
											0,0,1,0,
											0,1,0,0,
											0,0,0,1);

			D3DXMATRIX setMatrix = D3DXMATRIX(	(float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0],
												(float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1],
												(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2],
												(float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3],1);

			//setMatrix *=0.5f;

			setMatrix = D3DXMATRIX(	(float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0],
									(float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1],
									//(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[1],
									(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2],
									(float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3], 1);

			//setMatrix = setMatrix*convert;

			///////// juz prawie dziala. sprawdz jeszcze te addytywne itp.
			/// generalnie dodaj to do włosów i dorzuć poprzednią macierz, żeby liczyć przesunięcia.


			//setMatrix /= 2.54f; //skala jedna jest w cm, druga w inchach, nieważne czy zmieniam system skali ręcznie... bzdurka fbxa
			

			std::string nametype = lCluster->GetLink()->GetName();	

			animationStructure->GetSkeleton(frame)->GetBone(animationStructure->GetSkeleton(frame)->GetBoneByName(lCluster->GetLink()->GetName()))->SetTransformation(setMatrix);
		}//lClusterCount
	}

	delete [] lClusterDeformation;
	delete [] lClusterWeight;
}
Esempio n. 22
0
//Compute the transform matrix that the cluster will transform the vertex.
void compute_cluster_deformation(FbxAMatrix& pGlobalPosition,
                                 FbxMesh* pMesh,
                                 FbxCluster* pCluster,
                                 FbxAMatrix& pVertexTransformMatrix,
                                 FbxTime pTime,
                                 FbxPose* pPose)
{
  FbxCluster::ELinkMode lClusterMode = pCluster->GetLinkMode();

  FbxAMatrix lReferenceGlobalInitPosition;
  FbxAMatrix lReferenceGlobalCurrentPosition;
  FbxAMatrix lAssociateGlobalInitPosition;
  FbxAMatrix lAssociateGlobalCurrentPosition;
  FbxAMatrix lClusterGlobalInitPosition;
  FbxAMatrix lClusterGlobalCurrentPosition;

  FbxAMatrix lReferenceGeometry;
  FbxAMatrix lAssociateGeometry;
  FbxAMatrix lClusterGeometry;

  FbxAMatrix lClusterRelativeInitPosition;
  FbxAMatrix lClusterRelativeCurrentPositionInverse;

  if(lClusterMode == FbxCluster::eAdditive && pCluster->GetAssociateModel()) {
    pCluster->GetTransformAssociateModelMatrix(lAssociateGlobalInitPosition);
    // Geometric transform of the model
    lAssociateGeometry = get_geometry(pCluster->GetAssociateModel());
    lAssociateGlobalInitPosition *= lAssociateGeometry;
    lAssociateGlobalCurrentPosition = get_global_position(pCluster->GetAssociateModel(), pTime, pPose);

    pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);
    // Multiply lReferenceGlobalInitPosition by Geometric Transformation
    lReferenceGeometry = get_geometry(pMesh->GetNode());
    lReferenceGlobalInitPosition *= lReferenceGeometry;
    lReferenceGlobalCurrentPosition = pGlobalPosition;

    // Get the link initial global position and the link current global position.
    pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
    // Multiply lClusterGlobalInitPosition by Geometric Transformation
    lClusterGeometry = get_geometry(pCluster->GetLink());
    lClusterGlobalInitPosition *= lClusterGeometry;
    lClusterGlobalCurrentPosition = get_global_position(pCluster->GetLink(), pTime, pPose);

    // Compute the shift of the link relative to the reference.
    //ModelM-1 * AssoM * AssoGX-1 * LinkGX * LinkM-1*ModelM
    pVertexTransformMatrix = lReferenceGlobalInitPosition.Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.Inverse() *
                             lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;
  } else {
    pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);
    lReferenceGlobalCurrentPosition = pGlobalPosition;
    // Multiply lReferenceGlobalInitPosition by Geometric Transformation
    lReferenceGeometry = get_geometry(pMesh->GetNode());
    lReferenceGlobalInitPosition *= lReferenceGeometry;

    // Get the link initial global position and the link current global position.
    pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
    lClusterGlobalCurrentPosition = get_global_position(pCluster->GetLink(), pTime, pPose);

    // Compute the initial position of the link relative to the reference.
    lClusterRelativeInitPosition = lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;

    // Compute the current position of the link relative to the reference.
    lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition;

    // Compute the shift of the link relative to the reference.
    pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition;
  }
}
Esempio n. 23
0
// Deform the vertex array in Dual Quaternion Skinning way.
void compute_dual_quaternion_deformation(FbxAMatrix& pGlobalPosition,
    FbxMesh* pMesh,
    FbxTime& pTime,
    FbxVector4* pVertexArray,
    FbxPose* pPose)
{
  // All the links must have the same link mode.
  FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();

  int lVertexCount = pMesh->GetControlPointsCount();
  int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);

  FbxDualQuaternion* lDQClusterDeformation = new FbxDualQuaternion[lVertexCount];
  memset(lDQClusterDeformation, 0, lVertexCount * sizeof(FbxDualQuaternion));

  double* lClusterWeight = new double[lVertexCount];
  memset(lClusterWeight, 0, lVertexCount * sizeof(double));

  // For all skins and all clusters, accumulate their deformation and weight
  // on each vertices and store them in lClusterDeformation and lClusterWeight.
  for(int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) {
    FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);
    int lClusterCount = lSkinDeformer->GetClusterCount();

    for(int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) {
      FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);

      if(!lCluster->GetLink()) {
        continue;
      }

      FbxAMatrix lVertexTransformMatrix;
      compute_cluster_deformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose);

      FbxQuaternion lQ = lVertexTransformMatrix.GetQ();
      FbxVector4 lT = lVertexTransformMatrix.GetT();
      FbxDualQuaternion lDualQuaternion(lQ, lT);

      int lVertexIndexCount = lCluster->GetControlPointIndicesCount();

      for(int k = 0; k < lVertexIndexCount; ++k) {
        int lIndex = lCluster->GetControlPointIndices()[k];

        // Sometimes, the mesh can have less points than at the time of the skinning
        // because a smooth operator was active when skinning but has been deactivated during export.
        if(lIndex >= lVertexCount) {
          continue;
        }

        double lWeight = lCluster->GetControlPointWeights()[k];

        if(lWeight == 0.0) {
          continue;
        }

        // Compute the influence of the link on the vertex.
        FbxDualQuaternion lInfluence = lDualQuaternion * lWeight;

        if(lClusterMode == FbxCluster::eAdditive) {
          // Simply influenced by the dual quaternion.
          lDQClusterDeformation[lIndex] = lInfluence;

          // Set the link to 1.0 just to know this vertex is influenced by a link.
          lClusterWeight[lIndex] = 1.0;
        } else { // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne
          if(lClusterIndex == 0) {
            lDQClusterDeformation[lIndex] = lInfluence;
          } else {
            // Add to the sum of the deformations on the vertex.
            // Make sure the deformation is accumulated in the same rotation direction.
            // Use dot product to judge the sign.
            double lSign = lDQClusterDeformation[lIndex].GetFirstQuaternion().DotProduct(lDualQuaternion.GetFirstQuaternion());

            if(lSign >= 0.0) {
              lDQClusterDeformation[lIndex] += lInfluence;
            } else {
              lDQClusterDeformation[lIndex] -= lInfluence;
            }
          }

          // Add to the sum of weights to either normalize or complete the vertex.
          lClusterWeight[lIndex] += lWeight;
        }
      }//For each vertex
    }//lClusterCount
  }

  //Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight
  for(int i = 0; i < lVertexCount; i++) {
    FbxVector4 lSrcVertex = pVertexArray[i];
    FbxVector4& lDstVertex = pVertexArray[i];
    double lWeightSum = lClusterWeight[i];

    // Deform the vertex if there was at least a link with an influence on the vertex,
    if(lWeightSum != 0.0) {
      lDQClusterDeformation[i].Normalize();
      lDstVertex = lDQClusterDeformation[i].Deform(lDstVertex);

      if(lClusterMode == FbxCluster::eNormalize) {
        // In the normalized link mode, a vertex is always totally influenced by the links.
        lDstVertex /= lWeightSum;
      } else if(lClusterMode == FbxCluster::eTotalOne) {
        // In the total 1 link mode, a vertex can be partially influenced by the links.
        lSrcVertex *= (1.0 - lWeightSum);
        lDstVertex += lSrcVertex;
      }
    }
  }

  delete [] lDQClusterDeformation;
  delete [] lClusterWeight;
}
void MeshImporter::LoadWeight(FbxMesh* fbxMesh, MeshEntry* mesh)
{
	int numSkin = fbxMesh->GetDeformerCount(FbxDeformer::eSkin);
	
	if (numSkin == 0)
	{
		return;
	}

	assert(numSkin == 1);

	// Assume only one deformer
	FbxSkin* fbxSkin = static_cast<FbxSkin*>(fbxMesh->GetDeformer(0, FbxDeformer::eSkin));
	int numCluster = fbxSkin->GetClusterCount();
	int numControlPoints = fbxMesh->GetControlPointsCount();
	vector<VertexWeight> tmpWeightList(numControlPoints);

	for (int i = 0; i < numCluster; i++)
	{
		FbxCluster* fbxCluster = fbxSkin->GetCluster(i);

		if (!fbxCluster->GetLink())
		{
			continue;
		}

		unsigned int boneIndex = model->skeleton->bones.size();

		assert(fbxCluster->GetLinkMode() == FbxCluster::eNormalize);

		// Read skeleton bones data (transformation matrix of each bone)
		string boneName(fbxCluster->GetLink()->GetName());

		if (!model->skeleton->FindBoneByName(boneName))
		{
			if (boneIndex >= MAXBONE)
			{
				PrintTab("Too many bones to load!!");
			}
			else
			{
				// Read weights of each vertex
				int numIndexInCluster = fbxCluster->GetControlPointIndicesCount();
				int* indicesInCluster = fbxCluster->GetControlPointIndices();
				double* weights = fbxCluster->GetControlPointWeights();

				for (int j = 0; j < numIndexInCluster; j++)
				{
					tmpWeightList[indicesInCluster[j]].AddBoneData(boneIndex, weights[j]);
				}

				// Normalize weights
				/*for (int inVert = 0; inVert < tmpWeightList.size(); inVert++)
				{
					tmpWeightList[inVert].Normalize();
				}*/

				// Read animation bone matrix
				FbxAMatrix fbxGlobalBoneBaseMatrix;// = fbxCluster->GetLink()->EvaluateGlobalTransform().Inverse().Transpose();

				FbxAMatrix referenceGlobalInitPosition;
				FbxAMatrix clusterGlobalInitPosition;

				fbxCluster->GetTransformMatrix(referenceGlobalInitPosition);
				fbxCluster->GetTransformLinkMatrix(clusterGlobalInitPosition);

				fbxGlobalBoneBaseMatrix = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition;

				// To be considered when importing Maya fbx model
				//FbxAMatrix geoMatrix = GetTransformMatrix(fbxCluster->GetLink());

				Bone bone;
				bone.name = boneName;
				bone.boneIndex = boneIndex;
				bone.fbxNode = fbxCluster->GetLink();
				bone.globalBindposeInverseMatrix = fbxGlobalBoneBaseMatrix;

				model->skeleton->bones.push_back(bone);
			}
		}
	}

	// Deployed in the index
	for (unsigned int i = 0; i < mesh->numVertices; i++)
	{
		mesh->vertices[i].boneIndices.x = tmpWeightList[mesh->indices[i]].boneWeight[0].first;
		mesh->vertices[i].boneIndices.y = tmpWeightList[mesh->indices[i]].boneWeight[1].first;
		mesh->vertices[i].boneIndices.z = tmpWeightList[mesh->indices[i]].boneWeight[2].first;
		mesh->vertices[i].boneIndices.w = tmpWeightList[mesh->indices[i]].boneWeight[3].first;

		mesh->vertices[i].weights.x = tmpWeightList[mesh->indices[i]].boneWeight[0].second;
		mesh->vertices[i].weights.y = tmpWeightList[mesh->indices[i]].boneWeight[1].second;
		mesh->vertices[i].weights.z = tmpWeightList[mesh->indices[i]].boneWeight[2].second;
		mesh->vertices[i].weights.w = tmpWeightList[mesh->indices[i]].boneWeight[3].second;
	}
}
Esempio n. 25
0
//FbxAMatrix ComputeTotalMatrix(FbxNode* node, FbxTime time = FBXSDK_TIME_INFINITE){
//
//}
SkinInfo::SkinInfo(FbxNode* meshNode) :
_node(meshNode), _mesh(meshNode->GetMesh()), _skin(nullptr)
{
	int deformerCount = _mesh->GetDeformerCount();
	for (auto ix = 0; ix < deformerCount; ++ix){
		auto skin = reinterpret_cast<FbxSkin*>(_mesh->GetDeformer(ix, FbxDeformer::eSkin));
		if (skin){
			_skin = skin;
			break;
		}
	}
	if (!_skin){
		return;
	}

	std::vector<FbxPose*> bindPoses;
	auto poseCount = _node->GetScene()->GetPoseCount();
	for (auto ix = 0; ix < poseCount; ++ix){
		auto pose = _node->GetScene()->GetPose(ix);
		if (pose->IsBindPose()){
			bindPoses.push_back(pose);
		}
	}

	std::vector<FbxNode*> unsortedFlatListOfNodes;
	std::vector<FbxCluster*> unsortedFlatListOfClusters;
	auto clusterCount = _skin->GetClusterCount();
	for (auto ix = 0; ix < clusterCount; ++ix){
		auto cluster = _skin->GetCluster(ix);
		if (!cluster)
		{
			std::cout << "Invalid skin" << std::endl;
			_skin = nullptr;
			return;
		}
		auto linkNode = cluster->GetLink();
		if (!linkNode){
			std::cout << "Invalid skin" << std::endl;
			_skin = nullptr;
			return;
		}
		unsortedFlatListOfClusters.push_back(cluster);
		unsortedFlatListOfNodes.push_back(linkNode);
	}

	ComputeBoneHierarchy(unsortedFlatListOfNodes, unsortedFlatListOfClusters, _bones, _fbxClusterIndexToBoneIndex, _controlPointToBoneIndicesAndWeights);
	auto deformType = _skin->GetDeformerType();

	auto geometryTransform = GetGeometryTransformation(meshNode);
	// compute all bones global inverse and global matrix
	for (auto& bone : _bones){
		FbxAMatrix transformMatrix;
		FbxAMatrix transformLinkMatrix;
		FbxMatrix globalBindposeInverseMatrix;

		bone.cluster->GetTransformMatrix(transformMatrix);	// The transformation of the mesh at binding time
		bone.cluster->GetTransformLinkMatrix(transformLinkMatrix);	// The transformation of the cluster(joint) at binding time from joint space to world space
		/*for (auto pose : bindPoses){
			auto inPoseIndex = pose->Find(bone.linkNode);
			if (inPoseIndex >= 0){
				auto tempMat = pose->GetMatrix(inPoseIndex);
				transformLinkMatrix = *(FbxAMatrix*) (double*) &tempMat;
				break;
			}
		}*/
		globalBindposeInverseMatrix = FbxMatrix(transformLinkMatrix.Inverse()) * FbxMatrix(transformMatrix) * geometryTransform;


		bone.matrixGlobalBindPose = ConvertToBabylonCoordinateSystem(globalBindposeInverseMatrix.Inverse());
	

		if (bone.parentBoneIndex == -1){
			bone.matrixLocalBindPose = bone.matrixGlobalBindPose;
		}
		else{
			bone.matrixLocalBindPose =
				_bones[bone.parentBoneIndex].matrixGlobalBindPose.Inverse()* bone.matrixGlobalBindPose;
			
		}
	}


	// compute anim
	auto animStack = _node->GetScene()->GetCurrentAnimationStack();
	FbxString animStackName = animStack->GetName();
	//FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
	auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
	auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
	auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
	auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
	auto animLengthInFrame = endFrame - startFrame + 1;


	for (auto ix = 0; ix < animLengthInFrame; ix++){
		FbxTime currTime;
		currTime.SetFrame(startFrame + ix, animTimeMode);


		auto currTransformOffset = FbxMatrix(meshNode->EvaluateGlobalTransform(currTime)) * geometryTransform;
		auto currTransformOffsetInverse = currTransformOffset.Inverse();

		// compute global transform and local
		for (auto& bone : _bones){
			BoneAnimKeyFrame kf;
			kf.frame = ix;
			kf.matrixGlobal = ConvertToBabylonCoordinateSystem(currTransformOffsetInverse*bone.linkNode->EvaluateGlobalTransform(currTime));
			


			if (bone.parentBoneIndex == -1){
				kf.matrixLocal = kf.matrixGlobal;
			}
			else{
				auto& parentBone = _bones[bone.parentBoneIndex];
				
				kf.matrixLocal = //bone.matrixLocalBindPose;
					parentBone.keyFrames[parentBone.keyFrames.size() - 1].matrixGlobal.Inverse()* kf.matrixGlobal;

			}


			bone.keyFrames.push_back(kf);
		}

	}
}
Esempio n. 26
0
MeshData* FBXImporter::GetMeshInfo()
{
	mMeshData = new MeshData();

	int indicesIndexOffset = 0;		// 记录当前mesh在整个ib中的索引位移。
	int verticesIndexOffset = 0;	// 记录当前mesh在整个vb中的顶点位移。

	for (int meshIndex = 0; meshIndex < mFBXMeshDatas.size(); meshIndex++)
	{
		FbxMesh* mesh = mFBXMeshDatas[meshIndex]->mMesh;
		FBXMeshData* fbxMeshData = mFBXMeshDatas[meshIndex];
		fbxMeshData->mVerticesCount = mesh->GetControlPointsCount();
		fbxMeshData->mIndicesCount = mesh->GetPolygonVertexCount();
		fbxMeshData->mTrianglesCount = mesh->GetPolygonCount();

		// 获取3dsmax中的全局变换矩阵,稍后可以在DX中还原。
		FbxMatrix gloableTransform = mesh->GetNode()->EvaluateGlobalTransform();

		FbxAMatrix matrixGeo;
		matrixGeo.SetIdentity();

		const FbxVector4 lT = mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot);
		const FbxVector4 lR = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot);
		const FbxVector4 lS = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot);

		matrixGeo.SetT(lT);
		matrixGeo.SetR(lR);
		matrixGeo.SetS(lS);

		FbxAMatrix matrixL2W;
		matrixL2W.SetIdentity();

		matrixL2W = mesh->GetNode()->EvaluateGlobalTransform();

		matrixL2W *= matrixGeo;

		XMMATRIX globalTransform = XMLoadFloat4x4(&fbxMeshData->globalTransform);
		FbxMatrixToXMMATRIX(globalTransform, matrixL2W);
		XMStoreFloat4x4(&fbxMeshData->globalTransform, globalTransform);

		// 读取顶点。
		ReadVertices(fbxMeshData);
		// 读取索引。
		ReadIndices(fbxMeshData);

		// 先读取网格对应的材质索引信息,以便优化稍后纹理读取。
		// 一个网格可能只对应一个materialId,也可能对应多个materialId(3dsmax里的Multi/Sub-Object材质)。
		// 如果只对应一个材质,简单的读取就行,不过普遍情况可能是为了优化渲染合并mesh从而拥有多材质。
		// 这个函数调用完毕我们会得到materialId和拥有这个materialId的三角形列表(三角形编号列表),保存在vector<MaterialIdOffset>的容器中。
		//struct Material
		//{
		//	Material() {}
		//	Material(int id, string diffuse, string normalMap)
		//		: materialId(id),
		//		diffuseTextureFile(diffuse),
		//		normalMapTextureFile(normalMap)
		//	{}
		//
		//	int materialId;
		//	string diffuseTextureFile;
		//	string normalMapTextureFile;
		//};
		// struct MaterialIdOffset
		//{
		//	MaterialIdOffset()
		//		: polygonCount(0)
		//	{}
		//	int polygonCount;
		//	Material material;
		//};
		ConnectMaterialsToMesh(mesh, fbxMeshData->mTrianglesCount);

		// 根据ConnectMaterialsToMesh得到的信息读取材质纹理信息,同样存入vector<MaterialIdOffset>容器。
		LoadMaterials(fbxMeshData);

		int triangleCount = mesh->GetPolygonCount();
		int controlPointIndex = 0;
		int normalIndex = 0;
		fbxMeshData->mUVs.resize(fbxMeshData->mIndicesCount, XMFLOAT2(-1.0f, -1.0f));

		// Extract normals and uvs from FbxMesh.
		for (int i = 0; i < triangleCount; i++)
		{
			int polygonSize = mesh->GetPolygonSize(i);

			for (int j = 0; j < polygonSize; j++)
			{ 
				controlPointIndex = mesh->GetPolygonVertex(i, j);

				ReadNormals(fbxMeshData, controlPointIndex, normalIndex);

				// 有纹理我们才读取uv,tangent以及binormal。
				if (fbxMeshData->hasDiffuseTexture())
				{
					ReadUVs(fbxMeshData, controlPointIndex, normalIndex, mesh->GetTextureUVIndex(i, j), 0);
					ReadTangents(fbxMeshData, controlPointIndex, normalIndex);
					ReadBinormals(fbxMeshData, controlPointIndex, normalIndex);
				}

				normalIndex++;
			}
		}

		SplitVertexByNormal(fbxMeshData);

		if (fbxMeshData->hasDiffuseTexture())
		{
			SplitVertexByUV(fbxMeshData);
		}
		else
		{
			fbxMeshData->mUVs.resize(fbxMeshData->mVerticesCount);
		}

		if (fbxMeshData->hasNormalMapTexture())
		{
			SplitVertexByTangent(fbxMeshData);
			SplitVertexByBinormal(fbxMeshData);
		}
		else
		{
			fbxMeshData->mTangents.resize(fbxMeshData->mVerticesCount);
			fbxMeshData->mBinormals.resize(fbxMeshData->mVerticesCount);
		}

		// 如果.fbx包含一个以上的mesh,需要计算当前FBXMeshData的索引在全局索引中的位置。
		for (int i = 0; i < fbxMeshData->mIndicesCount; i++)
		{
			fbxMeshData->mIndices[i] = fbxMeshData->mIndices[i] + verticesIndexOffset;
		}

		mMeshData->verticesCount += fbxMeshData->mVerticesCount;
		mMeshData->indicesCount += fbxMeshData->mIndicesCount;
		mMeshData->meshesCount++;

		// 多材质的情况。
		// 根据之前填充的materialIdOffsets容器保存的materialId和三角形的对应关系,
		// 计算每个RenderPackage渲染所需的索引数量和索引起始位置(偏移)。
		if (isByPolygon && fbxMeshData->hasDiffuseTexture())
		{
			vector<MaterialIdOffset> materialIdOffsets = mMeshData->materialIdOffsets;

			for (int i = 0; i < materialIdOffsets.size(); i++)
			{
				RenderPackage renderPacakge;
				renderPacakge.globalTransform = fbxMeshData->globalTransform;
				renderPacakge.indicesCount = materialIdOffsets[i].polygonCount * 3;
	
				if (i == 0)
				{
					renderPacakge.indicesOffset = indicesIndexOffset;
				}
				else
				{
					renderPacakge.indicesOffset += indicesIndexOffset;
				}

				renderPacakge.material = materialIdOffsets[i].material;

				mMeshData->renderPackages.push_back(renderPacakge);

				indicesIndexOffset += renderPacakge.indicesCount;
			}
		}
		else
		// 单一材质的情况。
		{
			RenderPackage renderPackage;
			renderPackage.indicesCount = fbxMeshData->mIndicesCount;
			renderPackage.indicesOffset = indicesIndexOffset;
			renderPackage.material = fbxMeshData->mMaterial;
			renderPackage.globalTransform = fbxMeshData->globalTransform;

			mMeshData->renderPackages.push_back(renderPackage);

			indicesIndexOffset += fbxMeshData->mIndices.size();
		}

		verticesIndexOffset += fbxMeshData->mVertices.size();

		// 将当前mesh的数据追加到全局数据容器。
		Merge(mMeshData->vertices, fbxMeshData->mVertices);
		Merge(mMeshData->indices, fbxMeshData->mIndices);
		Merge(mMeshData->normals, fbxMeshData->mNormals);
		Merge(mMeshData->uvs, fbxMeshData->mUVs);
		Merge(mMeshData->tangents, fbxMeshData->mTangents);
		Merge(mMeshData->binormals, fbxMeshData->mBinormals);

		mMeshData->materialIdOffsets.clear();
	}

	clear();

	return mMeshData;
}
Esempio n. 27
0
		void FbxLoader::ProcessBoneAndAnimation(FbxNode* node, Node& meshNode)
		{
			auto currMesh = node->GetMesh();
			if(!currMesh) return;

			FbxVector4 lT = node->GetGeometricTranslation(FbxNode::eSourcePivot);
			FbxVector4 lR = node->GetGeometricRotation(FbxNode::eSourcePivot);
			FbxVector4 lS = node->GetGeometricScaling(FbxNode::eSourcePivot);

			FbxAMatrix geometryTransform = FbxAMatrix(lT, lR, lS);

			FbxSkin* skin = nullptr;
			const int deformerCnt = currMesh->GetDeformerCount();
			for(int deformerIndex = 0; deformerIndex < deformerCnt; ++deformerIndex) {
				skin = (FbxSkin*)(currMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
				if(skin) break;
			}
			if(!skin) return;

			meshNode.useSkinnedMesh = true;
			const size_t nClusters = skin->GetClusterCount();
			if(nClusters < 1) return;

			for(auto& clip : animationClips)
				clip.second->transformCurves.resize(nClusters);

			meshNode.bones.resize(nClusters);
			const int animCount = scene->GetSrcObjectCount<FbxAnimStack>();

			float time = 0;
			for(int ci = 0; ci < nClusters; ++ci) {
				FbxCluster* cluster = skin->GetCluster(ci);
				auto elink = cluster->GetLinkMode();
				std::string boneName = cluster->GetLink()->GetName();

				FbxAMatrix transformMatrix, transformLinkMatrix, globalBindposeInverse;
				cluster->GetTransformMatrix(transformMatrix);
				cluster->GetTransformLinkMatrix(transformLinkMatrix);
				globalBindposeInverse = transformLinkMatrix.Inverse() * geometryTransform * transformMatrix;

				FbxNode* boneNode = cluster->GetLink();
				Bone& bone = meshNode.bones[ci];
				bone.name = boneName;
				bone.index = ci;

				auto T = globalBindposeInverse.GetT() * factor;
				
				if(axismode == eLeftHanded) {
					auto R = globalBindposeInverse.GetR();
					T[0] *= -1; R[1] *= -1; R[2] *= -1;
					globalBindposeInverse.SetR(R);
				}
				globalBindposeInverse.SetT(T);

				ConvertMatrix(bone.bindPoseInverse, globalBindposeInverse);

				const int nCtrl = cluster->GetControlPointIndicesCount();

				for(int ctrlIndex = 0; ctrlIndex < nCtrl; ++ctrlIndex) {
					BlendWeightPair pair;
					pair.boneIndex = ci;
					pair.weight = (float)cluster->GetControlPointWeights()[ctrlIndex];
					meshNode.controlPoints[cluster->GetControlPointIndices()[ctrlIndex]].blendWeigths.push_back(pair);
				}

				FbxAMatrix preRot;
				auto preR = boneNode->GetPreRotation(FbxNode::eSourcePivot);
				preRot.SetR(preR);

				for(int ai = 0; ai < animCount; ++ai) {
					auto animStack = scene->GetSrcObject<FbxAnimStack>(ai);
					scene->SetCurrentAnimationStack(animStack);
					std::string animName = animStack->GetName();
					auto& clip = animationClips[animName];
					auto& transformCurve = clip->transformCurves[ci];
					transformCurve.boneName = boneName;
					transformCurve.begin = 0;

					auto animLayer = animStack->GetMember<FbxAnimLayer>(0);
					FbxAnimCurve* fbxTCurves[3];
					FbxAnimCurve* fbxRCurves[3];
					FbxAnimCurve* fbxSCurves[3];

					fbxTCurves[0] = boneNode->LclTranslation.GetCurve(animLayer, "X");

					if(!fbxTCurves[0])
						continue;
					
					fbxTCurves[1] = boneNode->LclTranslation.GetCurve(animLayer, "Y");
					fbxTCurves[2] = boneNode->LclTranslation.GetCurve(animLayer, "Z");

					fbxRCurves[0] = boneNode->LclRotation.GetCurve(animLayer, "X");
					fbxRCurves[1] = boneNode->LclRotation.GetCurve(animLayer, "Y");
					fbxRCurves[2] = boneNode->LclRotation.GetCurve(animLayer, "Z");

					fbxSCurves[0] = boneNode->LclScaling.GetCurve(animLayer, "X");
					fbxSCurves[1] = boneNode->LclScaling.GetCurve(animLayer, "Y");
					fbxSCurves[2] = boneNode->LclScaling.GetCurve(animLayer, "Z");

					// set & apply filter
					FbxAnimCurveFilterKeyReducer keyReducer;
					keyReducer.SetKeySync(false);
					keyReducer.Apply(fbxTCurves, 3);
					keyReducer.Apply(fbxSCurves, 3);
					keyReducer.SetKeySync(true);
					keyReducer.Apply(fbxRCurves, 3);

					FbxAnimCurveFilterUnroll unroll;
					unroll.SetForceAutoTangents(true);
					unroll.Apply(fbxRCurves, 3);

					FbxAnimCurveFilterTSS tss;
					FbxTime tt;
					tt.SetSecondDouble(-fbxTCurves[0]->KeyGetTime(0).GetSecondDouble());
					tss.SetShift(tt);
					tss.Apply(fbxTCurves, 3);
					tss.Apply(fbxRCurves, 3);
					tss.Apply(fbxSCurves, 3);
					//

					// process curves
					if(fbxTCurves[0]->KeyGetCount() > 0) {
						ProcessAnimCurveT(fbxTCurves, transformCurve);
						ProcessAnimCurveS(fbxSCurves, transformCurve);
						ProcessAnimCurveR(fbxRCurves, transformCurve, preRot);

						//clamping by reduced keyframes
						clip->startTime = 0;
						clip->lengthInSeconds = transformCurve.end;
						clip->lengthInFrames = (int)(1.5f + (transformCurve.end / (1 / 30.0f)));
					}
				} // animations loop
			} // cluster loop
		}
Esempio n. 28
0
void FBXSceneEncoder::transformNode(FbxNode* fbxNode, Node* node)
{
    FbxAMatrix matrix;
    float m[16];
    
    if (fbxNode->GetCamera() || fbxNode->GetLight())
    {
        FbxAMatrix rotateAdjust;
        
        if(fbxNode->GetLight())
        {
            /*
             * according to the fbx-documentation the light's forward vector
             * points along a node's negative Y axis.
             * so we have to rotate it by 90° around the X-axis to correct it.
             */
            if(fbxNode->RotationActive.Get())
            {
                const FbxVector4& postRotation = fbxNode->PostRotation.Get();
                fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0] + 90.0,
                                                                           postRotation.mData[1],
                                                                           postRotation.mData[2])
                                         );
            }
            else
            {
                // if the rotation is deactivated we have to rotate it anyway to get the correct transformation in the end
                rotateAdjust.SetR(FbxVector4(-90.0, 0.0, 0.0));
            }
            
            matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust;
        }
        else if(fbxNode->GetCamera())
        {
			/*
			* according to the fbx-documentation the camera's forward vector
			* points along a node's positive X axis.
			* so we have to rotate it by 90 around the Y-axis to correct it.
			*/
			if (fbxNode->RotationActive.Get())
			{
				const FbxVector4& postRotation = fbxNode->PostRotation.Get();
				fbxNode->SetPostRotation(FbxNode::eSourcePivot, FbxVector4(postRotation.mData[0],
					postRotation.mData[1] + 90.0,
					postRotation.mData[2]));
			}
			else
			{
				// usually for the fbx-exporter in Blender 2.75
				// if rotation is deactivated we have to rotate the local transform in 90°
				rotateAdjust.SetR(FbxVector4(0, 90.0, 0.0));
			}

			matrix = fbxNode->EvaluateLocalTransform() * rotateAdjust;
        }
        
        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
    else
    {
        matrix = fbxNode->EvaluateLocalTransform();
        copyMatrix(matrix, m);
        node->setTransformMatrix(m);
    }
}
Esempio n. 29
0
    bool Submesh::load(FbxNode* pNode, FbxMesh* pMesh, const std::vector<face>& faces, const std::vector<vertexInfo>& vertInfo, const std::vector<FbxVector4>& points, 
        const std::vector<FbxVector4>& normals, const std::vector<int>& texcoordsets, ParamList& params, const FbxAMatrix& bindPose, bool opposite )
    {
        //save the mesh from which this submesh will be created
        m_pNode = pNode;

        size_t i,j,k;
        FxOgreFBXLog( "Loading submesh associated to material: %s ...\n", m_pMaterial->name().c_str());
        
        //save uvsets info
        for (i=m_uvsets.size(); i<texcoordsets.size(); i++)
        {
            uvset uv;
            uv.size = 2;
            m_uvsets.push_back(uv);
        }
        //iterate over faces array, to retrieve vertices info
        for (i=0; i<faces.size(); i++)
        {
            face newFace;
            // if we are using shared geometry, indexes refer to the vertex buffer of the whole mesh
            if (params.useSharedGeom)
            {
                if(opposite)
                {	// reverse order of face vertices for correct culling
                    newFace.v[0] = faces[i].v[2];
                    newFace.v[1] = faces[i].v[1];
                    newFace.v[2] = faces[i].v[0];
                }
                else
                {
                    newFace.v[0] = faces[i].v[0];
                    newFace.v[1] = faces[i].v[1];
                    newFace.v[2] = faces[i].v[2];
                }
            }
            // otherwise we create a vertex buffer for this submesh
            else
            {	// faces are triangles, so retrieve index of the three vertices
                for (j=0; j<3; j++)
                {
                    vertex v;
                    vertexInfo vInfo = vertInfo[faces[i].v[j]];
                    // save vertex coordinates (rescale to desired length unit)
                    assert(vInfo.pointIdx >= 0 && vInfo.pointIdx < static_cast<int>(points.size()));
                    FbxVector4 point = points[vInfo.pointIdx] * params.lum;
                    if (fabs(point[0]) < PRECISION)
                        point[0] = 0;
                    if (fabs(point[1]) < PRECISION)
                        point[1] = 0;
                    if (fabs(point[2]) < PRECISION)
                        point[2] = 0;
                    v.x = point[0];
                    v.y = point[1];
                    v.z = point[2];
                    // save vertex normal
                    assert(vInfo.normalIdx >= 0 && vInfo.normalIdx < static_cast<int>(normals.size()));
                    FbxVector4 normal = normals[vInfo.normalIdx];
                    if (fabs(normal[0]) < PRECISION)
                        normal[0] = 0;
                    if (fabs(normal[1]) < PRECISION)
                        normal[1] = 0;
                    if (fabs(normal[2]) < PRECISION)
                        normal[2] = 0;
                    v.n.x = normal[0];
                    v.n.y = normal[1];
                    v.n.z = normal[2];
                    if (opposite)
                    {
                        // Reversing the winding order appears to be sufficent.
                        v.n.x = -normal[0];
                        v.n.y = -normal[1];
                        v.n.z = -normal[2];
                    }
                    v.n.Normalize();

                    // save vertex color
                    v.r = vInfo.r;
                    v.g = vInfo.g;
                    v.b = vInfo.b;
                    v.a = vInfo.a;
                    // save vertex bone assignements
                    for (k=0; k<vInfo.vba.size(); k++)
                    {
                        vba newVba;
                        newVba.jointIdx = vInfo.jointIds[k];
                        newVba.weight = vInfo.vba[k];
                        v.vbas.push_back(newVba);
                    }
                    // save texture coordinates
                    for (k=0; k<vInfo.u.size(); k++)
                    {
                        texcoord newTexCoords;
                        newTexCoords.u = vInfo.u[k];
                        newTexCoords.v = vInfo.v[k];
                        newTexCoords.w = 0;
                        v.texcoords.push_back(newTexCoords);
                    }
                    // save vertex index in mesh, to retrieve future positions of the same vertex
                    v.index = vInfo.pointIdx;
                    // add newly created vertex to vertex list
                    m_vertices.push_back(v);
                    if (opposite)	// reverse order of face vertices to get correct culling
                        newFace.v[2-j] = static_cast<int>(m_vertices.size()) - 1;
                    else
                        newFace.v[j] = static_cast<int>(m_vertices.size()) - 1;
                }
            }
            m_faces.push_back(newFace);
        }
        // set use32bitIndexes flag
        if (params.useSharedGeom || (m_vertices.size() > 65535) || (m_faces.size() > 65535))
            m_use32bitIndexes = true;
        else
            m_use32bitIndexes = false;

        pMesh->ComputeBBox();
        FbxDouble3 minDouble = pMesh->BBoxMin.Get();
        FbxDouble3 maxDouble = pMesh->BBoxMax.Get();

        FbxVector4 min = bindPose.MultT( FbxVector4(minDouble[0],minDouble[1],minDouble[2],0));
        FbxVector4 max = bindPose.MultT( FbxVector4(maxDouble[0],maxDouble[1],maxDouble[2],0));

        m_bbox.merge(Point3(max[0], max[1], max[2]));
        m_bbox.merge(Point3(min[0], min[1], min[2]));
        

        // add submesh pointer to m_params list
        params.loadedSubmeshes.push_back(this);

        FxOgreFBXLog( "DONE\n");
        
        return true;
    }
Esempio n. 30
0
//Compute the transform matrix that the cluster will transform the vertex.
void ofxFBXMesh::computeClusterDeformation(FbxAMatrix& pGlobalPosition,
                                           FbxMesh* pMesh,
                                           FbxCluster* pCluster,
                                           FbxAMatrix& pVertexTransformMatrix,
                                           FbxTime pTime,
                                           FbxPose* pPose) {
    FbxCluster::ELinkMode lClusterMode = pCluster->GetLinkMode();
    
	FbxAMatrix lReferenceGlobalInitPosition;
	FbxAMatrix lReferenceGlobalCurrentPosition;
	FbxAMatrix lAssociateGlobalInitPosition;
	FbxAMatrix lAssociateGlobalCurrentPosition;
	FbxAMatrix lClusterGlobalInitPosition;
	FbxAMatrix lClusterGlobalCurrentPosition;
    
	FbxAMatrix lReferenceGeometry;
	FbxAMatrix lAssociateGeometry;
	FbxAMatrix lClusterGeometry;
    
	FbxAMatrix lClusterRelativeInitPosition;
	FbxAMatrix lClusterRelativeCurrentPositionInverse;
    
    ofxFBXBone* bone        = NULL;
    ofxFBXCluster* cluster  = NULL; 
    
    if(pCluster->GetLink()) {
        FbxNode* boneNode = pCluster->GetLink();
        if(boneNode->GetUserDataPtr()) {
            bone = static_cast<ofxFBXBone *>(boneNode->GetUserDataPtr());
        }
    }
    
    if(bone != NULL) {
        if(pCluster->GetUserDataPtr()) {
            cluster = static_cast<ofxFBXCluster *>(pCluster->GetUserDataPtr());
//            cluster->update( pTime, pPose );
        }
    }
    
    if( bone != NULL && cluster != NULL ) {
//        cout << "We have cached cluster and bone! " << bone->getName() << endl;
        pVertexTransformMatrix = cluster->preTrans * bone->fbxTransform * cluster->postTrans;
    } else {
        // nothing is setup for the control of the bones, so we are just doing animation
        // right now, can't do animation and control the bones at the same time.
        if (lClusterMode == FbxCluster::eAdditive && pCluster->GetAssociateModel()) {
            pCluster->GetTransformAssociateModelMatrix(lAssociateGlobalInitPosition);
            // Geometric transform of the model
            lAssociateGeometry = GetGeometry(pCluster->GetAssociateModel());
            lAssociateGlobalInitPosition *= lAssociateGeometry;
            lAssociateGlobalCurrentPosition = GetGlobalPosition(pCluster->GetAssociateModel(), pTime, pPose);
            
            pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);
            // Multiply lReferenceGlobalInitPosition by Geometric Transformation
            lReferenceGeometry = GetGeometry(pMesh->GetNode());
            lReferenceGlobalInitPosition *= lReferenceGeometry;
            lReferenceGlobalCurrentPosition = pGlobalPosition;
            
            // Get the link initial global position and the link current global position.
            pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
            // Multiply lClusterGlobalInitPosition by Geometric Transformation
            lClusterGeometry = GetGeometry(pCluster->GetLink());
            lClusterGlobalInitPosition *= lClusterGeometry;
            lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose);
            
            // Compute the shift of the link relative to the reference.
            //ModelM-1 * AssoM * AssoGX-1 * LinkGX * LinkM-1*ModelM
            pVertexTransformMatrix = lReferenceGlobalInitPosition.Inverse() * lAssociateGlobalInitPosition * lAssociateGlobalCurrentPosition.Inverse() *
            lClusterGlobalCurrentPosition * lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;
        } else {
            pCluster->GetTransformMatrix(lReferenceGlobalInitPosition);
            lReferenceGlobalCurrentPosition = pGlobalPosition;
            // Multiply lReferenceGlobalInitPosition by Geometric Transformation
            lReferenceGeometry = GetGeometry(pMesh->GetNode());
            lReferenceGlobalInitPosition *= lReferenceGeometry;
            
            // Get the link initial global position and the link current global position.
            pCluster->GetTransformLinkMatrix(lClusterGlobalInitPosition);
            lClusterGlobalCurrentPosition = GetGlobalPosition(pCluster->GetLink(), pTime, pPose);
            
            // Compute the initial position of the link relative to the reference.
            lClusterRelativeInitPosition = lClusterGlobalInitPosition.Inverse() * lReferenceGlobalInitPosition;
            
            // Compute the current position of the link relative to the reference.
            lClusterRelativeCurrentPositionInverse = lReferenceGlobalCurrentPosition.Inverse() * lClusterGlobalCurrentPosition;
            
            // Compute the shift of the link relative to the reference.
            pVertexTransformMatrix = lClusterRelativeCurrentPositionInverse * lClusterRelativeInitPosition;
        }
    }
}