// This method, called by the system, modifies the items... void SpherifyMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Matrix3 mat, invmat; // Get the deformation space tm from the ModContext. We use this to // transform our points in and out of deformation space. if (mc.tm) mat = *mc.tm; else mat.IdentityMatrix(); // Compute the tm's inverse invmat = Inverse(mat); // Call the Deform method of the object passing it our deformer. // The Deform method of the object calls the Map method of the // deformer we pass one point at a time. os->obj->Deform(&GetDeformer(t, mc, mat, invmat), TRUE); // This informs the system that the object may need to be re-evaluated // if the user moves to a new time. We pass the channel we have // modified, and the interval of our modification. os->obj->UpdateValidity(GEOM_CHAN_NUM, SpherifyValidity(t)); }
void patchSkins(FbxNode* currentRoot, const std::map<std::string, FbxNode*>& animatedNodes, const std::string& prefix){ auto mesh = currentRoot->GetMesh(); if (mesh){ auto skinCount = mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin); for (auto ix = 0; ix < skinCount; ++ix){ auto skin = (FbxSkin*) mesh->GetDeformer(ix, FbxDeformer::EDeformerType::eSkin); if (skin){ std::vector<FbxCluster*> replacements; auto clusterCount = skin->GetClusterCount(); for (auto clusterIx = 0; clusterIx < clusterCount; ++clusterIx){ auto cluster = skin->GetCluster(clusterIx); if (cluster){ auto linkNode = cluster->GetLink(); if (linkNode){ auto candidateName = prefix; candidateName.append(linkNode->GetName()); auto found = animatedNodes.find(candidateName); if (found != animatedNodes.end()){ FbxCluster* newCluster = FbxCluster::Create(currentRoot->GetScene(), ""); newCluster->SetLink(found->second); newCluster->SetLinkMode(cluster->GetLinkMode()); FbxAMatrix mat; newCluster->SetTransformAssociateModelMatrix(cluster->GetTransformAssociateModelMatrix(mat)); newCluster->SetAssociateModel(cluster->GetAssociateModel()); newCluster->SetTransformLinkMatrix(cluster->GetTransformLinkMatrix(mat)); newCluster->SetTransformMatrix(cluster->GetTransformMatrix(mat)); newCluster->SetTransformParentMatrix(cluster->GetTransformParentMatrix(mat)); auto indicesAndWeightsCount = cluster->GetControlPointIndicesCount(); for (auto ix = 0; ix < indicesAndWeightsCount; ++ix){ newCluster->AddControlPointIndex(cluster->GetControlPointIndices()[ix], cluster->GetControlPointWeights()[ix]); } replacements.push_back(newCluster); } } } } if (replacements.size() == clusterCount){ while (skin->GetClusterCount()>0){ auto oldCluster = skin->GetCluster(skin->GetClusterCount() - 1); skin->RemoveCluster(oldCluster); oldCluster->Destroy(); } for (auto c : replacements){ skin->AddCluster(c); } } else{ for (auto c : replacements){ c->Destroy(); } } } } } for (auto ix = 0; ix < currentRoot->GetChildCount(); ++ix){ patchSkins(currentRoot->GetChild(ix), animatedNodes, prefix); } }
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 }