// Deform the vertex array with the shapes contained in the mesh. void compute_shape_deformation(FbxMesh* pMesh, FbxTime& pTime, FbxAnimLayer * pAnimLayer, FbxVector4* pVertexArray) { int lVertexCount = pMesh->GetControlPointsCount(); FbxVector4* lSrcVertexArray = pVertexArray; FbxVector4* lDstVertexArray = new FbxVector4[lVertexCount]; memcpy(lDstVertexArray, pVertexArray, lVertexCount * sizeof(FbxVector4)); int lBlendShapeDeformerCount = pMesh->GetDeformerCount(FbxDeformer::eBlendShape); for(int lBlendShapeIndex = 0; lBlendShapeIndex<lBlendShapeDeformerCount; ++lBlendShapeIndex) { FbxBlendShape* lBlendShape = (FbxBlendShape*)pMesh->GetDeformer(lBlendShapeIndex, FbxDeformer::eBlendShape); int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount(); for(int lChannelIndex = 0; lChannelIndex<lBlendShapeChannelCount; ++lChannelIndex) { FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex); if(lChannel) { // Get the percentage of influence of the shape. FbxAnimCurve* lFCurve = pMesh->GetShapeChannel(lBlendShapeIndex, lChannelIndex, pAnimLayer); if(!lFCurve) { continue; } double lWeight = lFCurve->Evaluate(pTime); //Find which shape should we use according to the weight. int lShapeCount = lChannel->GetTargetShapeCount(); double* lFullWeights = lChannel->GetTargetShapeFullWeights(); for(int lShapeIndex = 0; lShapeIndex<lShapeCount; ++lShapeIndex) { FbxShape* lShape = NULL; if(lWeight > 0 && lWeight <= lFullWeights[0]) { lShape = lChannel->GetTargetShape(0); } if(lWeight > lFullWeights[lShapeIndex] && lWeight < lFullWeights[lShapeIndex+1]) { lShape = lChannel->GetTargetShape(lShapeIndex+1); } if(lShape) { for(int j = 0; j < lVertexCount; j++) { // Add the influence of the shape vertex to the mesh vertex. FbxVector4 lInfluence = (lShape->GetControlPoints()[j] - lSrcVertexArray[j]) * lWeight * 0.01; lDstVertexArray[j] += lInfluence; } } }//For each target shape }//If lChannel is valid }//For each blend shape channel }//For each blend shape deformer memcpy(pVertexArray, lDstVertexArray, lVertexCount * sizeof(FbxVector4)); delete [] lDstVertexArray; }
//-------------------------------------------------------------- void ofxFBXMesh::computeBlendShapes( ofMesh* aMesh, FbxTime& pTime, FbxAnimLayer * pAnimLayer ) { int lBlendShapeDeformerCount = fbxMesh->GetDeformerCount(FbxDeformer::eBlendShape); // cout << "Computing blendshapes for " << getName() << endl; for(int lBlendShapeIndex = 0; lBlendShapeIndex<lBlendShapeDeformerCount; ++lBlendShapeIndex) { FbxBlendShape* lBlendShape = (FbxBlendShape*)fbxMesh->GetDeformer(lBlendShapeIndex, FbxDeformer::eBlendShape); int lBlendShapeChannelCount = lBlendShape->GetBlendShapeChannelCount(); for(int lChannelIndex = 0; lChannelIndex<lBlendShapeChannelCount; ++lChannelIndex) { FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(lChannelIndex); if(lChannel) { // Get the percentage of influence on this channel. FbxAnimCurve* lFCurve = fbxMesh->GetShapeChannel(lBlendShapeIndex, lChannelIndex, pAnimLayer); if (!lFCurve) continue; double lWeight = lFCurve->Evaluate(pTime); // cout << "updateMesh lWeight = " << lWeight << " time = " << pTime.GetMilliSeconds() << endl; int lShapeCount = lChannel->GetTargetShapeCount(); double* lFullWeights = lChannel->GetTargetShapeFullWeights(); // Find out which scope the lWeight falls in. int lStartIndex = -1; int lEndIndex = -1; for(int lShapeIndex = 0; lShapeIndex<lShapeCount; ++lShapeIndex) { if(lWeight > 0 && lWeight <= lFullWeights[0]) { lEndIndex = 0; break; } if(lWeight > lFullWeights[lShapeIndex] && lWeight < lFullWeights[lShapeIndex+1]) { lStartIndex = lShapeIndex; lEndIndex = lShapeIndex + 1; break; } } FbxShape* lStartShape = NULL; FbxShape* lEndShape = NULL; if(lStartIndex > -1) { lStartShape = lChannel->GetTargetShape(lStartIndex); } if(lEndIndex > -1) { lEndShape = lChannel->GetTargetShape(lEndIndex); } //The weight percentage falls between base geometry and the first target shape. if(lStartIndex == -1 && lEndShape) { float lEndWeight = lFullWeights[0]; lWeight = (lWeight/lEndWeight); cout << "updateMesh : weight = " << lWeight << endl; for (int j = 0; j < aMesh->getNumVertices(); j++) { // Add the influence of the shape vertex to the mesh vertex. ofVec3f influence = (toOf(lEndShape->GetControlPoints()[j]) - original.getVertices()[j]) * lWeight; aMesh->getVertices()[j] += influence; } } else if(lStartShape && lEndShape) { float lStartWeight = lFullWeights[lStartIndex]; float lEndWeight = lFullWeights[lEndIndex]; // Calculate the real weight. lWeight = ofMap(lWeight, lStartWeight, lEndWeight, 0, 1, true); cout << "updateMesh : weight = " << lWeight << " lStartWeight " << lStartWeight << " lEndWeight " << lEndWeight << endl; // lWeight = ((lWeight-lStartWeight)/(lEndWeight-lStartWeight)) * 100; for (int j = 0; j < aMesh->getNumVertices(); j++) { // Add the influence of the shape vertex to the mesh vertex. ofVec3f influence = (toOf(lEndShape->GetControlPoints()[j] - lStartShape->GetControlPoints()[j] )) * lWeight; aMesh->getVertices()[j] += influence; } } } } } }