// Deform the vertex array in Dual Quaternion Skinning way. void fbxLoader2::ComputeDualQuaternionDeformation(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(); 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; ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, frame); 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 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 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; }