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; }
// 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; }