void Model::ComputeLinearDeformation( KFbxMesh *mesh, KTime &time, KFbxVector4 *vertices, KFbxPose *pose ) {
	
	KFbxCluster::ELinkMode cluster_mode = ((KFbxSkin*)mesh->GetDeformer(0, KFbxDeformer::eSKIN))->GetCluster(0)->GetLinkMode();

	int cp_count = mesh->GetControlPointsCount();
	KFbxXMatrix *cluster_deformations = new KFbxXMatrix[cp_count];
	memset( cluster_deformations, 0, cp_count * sizeof( KFbxXMatrix ) );

	double *cluster_weights = new double[cp_count];
	memset( cluster_weights, 0, cp_count * sizeof( double ) );

	if( cluster_mode == KFbxCluster::eADDITIVE ) {
		for( int i = 0;i < cp_count; i++ ) {
			cluster_deformations[i].SetIdentity();
		}
	}

	int skin_count = mesh->GetDeformerCount(KFbxDeformer::eSKIN);
	for( int skin_index = 0; skin_index < skin_count; skin_index++ ) {
		KFbxSkin *skin_deformer = (KFbxSkin*)mesh->GetDeformer(skin_index,KFbxDeformer::eSKIN);

		int cluster_count = skin_deformer->GetClusterCount();
		for( int cluster_index = 0; cluster_index < cluster_count; cluster_index++ ) {
			KFbxCluster *cluster = skin_deformer->GetCluster(cluster_index);
			if( !cluster->GetLink() ) continue;

			KFbxXMatrix vertex_transform_matrix;
			ComputeClusterDeformation( mesh, cluster, vertex_transform_matrix, time, pose );

			int vertex_index_count = cluster->GetControlPointIndicesCount();
			
			for( int k = 0; k < vertex_index_count; k++ ) {
				int index = cluster->GetControlPointIndices()[k];
				if( index >= cp_count ) continue;

				double weight = cluster->GetControlPointWeights()[k];

				if( weight == 0.0 ) continue;

				KFbxXMatrix influence = vertex_transform_matrix;
				MatrixScale( influence, weight );

				if( cluster_mode == KFbxCluster::eADDITIVE ) {
					MatrixAddToDiagonal( influence, 1.0 - weight );
					cluster_deformations[index] = influence * cluster_deformations[index];

					cluster_weights[index] = 1.0;
				} else { // linkmode == normalize or total1

					MatrixAdd( cluster_deformations[index], influence );

					cluster_weights[index] += weight;
				}
			}
		}
	}

	// actual deformation
	for( int i = 0; i < cp_count; i++ ) {
		KFbxVector4 source_vertex = vertices[i];
		KFbxVector4 &dest_vertex = vertices[i];
		double weight = cluster_weights[i];

		if( weight != 0.0 ) {
			dest_vertex = cluster_deformations[i].MultT( source_vertex );
			if( cluster_mode == KFbxCluster::eNORMALIZE ) {
				dest_vertex /= weight;
			} else if( cluster_mode == KFbxCluster::eTOTAL1 ) {
				source_vertex *= (1.0 - weight);
				dest_vertex += source_vertex;
			}
		}
	}

	delete[] cluster_deformations;
	delete[] cluster_weights;
}
Exemple #2
0
// Deform the vertex array in classic linear way.
void ofxFBXMesh::computeLinearDeformation(FbxAMatrix& pGlobalPosition,
                                          FbxMesh* pMesh,
                                          FbxTime& pTime,
                                          FbxVector4* pVertexArray,
                                          FbxPose* pPose ) {
	// All the links must have the same link mode.
	FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)fbxMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();
    
	int lVertexCount = pMesh->GetControlPointsCount();
    
//    cout << "control points count = " << lVertexCount << " mesh verts = " << mesh.getNumVertices() << endl;
    
	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);
    
//    cout << "computeLinearDeformation :: number of skins = " << lSkinCount << endl;
    
	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);
            
			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.
				FbxAMatrix lInfluence = lVertexTransformMatrix;
				MatrixScale(lInfluence, lWeight);
                
				if (lClusterMode == FbxCluster::eAdditive) {
//                    cout << "computeLinearDeformation :: clustermode = eAdditive" << endl;
					// Multiply with the product of the deformations on the vertex.
					MatrixAddToDiagonal(lInfluence, 1.0 - lWeight);
					lClusterDeformation[lIndex] = lInfluence * lClusterDeformation[lIndex];
                    
					// 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(k == 0) cout << "computeLinearDeformation :: clustermode != eAdditive" << endl;
					// Add to the sum of the deformations on the vertex.
					MatrixAdd(lClusterDeformation[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 lWeight = lClusterWeight[i];
        
		// Deform the vertex if there was at least a link with an influence on the vertex,
		if (lWeight != 0.0) {
			lDstVertex = lClusterDeformation[i].MultT(lSrcVertex);
			if (lClusterMode == FbxCluster::eNormalize) {
				// In the normalized link mode, a vertex is always totally influenced by the links.
				lDstVertex /= lWeight;
			} else if (lClusterMode == FbxCluster::eTotalOne) {
				// In the total 1 link mode, a vertex can be partially influenced by the links.
				lSrcVertex *= (1.0 - lWeight);
				lDstVertex += lSrcVertex;
			}
		}
	}
    
	delete [] lClusterDeformation;
	delete [] lClusterWeight;
}