static void extractKeyTimes(FbxNode* fbxChildNode, FbxAnimLayer* fbxAnimLayer, const char* channel, hkxNode* node, hkReal startTime, hkReal endTime) { HK_ASSERT(0x0, startTime <= endTime || endTime < 0.f); startTime = hkMath::max2(startTime, 0.f); FbxAnimCurve* lAnimCurve = fbxChildNode->LclTranslation.GetCurve(fbxAnimLayer, channel); if (lAnimCurve) { int lKeyCount = lAnimCurve->KeyGetCount(); hkReal lKeyTime; // Store keyframe times in seconds(from [0, endTime]) for(int lCount = 0; lCount < lKeyCount; lCount++) { lKeyTime = hkMath::max2((hkReal)lAnimCurve->KeyGetTime(lCount).GetSecondDouble(), 0.f); if (lKeyTime >= startTime && (lKeyTime <= endTime || endTime < 0.f)) { if (node->m_linearKeyFrameHints.indexOf(lKeyTime) < 0) { node->m_linearKeyFrameHints.pushBack(lKeyTime - startTime); } } else // handle case of [EXP-2436], where no keys in the range but range is affected by keys outside, so have to mark at start and end { if ((lKeyTime < startTime) &&(node->m_linearKeyFrameHints.indexOf(0.f) < 0)) { node->m_linearKeyFrameHints.pushBack(0.f); } else if (endTime >= 0.f &&(lKeyTime - startTime > endTime) &&(node->m_linearKeyFrameHints.indexOf(endTime - startTime) < 0)) { node->m_linearKeyFrameHints.pushBack(endTime - startTime); } } } } }
// 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 readKeys(FbxAnimCurve* curveX, FbxAnimCurve* curveY, FbxAnimCurve* curveZ, const FbxDouble3& defaultValue, std::vector<osgAnimation::TemplateKeyframe<osg::Vec3> >& keyFrameCntr, float scalar = 1.0f) { FbxAnimCurve* curves[3] = {curveX, curveY, curveZ}; typedef std::set<double> TimeSet; typedef std::map<double, float> TimeFloatMap; TimeSet times; TimeFloatMap curveTimeMap[3]; for (int nCurve = 0; nCurve < 3; ++nCurve) { FbxAnimCurve* pCurve = curves[nCurve]; int nKeys = pCurve ? pCurve->KeyGetCount() : 0; if (!nKeys) { times.insert(0.0); curveTimeMap[nCurve][0.0] = defaultValue[nCurve] * scalar; } for (int i = 0; i < nKeys; ++i) { FbxAnimCurveKey key = pCurve->KeyGet(i); double fTime = key.GetTime().GetSecondDouble(); times.insert(fTime); curveTimeMap[nCurve][fTime] = static_cast<float>(key.GetValue()) * scalar; } } for (TimeSet::iterator it = times.begin(); it != times.end(); ++it) { double fTime = *it; osg::Vec3 val; for (int i = 0; i < 3; ++i) { if (curveTimeMap[i].empty()) continue; TimeFloatMap::iterator lb = curveTimeMap[i].lower_bound(fTime); if (lb == curveTimeMap[i].end()) --lb; val[i] = lb->second; } keyFrameCntr.push_back(osgAnimation::Vec3Keyframe(fTime, val)); } }
void fbxLoader2::readAnimationTakeData(FbxNode* node) { FbxAnimStack* pAnimStack = FbxCast<FbxAnimStack>(scene->GetSrcObject(FBX_TYPE(FbxAnimStack))); FbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(FbxAnimLayer)); FbxAnimCurve* animCv = node->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); FbxTimeSpan length = FbxTimeSpan(); int p = animCv->KeyGetCount(); const char* nameAnim = animCv->GetName(); const size_t len = strlen(nameAnim); char * new_name = new char[len + 1]; strncpy(new_name, nameAnim, len); animCv->GetTimeInterval(length); FbxTime duration = length.GetDuration(); FbxTime::EMode mode = duration.GetGlobalTimeMode(); double frameRate = duration.GetFrameRate(mode); double startt = length.GetStart().GetMilliSeconds(); double endt = length.GetStop().GetMilliSeconds(); int frames = animCv->KeyGetCount(); animationStructure = new AnimationData(new_name, startt, endt, (int)frameRate, frames); for (int i = 0; i< frames; i++) { SkeletalData *sk = new SkeletalData(); for(int j = 0; j<skeleton->GetBonesCount(); j++) { BoneData *bonecopy = new BoneData(); bonecopy->SetID(skeleton->GetBone(j)->GetID()); bonecopy->SetName(skeleton->GetBone(j)->GetName()); bonecopy->SetParent(skeleton->GetBone(j)->GetParent()); sk->SetBones(bonecopy); } animationStructure->SetSkeleton(sk, i); } }
// The curve code doesn't differentiate between angles and other data, so an interpolation from 179 to -179 // will cause the bone to rotate all the way around through 0 degrees. So here we make a second pass over the // rotation tracks to convert the angles into a more interpolation-friendly format. void FFbxExporter::CorrectAnimTrackInterpolation( TArray<FbxNode*>& BoneNodes, FbxAnimLayer* InAnimLayer ) { // Add the animation data to the bone nodes for(int32 BoneIndex = 0; BoneIndex < BoneNodes.Num(); ++BoneIndex) { FbxNode* CurrentBoneNode = BoneNodes[BoneIndex]; // Fetch the AnimCurves FbxAnimCurve* Curves[3]; Curves[0] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); Curves[1] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); Curves[2] = CurrentBoneNode->LclRotation.GetCurve(InAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); for(int32 CurveIndex = 0; CurveIndex < 3; ++CurveIndex) { FbxAnimCurve* CurrentCurve = Curves[CurveIndex]; float CurrentAngleOffset = 0.f; for(int32 KeyIndex = 1; KeyIndex < CurrentCurve->KeyGetCount(); ++KeyIndex) { float PreviousOutVal = CurrentCurve->KeyGetValue( KeyIndex-1 ); float CurrentOutVal = CurrentCurve->KeyGetValue( KeyIndex ); float DeltaAngle = (CurrentOutVal + CurrentAngleOffset) - PreviousOutVal; if(DeltaAngle >= 180) { CurrentAngleOffset -= 360; } else if(DeltaAngle <= -180) { CurrentAngleOffset += 360; } CurrentOutVal += CurrentAngleOffset; CurrentCurve->KeySetValue(KeyIndex, CurrentOutVal); } } } }
void ofxFBXScene::parseRotationCurve(ofxFBXNode & node, FbxAnimLayer * pAnimLayer, FbxNode* fbxNode, FbxPropertyT<FbxDouble3> &rotation){ node.originalRotation = ofQuaternion(rotation.Get().mData[0], ofVec3f(1, 0, 0), rotation.Get().mData[1], ofVec3f(0, 1, 0), rotation.Get().mData[2], ofVec3f(0, 0, 1)); node.getNode().setOrientation(node.originalRotation); ofLogVerbose("ofxFBXScene") << "original rotation " << endl << node.originalRotation << endl; if(!rotation.GetCurve(pAnimLayer)) return; FbxAnimCurve* lAnimCurveX = rotation.GetCurve(pAnimLayer,"X"); FbxAnimCurve* lAnimCurveY = rotation.GetCurve(pAnimLayer,"Y"); FbxAnimCurve* lAnimCurveZ = rotation.GetCurve(pAnimLayer,"Z"); int xKeyCount = lAnimCurveX ? lAnimCurveX->KeyGetCount() : 0; int yKeyCount = lAnimCurveY ? lAnimCurveY->KeyGetCount() : 0; int zKeyCount = lAnimCurveZ ? lAnimCurveZ->KeyGetCount() : 0; FbxTime lKeyTime; int lCount; FbxTime lXKeyTime,lYKeyTime,lZKeyTime; for(lCount = 0; lCount < max(max(xKeyCount,yKeyCount),zKeyCount); lCount++) { if(lCount<xKeyCount){ lXKeyTime = lAnimCurveX->KeyGetTime(lCount); } if(lCount<yKeyCount){ lYKeyTime = lAnimCurveY->KeyGetTime(lCount); } if(lCount<zKeyCount){ lZKeyTime = lAnimCurveZ->KeyGetTime(lCount); } lKeyTime = min(min(lXKeyTime,lYKeyTime),lZKeyTime); lKeyTime = lXKeyTime; FbxAMatrix & matrix = fbxNode->EvaluateLocalTransform(lKeyTime); ofxFBXKey<ofQuaternion> key; ofVec3f t,s; ofQuaternion so; ofMatrix4x4 m = toOf(matrix); m.decompose(t,key.value,s,so); key.timeMillis = lKeyTime.GetMilliSeconds(); node.rotationKeys.push_back(key); } }
int main(int argc, char **argv) { #ifndef _DEBUG if (argc != 2) { printf("invalid arg"); return 0; } const char* filename = argv[1]; #else const char* filename = "*****@*****.**"; #endif output.open("output.txt", ios::out | ios::trunc); output2.open("output2.txt", ios::out | ios::trunc); output3.open("output3.txt", ios::out | ios::trunc); if (!output.is_open()) { exit(1); } FbxManager* fm = FbxManager::Create(); FbxIOSettings *ios = FbxIOSettings::Create(fm, IOSROOT); //ios->SetBoolProp(EXP_FBX_ANIMATION, false); ios->SetIntProp(EXP_FBX_COMPRESS_LEVEL, 9); ios->SetAllObjectFlags(true); fm->SetIOSettings(ios); FbxImporter* importer = FbxImporter::Create(fm, ""); if (!importer->Initialize(filename, -1, fm->GetIOSettings())) { printf("error returned : %s\n", importer->GetStatus().GetErrorString()); exit(-1); } FbxScene* scene = FbxScene::Create(fm, "myscene"); importer->Import(scene); importer->Destroy(); output << "some\n"; output << "charcnt : " << scene->GetCharacterCount() << endl << "node cnt : " << scene->GetNodeCount() << endl; int animstackcnt = scene->GetSrcObjectCount<FbxAnimStack>(); output << "animstackcnt : " << animstackcnt << endl; output << "------------" << endl; vector<FbxNode*> removableNodes; for (int i = 0; i < scene->GetNodeCount(); i++) { FbxNode* node = scene->GetNode(i); output << "scene's node " << i << " : " << node->GetName() << ", childcnt : " << node->GetChildCount(); if (node->GetNodeAttribute()) { output <<", att type : " << node->GetNodeAttribute()->GetAttributeType(); if (node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eMesh) { FbxMesh* mesh = node->GetMesh(); output << ", mem usage : " << mesh->MemoryUsage() << ", deformer cnt : " << mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin) << endl; collapseMesh(mesh); FbxSkin* skin = (FbxSkin*) (mesh->GetDeformer(0, FbxDeformer::EDeformerType::eSkin)); if (skin) { for (int cli = 0; cli < skin->GetClusterCount(); cli++) { FbxCluster* cluster = skin->GetCluster(cli); output << "\tcluster no." << cli << " has " << cluster->GetControlPointIndicesCount() << " connected verts" << endl; if (cluster->GetControlPointIndicesCount() == 0) removableNodes.push_back( cluster->GetLink() ); //cluster-> //skin->RemoveCluster(cluster);효과없음 } } if (mesh->IsTriangleMesh()) { output << "\tit's triangle mesh" << endl; } //mesh->RemoveDeformer(0);효과없음 } else output << endl; } else { output << ", att type : none" << endl; } } for (int rni = 0; rni < removableNodes.size(); rni++) { FbxNode* rnd = removableNodes[rni]; if (rnd && rnd->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eSkeleton) { output3 << rnd->GetName() << " node with no vert attached's curve : " << rnd->GetSrcObjectCount<FbxAnimCurve>() << "," << rnd->GetSrcObjectCount<FbxAnimCurveNode>() << endl; } } output << "-----------animinfo" << endl; int cubic = 0, linear = 0, cons = 0; for (int si = 0; si < animstackcnt; si++) { FbxAnimStack* stack = scene->GetSrcObject<FbxAnimStack>(si); for (int i = 0; i < stack->GetMemberCount<FbxAnimLayer>(); i++) { FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(i); int curvenodecnt = layer->GetMemberCount<FbxAnimCurveNode>(); int compositcnt = 0; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); compositcnt += (cnode->IsComposite() ? 1 : 0); } output << "\tanimstack's layer " << i << " : " << layer->GetName() << ", curve node cnt : " << curvenodecnt << ", composit node cnt : " << compositcnt << endl; vector<FbxAnimCurveNode*> nodes2del; for (int j = 0; j < curvenodecnt; j++) { FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j); output << "\t\tcurvenode " << j << " channel cnt : " << cnode->GetChannelsCount() << ", dst obj cnt " << cnode->GetDstObjectCount() << "("; for (int dsti = 0; dsti < cnode->GetDstObjectCount(); dsti++) { output << "," << cnode->GetDstObject(dsti)->GetName(); if (cnode->GetDstObject(dsti)->GetSrcObjectCount() > 0) output << "<" << cnode->GetDstObject(dsti)->GetSrcObjectCount<FbxSkeleton>() << ">"; } output << ")"; FbxTimeSpan interval; if (cnode->GetAnimationInterval(interval)) { output << ", start : " << interval.GetStart().GetTimeString() << ", end : " << interval.GetStop().GetTimeString() << endl; } else { nodes2del.push_back(cnode); output << ", no interval" << endl; } for (int chi = 0; chi < cnode->GetChannelsCount(); chi++) { int curvecnt = cnode->GetCurveCount(chi); output << "\t\t\tchannel." << chi << " curvecnt : " << curvecnt << endl; for (int ci = 0; ci < curvecnt; ci++) { FbxAnimCurve* curve = cnode->GetCurve(chi, ci); int keycnt = curve->KeyGetCount(); output << "\t\t\t\tcurve no." << ci << " : key count : " << keycnt; output2 << "curve " << ci << endl; vector<int> keys2Remove; for (int cki = 0; cki < keycnt; cki++) { FbxAnimCurveKey prevkey, currkey, nextkey; if (cki == 0 || cki == keycnt - 1) continue; currkey = curve->KeyGet(cki); prevkey = curve->KeyGet(cki-1); nextkey = curve->KeyGet(cki + 1); bool keepit = true; output2 << ci << "-" << cki; // keepit = keepTestHorizon(curve, prevkey, currkey, nextkey); // if (keepit) // keepit = slopkeepTest(curve, prevkey, currkey, nextkey); if (!keepit) { if (!(currkey.GetInterpolation() == FbxAnimCurveDef::EInterpolationType::eInterpolationConstant && nextkey.GetInterpolation() != FbxAnimCurveDef::EInterpolationType::eInterpolationConstant)) keys2Remove.push_back(cki); } } for (int kri = keys2Remove.size() - 1; kri >= 0; kri--) { //curve->KeyRemove(keys2Remove[kri]); } output2 << endl; //output << ", cubic:linear:const : " << cubic << ":" << linear << ":" << cons << endl; if (keys2Remove.size() > 0) output << ", " << keys2Remove.size() << " keys removed"; keycnt = curve->KeyGetCount(); } } } //이부분은 별로 효과없음 /* for (int di = 0; di < nodes2del.size(); di++) { layer->RemoveMember(nodes2del[di]); } */ } } output << "cubic:linear:const " << cubic << ":" << linear << ":" << cons << endl; FbxExporter* exporter = FbxExporter::Create(fm, ""); const char* outFBXName = "after.fbx"; bool exportstatus = exporter->Initialize(outFBXName, -1, fm->GetIOSettings()); if (exportstatus == false) { puts("err export fail"); } exporter->Export(scene); exporter->Destroy(); scene->Destroy(); ios->Destroy(); fm->Destroy(); output.close(); output2.close(); output3.close(); return 0; }
bool UnFbx::FFbxImporter::ImportAnimation(USkeleton* Skeleton, UAnimSequence * DestSeq, const FString& FileName, TArray<FbxNode*>& SortedLinks, TArray<FbxNode*>& NodeArray, FbxAnimStack* CurAnimStack, const int32 ResampleRate, const FbxTimeSpan AnimTimeSpan) { // @todo : the length might need to change w.r.t. sampling keys FbxTime SequenceLength = AnimTimeSpan.GetDuration(); float PreviousSequenceLength = DestSeq->SequenceLength; // if you have one pose(thus 0.f duration), it still contains animation, so we'll need to consider that as MINIMUM_ANIMATION_LENGTH time length DestSeq->SequenceLength = FGenericPlatformMath::Max<float>(SequenceLength.GetSecondDouble(), MINIMUM_ANIMATION_LENGTH); if(PreviousSequenceLength > MINIMUM_ANIMATION_LENGTH && DestSeq->RawCurveData.FloatCurves.Num() > 0) { // The sequence already existed when we began the import. We need to scale the key times for all curves to match the new // duration before importing over them. This is to catch any user-added curves float ScaleFactor = DestSeq->SequenceLength / PreviousSequenceLength; for(FFloatCurve& Curve : DestSeq->RawCurveData.FloatCurves) { Curve.FloatCurve.ScaleCurve(0.0f, ScaleFactor); } } if (ImportOptions->bDeleteExistingMorphTargetCurves) { for (int32 CurveIdx=0; CurveIdx<DestSeq->RawCurveData.FloatCurves.Num(); ++CurveIdx) { auto& Curve = DestSeq->RawCurveData.FloatCurves[CurveIdx]; if (Curve.GetCurveTypeFlag(ACF_DrivesMorphTarget)) { DestSeq->RawCurveData.FloatCurves.RemoveAt(CurveIdx, 1, false); --CurveIdx; } } DestSeq->RawCurveData.FloatCurves.Shrink(); } // // import blend shape curves // { GWarn->BeginSlowTask( LOCTEXT("BeginImportMorphTargetCurves", "Importing Morph Target Curves"), true); for ( int32 NodeIndex = 0; NodeIndex < NodeArray.Num(); NodeIndex++ ) { // consider blendshape animation curve FbxGeometry* Geometry = (FbxGeometry*)NodeArray[NodeIndex]->GetNodeAttribute(); if (Geometry) { int32 BlendShapeDeformerCount = Geometry->GetDeformerCount(FbxDeformer::eBlendShape); for(int32 BlendShapeIndex = 0; BlendShapeIndex<BlendShapeDeformerCount; ++BlendShapeIndex) { FbxBlendShape* BlendShape = (FbxBlendShape*)Geometry->GetDeformer(BlendShapeIndex, FbxDeformer::eBlendShape); const int32 BlendShapeChannelCount = BlendShape->GetBlendShapeChannelCount(); FString BlendShapeName = UTF8_TO_TCHAR(MakeName(BlendShape->GetName())); for(int32 ChannelIndex = 0; ChannelIndex<BlendShapeChannelCount; ++ChannelIndex) { FbxBlendShapeChannel* Channel = BlendShape->GetBlendShapeChannel(ChannelIndex); if(Channel) { FString ChannelName = UTF8_TO_TCHAR(MakeName(Channel->GetName())); // Maya adds the name of the blendshape and an underscore to the front of the channel name, so remove it if(ChannelName.StartsWith(BlendShapeName)) { ChannelName = ChannelName.Right(ChannelName.Len() - (BlendShapeName.Len()+1)); } FbxAnimCurve* Curve = Geometry->GetShapeChannel(BlendShapeIndex, ChannelIndex, (FbxAnimLayer*)CurAnimStack->GetMember(0)); if (Curve && Curve->KeyGetCount() > 0) { FFormatNamedArguments Args; Args.Add(TEXT("BlendShape"), FText::FromString(ChannelName)); const FText StatusUpate = FText::Format(LOCTEXT("ImportingMorphTargetCurvesDetail", "Importing Morph Target Curves [{BlendShape}]"), Args); GWarn->StatusUpdate(NodeIndex + 1, NodeArray.Num(), StatusUpate); // now see if we have one already exists. If so, just overwrite that. if not, add new one. ImportCurveToAnimSequence(DestSeq, *ChannelName, Curve, ACF_DrivesMorphTarget | ACF_TriggerEvent, AnimTimeSpan, 0.01f /** for some reason blend shape values are coming as 100 scaled **/); } } } } } } GWarn->EndSlowTask(); } // // importing custom attribute START // if (ImportOptions->bImportCustomAttribute) { GWarn->BeginSlowTask( LOCTEXT("BeginImportMorphTargetCurves", "Importing Custom Attirubte Curves"), true); const int32 TotalLinks = SortedLinks.Num(); int32 CurLinkIndex=0; for(auto Node: SortedLinks) { FbxProperty Property = Node->GetFirstProperty(); while (Property.IsValid()) { FbxAnimCurveNode* CurveNode = Property.GetCurveNode(); // do this if user defined and animated and leaf node if( CurveNode && Property.GetFlag(FbxPropertyAttr::eUserDefined) && CurveNode->IsAnimated() && IsSupportedCurveDataType(Property.GetPropertyDataType().GetType()) ) { FString CurveName = UTF8_TO_TCHAR(CurveNode->GetName()); UE_LOG(LogFbx, Log, TEXT("CurveName : %s"), *CurveName ); int32 TotalCount = CurveNode->GetChannelsCount(); for (int32 ChannelIndex=0; ChannelIndex<TotalCount; ++ChannelIndex) { FbxAnimCurve * AnimCurve = CurveNode->GetCurve(ChannelIndex); FString ChannelName = CurveNode->GetChannelName(ChannelIndex).Buffer(); if (AnimCurve) { FString FinalCurveName; if (TotalCount == 1) { FinalCurveName = CurveName; } else { FinalCurveName = CurveName + "_" + ChannelName; } FFormatNamedArguments Args; Args.Add(TEXT("CurveName"), FText::FromString(FinalCurveName)); const FText StatusUpate = FText::Format(LOCTEXT("ImportingCustomAttributeCurvesDetail", "Importing Custom Attribute [{CurveName}]"), Args); GWarn->StatusUpdate(CurLinkIndex + 1, TotalLinks, StatusUpate); ImportCurveToAnimSequence(DestSeq, FinalCurveName, AnimCurve, ACF_DefaultCurve, AnimTimeSpan); } } } Property = Node->GetNextProperty(Property); } CurLinkIndex++; } GWarn->EndSlowTask(); } // importing custom attribute END const bool bSourceDataExists = (DestSeq->SourceRawAnimationData.Num() > 0); TArray<AnimationTransformDebug::FAnimationTransformDebugData> TransformDebugData; int32 TotalNumKeys = 0; const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton(); // import animation { GWarn->BeginSlowTask( LOCTEXT("BeginImportAnimation", "Importing Animation"), true); TArray<struct FRawAnimSequenceTrack>& RawAnimationData = bSourceDataExists? DestSeq->SourceRawAnimationData : DestSeq->RawAnimationData; DestSeq->TrackToSkeletonMapTable.Empty(); DestSeq->AnimationTrackNames.Empty(); RawAnimationData.Empty(); TArray<FName> FbxRawBoneNames; FillAndVerifyBoneNames(Skeleton, SortedLinks, FbxRawBoneNames, FileName); UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance(); const bool bPreserveLocalTransform = FbxImporter->GetImportOptions()->bPreserveLocalTransform; // Build additional transform matrix UFbxAnimSequenceImportData* TemplateData = Cast<UFbxAnimSequenceImportData>(DestSeq->AssetImportData); FbxAMatrix FbxAddedMatrix; BuildFbxMatrixForImportTransform(FbxAddedMatrix, TemplateData); FMatrix AddedMatrix = Converter.ConvertMatrix(FbxAddedMatrix); const int32 NumSamplingKeys = FMath::FloorToInt(AnimTimeSpan.GetDuration().GetSecondDouble() * ResampleRate); const FbxTime TimeIncrement = (NumSamplingKeys > 1)? AnimTimeSpan.GetDuration() / (NumSamplingKeys - 1) : AnimTimeSpan.GetDuration(); for(int32 SourceTrackIdx = 0; SourceTrackIdx < FbxRawBoneNames.Num(); ++SourceTrackIdx) { int32 NumKeysForTrack = 0; // see if it's found in Skeleton FName BoneName = FbxRawBoneNames[SourceTrackIdx]; int32 BoneTreeIndex = RefSkeleton.FindBoneIndex(BoneName); // update status FFormatNamedArguments Args; Args.Add(TEXT("TrackName"), FText::FromName(BoneName)); Args.Add(TEXT("TotalKey"), FText::AsNumber(NumSamplingKeys)); Args.Add(TEXT("TrackIndex"), FText::AsNumber(SourceTrackIdx+1)); Args.Add(TEXT("TotalTracks"), FText::AsNumber(FbxRawBoneNames.Num())); const FText StatusUpate = FText::Format(LOCTEXT("ImportingAnimTrackDetail", "Importing Animation Track [{TrackName}] ({TrackIndex}/{TotalTracks}) - TotalKey {TotalKey}"), Args); GWarn->StatusForceUpdate(SourceTrackIdx + 1, FbxRawBoneNames.Num(), StatusUpate); if (BoneTreeIndex!=INDEX_NONE) { bool bSuccess = true; FRawAnimSequenceTrack RawTrack; RawTrack.PosKeys.Empty(); RawTrack.RotKeys.Empty(); RawTrack.ScaleKeys.Empty(); AnimationTransformDebug::FAnimationTransformDebugData NewDebugData; FbxNode* Link = SortedLinks[SourceTrackIdx]; FbxNode * LinkParent = Link->GetParent(); for(FbxTime CurTime = AnimTimeSpan.GetStart(); CurTime <= AnimTimeSpan.GetStop(); CurTime += TimeIncrement) { // save global trasnform FbxAMatrix GlobalMatrix = Link->EvaluateGlobalTransform(CurTime); // we'd like to verify this before going to Transform. // currently transform has tons of NaN check, so it will crash there FMatrix GlobalUEMatrix = Converter.ConvertMatrix(GlobalMatrix); if (GlobalUEMatrix.ContainsNaN()) { bSuccess = false; AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidTransform", "Track {0} contains invalid transform. Could not import the track."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError); break; } FTransform GlobalTransform = Converter.ConvertTransform(GlobalMatrix); if (GlobalTransform.ContainsNaN()) { bSuccess = false; AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidUnrealTransform", "Track {0} did not yeild valid transform. Please report this to animation team."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError); break; } // debug data, including import transformation FTransform AddedTransform(AddedMatrix); NewDebugData.SourceGlobalTransform.Add(GlobalTransform * AddedTransform); FTransform LocalTransform; if( !bPreserveLocalTransform && LinkParent) { // I can't rely on LocalMatrix. I need to recalculate quaternion/scale based on global transform if Parent exists FbxAMatrix ParentGlobalMatrix = Link->GetParent()->EvaluateGlobalTransform(CurTime); FTransform ParentGlobalTransform = Converter.ConvertTransform(ParentGlobalMatrix); LocalTransform = GlobalTransform.GetRelativeTransform(ParentGlobalTransform); NewDebugData.SourceParentGlobalTransform.Add(ParentGlobalTransform); } else { FbxAMatrix& LocalMatrix = Link->EvaluateLocalTransform(CurTime); FbxVector4 NewLocalT = LocalMatrix.GetT(); FbxVector4 NewLocalS = LocalMatrix.GetS(); FbxQuaternion NewLocalQ = LocalMatrix.GetQ(); LocalTransform.SetTranslation(Converter.ConvertPos(NewLocalT)); LocalTransform.SetScale3D(Converter.ConvertScale(NewLocalS)); LocalTransform.SetRotation(Converter.ConvertRotToQuat(NewLocalQ)); NewDebugData.SourceParentGlobalTransform.Add(FTransform::Identity); } if(TemplateData && BoneTreeIndex == 0) { // If we found template data earlier, apply the import transform matrix to // the root track. LocalTransform.SetFromMatrix(LocalTransform.ToMatrixWithScale() * AddedMatrix); } if (LocalTransform.ContainsNaN()) { bSuccess = false; AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidUnrealLocalTransform", "Track {0} did not yeild valid local transform. Please report this to animation team."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError); break; } RawTrack.ScaleKeys.Add(LocalTransform.GetScale3D()); RawTrack.PosKeys.Add(LocalTransform.GetTranslation()); RawTrack.RotKeys.Add(LocalTransform.GetRotation()); NewDebugData.RecalculatedLocalTransform.Add(LocalTransform); ++NumKeysForTrack; } if (bSuccess) { //add new track int32 NewTrackIdx = RawAnimationData.Add(RawTrack); DestSeq->AnimationTrackNames.Add(BoneName); NewDebugData.SetTrackData(NewTrackIdx, BoneTreeIndex, BoneName); // add mapping to skeleton bone track DestSeq->TrackToSkeletonMapTable.Add(FTrackToSkeletonMap(BoneTreeIndex)); TransformDebugData.Add(NewDebugData); } } TotalNumKeys = FMath::Max( TotalNumKeys, NumKeysForTrack ); } DestSeq->NumFrames = TotalNumKeys; GWarn->EndSlowTask(); } // compress animation { GWarn->BeginSlowTask( LOCTEXT("BeginCompressAnimation", "Compress Animation"), true); GWarn->StatusForceUpdate(1, 1, LOCTEXT("CompressAnimation", "Compressing Animation")); // if source data exists, you should bake it to Raw to apply if(bSourceDataExists) { DestSeq->BakeTrackCurvesToRawAnimation(); } else { // otherwise just compress DestSeq->PostProcessSequence(); } // run debug mode AnimationTransformDebug::OutputAnimationTransformDebugData(TransformDebugData, TotalNumKeys, RefSkeleton); GWarn->EndSlowTask(); } return true; }
bool UnFbx::FFbxImporter::ValidateAnimStack(TArray<FbxNode*>& SortedLinks, TArray<FbxNode*>& NodeArray, FbxAnimStack* CurAnimStack, int32 ResampleRate, bool bImportMorph, FbxTimeSpan &AnimTimeSpan) { // set current anim stack Scene->SetCurrentAnimationStack(CurAnimStack); UE_LOG(LogFbx, Log, TEXT("Parsing AnimStack %s"),UTF8_TO_TCHAR(CurAnimStack->GetName())); // There are a FBX unroll filter bug, so don't bake animation layer at all MergeAllLayerAnimation(CurAnimStack, ResampleRate); bool bValidAnimStack = true; AnimTimeSpan = GetAnimationTimeSpan(SortedLinks[0], CurAnimStack); // if no duration is found, return false if (AnimTimeSpan.GetDuration() <= 0) { return false; } const FBXImportOptions* ImportOption = GetImportOptions(); // only add morph time if not setrange. If Set Range there is no reason to override time if ( bImportMorph && ImportOption->AnimationLengthImportType != FBXALIT_SetRange) { for ( int32 NodeIndex = 0; NodeIndex < NodeArray.Num(); NodeIndex++ ) { // consider blendshape animation curve FbxGeometry* Geometry = (FbxGeometry*)NodeArray[NodeIndex]->GetNodeAttribute(); if (Geometry) { int32 BlendShapeDeformerCount = Geometry->GetDeformerCount(FbxDeformer::eBlendShape); for(int32 BlendShapeIndex = 0; BlendShapeIndex<BlendShapeDeformerCount; ++BlendShapeIndex) { FbxBlendShape* BlendShape = (FbxBlendShape*)Geometry->GetDeformer(BlendShapeIndex, FbxDeformer::eBlendShape); int32 BlendShapeChannelCount = BlendShape->GetBlendShapeChannelCount(); for(int32 ChannelIndex = 0; ChannelIndex<BlendShapeChannelCount; ++ChannelIndex) { FbxBlendShapeChannel* Channel = BlendShape->GetBlendShapeChannel(ChannelIndex); if(Channel) { // Get the percentage of influence of the shape. FbxAnimCurve* Curve = Geometry->GetShapeChannel(BlendShapeIndex, ChannelIndex, (FbxAnimLayer*)CurAnimStack->GetMember(0)); if (Curve && Curve->KeyGetCount() > 0) { FbxTimeSpan TmpAnimSpan; if (Curve->GetTimeInterval(TmpAnimSpan)) { bValidAnimStack = true; // update animation interval to include morph target range AnimTimeSpan.UnionAssignment(TmpAnimSpan); } } } } } } } } return bValidAnimStack; }
int32 UnFbx::FFbxImporter::GetMaxSampleRate(TArray<FbxNode*>& SortedLinks, TArray<FbxNode*>& NodeArray) { int32 MaxStackResampleRate = 0; int32 AnimStackCount = Scene->GetSrcObjectCount<FbxAnimStack>(); for( int32 AnimStackIndex = 0; AnimStackIndex < AnimStackCount; AnimStackIndex++) { FbxAnimStack* CurAnimStack = Scene->GetSrcObject<FbxAnimStack>(AnimStackIndex); FbxTimeSpan AnimStackTimeSpan = GetAnimationTimeSpan(SortedLinks[0], CurAnimStack); double AnimStackStart = AnimStackTimeSpan.GetStart().GetSecondDouble(); double AnimStackStop = AnimStackTimeSpan.GetStop().GetSecondDouble(); FbxAnimLayer* AnimLayer = (FbxAnimLayer*)CurAnimStack->GetMember(0); for(int32 LinkIndex = 0; LinkIndex < SortedLinks.Num(); ++LinkIndex) { FbxNode* CurrentLink = SortedLinks[LinkIndex]; FbxAnimCurve* Curves[6]; Curves[0] = CurrentLink->LclTranslation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_X, false); Curves[1] = CurrentLink->LclTranslation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, false); Curves[2] = CurrentLink->LclTranslation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, false); Curves[3] = CurrentLink->LclRotation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_X, false); Curves[4] = CurrentLink->LclRotation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, false); Curves[5] = CurrentLink->LclRotation.GetCurve(AnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, false); for(int32 CurveIndex = 0; CurveIndex < 6; ++CurveIndex) { FbxAnimCurve* CurrentCurve = Curves[CurveIndex]; if(CurrentCurve) { int32 KeyCount = CurrentCurve->KeyGetCount(); FbxTimeSpan TimeInterval(FBXSDK_TIME_INFINITE,FBXSDK_TIME_MINUS_INFINITE); bool bValidTimeInterval = CurrentCurve->GetTimeInterval(TimeInterval); if(KeyCount > 1 && bValidTimeInterval) { double KeyAnimLength = TimeInterval.GetDuration().GetSecondDouble(); double KeyAnimStart = TimeInterval.GetStart().GetSecondDouble(); double KeyAnimStop = TimeInterval.GetStop().GetSecondDouble(); if(KeyAnimLength != 0.0) { // 30 fps animation has 31 keys because it includes index 0 key for 0.0 second int32 NewRate = FPlatformMath::RoundToInt((KeyCount-1) / KeyAnimLength); MaxStackResampleRate = FMath::Max(NewRate, MaxStackResampleRate); } } } } } } // Make sure we're not hitting 0 for samplerate if ( MaxStackResampleRate != 0 ) { return MaxStackResampleRate; } return DEFAULT_SAMPLERATE; }
bool UnFbx::FFbxImporter::IsValidAnimationData(TArray<FbxNode*>& SortedLinks, TArray<FbxNode*>& NodeArray, int32& ValidTakeCount) { // If there are no valid links, then we cannot import the anim set if(SortedLinks.Num() == 0) { return false; } ValidTakeCount = 0; int32 AnimStackCount = Scene->GetSrcObjectCount<FbxAnimStack>(); int32 AnimStackIndex; for (AnimStackIndex = 0; AnimStackIndex < AnimStackCount; AnimStackIndex++ ) { FbxAnimStack* CurAnimStack = Scene->GetSrcObject<FbxAnimStack>(AnimStackIndex); // set current anim stack Scene->SetCurrentAnimationStack(CurAnimStack); // debug purpose for (int32 BoneIndex = 0; BoneIndex < SortedLinks.Num(); BoneIndex++) { FString BoneName = UTF8_TO_TCHAR(MakeName(SortedLinks[BoneIndex]->GetName())); UE_LOG(LogFbx, Log, TEXT("SortedLinks :(%d) %s"), BoneIndex, *BoneName ); } FbxTimeSpan AnimTimeSpan = GetAnimationTimeSpan(SortedLinks[0], CurAnimStack); if (AnimTimeSpan.GetDuration() <= 0) { AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, FText::Format(LOCTEXT("FBXImport_ZeroLength", "Animation Stack {0} does not contain any valid key. Try different time options when import."), FText::FromString(UTF8_TO_TCHAR(CurAnimStack->GetName())))), FFbxErrors::Animation_ZeroLength); continue; } ValidTakeCount++; { bool bBlendCurveFound = false; for ( int32 NodeIndex = 0; !bBlendCurveFound && NodeIndex < NodeArray.Num(); NodeIndex++ ) { // consider blendshape animation curve FbxGeometry* Geometry = (FbxGeometry*)NodeArray[NodeIndex]->GetNodeAttribute(); if (Geometry) { int32 BlendShapeDeformerCount = Geometry->GetDeformerCount(FbxDeformer::eBlendShape); for(int32 BlendShapeIndex = 0; BlendShapeIndex<BlendShapeDeformerCount; ++BlendShapeIndex) { FbxBlendShape* BlendShape = (FbxBlendShape*)Geometry->GetDeformer(BlendShapeIndex, FbxDeformer::eBlendShape); int32 BlendShapeChannelCount = BlendShape->GetBlendShapeChannelCount(); for(int32 ChannelIndex = 0; ChannelIndex<BlendShapeChannelCount; ++ChannelIndex) { FbxBlendShapeChannel* Channel = BlendShape->GetBlendShapeChannel(ChannelIndex); if(Channel) { // Get the percentage of influence of the shape. FbxAnimCurve* Curve = Geometry->GetShapeChannel(BlendShapeIndex, ChannelIndex, (FbxAnimLayer*)CurAnimStack->GetMember(0)); if (Curve && Curve->KeyGetCount() > 0) { bBlendCurveFound = true; break; } } } } } } } } return ( ValidTakeCount != 0 ); }
void readFbxRotationAnimation(osgAnimation::Channel* channels[3], FbxNode* pNode, FbxAnimLayer* pAnimLayer, const char* targetName) { if (!pNode->LclRotation.IsValid()) { return; } EFbxRotationOrder rotOrder = pNode->RotationOrder.IsValid() ? pNode->RotationOrder.Get() : eEulerXYZ; if (pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get()) { channels[0] = readFbxChannelsQuat( pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X), pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y), pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z), pNode->LclRotation.Get(), targetName, rotOrder); } else { const char* curveNames[3] = {FBXSDK_CURVENODE_COMPONENT_X, FBXSDK_CURVENODE_COMPONENT_Y, FBXSDK_CURVENODE_COMPONENT_Z}; FbxDouble3 fbxPropValue = pNode->LclRotation.Get(); fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]); fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]); fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]); for (int i = 0; i < 3; ++i) { FbxAnimCurve* curve = pNode->LclRotation.GetCurve(pAnimLayer, curveNames[i]); if (!curve) { continue; } FbxAnimCurveDef::EInterpolationType interpolationType = FbxAnimCurveDef::eInterpolationConstant; if (curve && curve->KeyGetCount()) interpolationType = curve->KeyGetInterpolation(0); if (interpolationType == FbxAnimCurveDef::eInterpolationCubic) { osgAnimation::FloatCubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::FloatCubicBezierKeyframeContainer; for (int j = 0; j < curve->KeyGetCount(); ++j) { double fTime = curve->KeyGetTime(j).GetSecondDouble(); float angle = curve->KeyGetValue(j); //FbxAnimCurveDef::EWeightedMode tangentWeightMode = curve->KeyGet(j).GetTangentWeightMode(); FbxAnimCurveTangentInfo leftTangent = curve->KeyGetLeftDerivativeInfo(j); FbxAnimCurveTangentInfo rightTangent = curve->KeyGetRightDerivativeInfo(j); if (j > 0) { leftTangent.mDerivative *= fTime - curve->KeyGetTime(j - 1).GetSecondDouble(); } if (j + 1 < curve->KeyGetCount()) { rightTangent.mDerivative *= curve->KeyGetTime(j + 1).GetSecondDouble() - fTime; } osgAnimation::FloatCubicBezier key( osg::DegreesToRadians(angle), osg::DegreesToRadians(angle - leftTangent.mDerivative / 3.0), osg::DegreesToRadians(angle + rightTangent.mDerivative / 3.0)); pKeyFrameCntr->push_back(osgAnimation::FloatCubicBezierKeyframe( fTime, key)); } reorderControlPoints(*pKeyFrameCntr); osgAnimation::FloatCubicBezierChannel* pCubicChannel = new osgAnimation::FloatCubicBezierChannel; pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr); channels[i] = pCubicChannel; } else { osgAnimation::FloatKeyframeContainer* keys = new osgAnimation::FloatKeyframeContainer; for (int j = 0; j < curve->KeyGetCount(); ++j) { FbxAnimCurveKey key = curve->KeyGet(j); keys->push_back(osgAnimation::FloatKeyframe( key.GetTime().GetSecondDouble(), static_cast<float>(osg::DegreesToRadians(key.GetValue())))); } if (interpolationType == FbxAnimCurveDef::eInterpolationConstant) { osgAnimation::FloatStepChannel* pStepChannel = new osgAnimation::FloatStepChannel(); pStepChannel->getOrCreateSampler()->setKeyframeContainer(keys); channels[i] = pStepChannel; } else { osgAnimation::FloatLinearChannel* pLinearChannel = new osgAnimation::FloatLinearChannel(); pLinearChannel->getOrCreateSampler()->setKeyframeContainer(keys); channels[i] = pLinearChannel; } } channels[i]->setTargetName(targetName); channels[i]->setName(std::string("rotate") + curveNames[i]); } } }
// Get the animated parameters of a camera contained in the scene // and store them in the associated member variables contained in // the camera. void GetCameraAnimatedParameters(FbxNode* pNode, FbxTime& pTime, FbxAnimLayer* pAnimLayer) { FbxCamera* lCamera = (FbxCamera*) pNode->GetNodeAttribute(); lCamera->Position.Set(GetGlobalPosition(pNode, pTime).GetT()); FbxAnimCurve* fc = lCamera->Roll.GetCurve(pAnimLayer); if (fc) lCamera->Roll.Set(fc->Evaluate(pTime)); FbxCamera::EApertureMode lCameraApertureMode = lCamera->GetApertureMode(); if (lCameraApertureMode == FbxCamera::eHorizontal || lCameraApertureMode == FbxCamera::eVertical) { double lFieldOfView = lCamera->FieldOfView.Get(); fc = lCamera->FieldOfView.GetCurve(pAnimLayer); if (fc) lFieldOfView = fc->Evaluate(pTime); //update FOV and focal length lCamera->FieldOfView.Set( lFieldOfView); lCamera->FocalLength.Set( lCamera->ComputeFocalLength( lFieldOfView)); } else if ( lCameraApertureMode == FbxCamera::eHorizAndVert) { double lOldFieldOfViewX = lCamera->FieldOfViewX.Get(); double lOldFieldOfViewY = lCamera->FieldOfViewY.Get(); //update FOV double lNewFieldOfViewX = lOldFieldOfViewX; double lNewFieldOfViewY = lOldFieldOfViewY; fc = lCamera->FieldOfViewX.GetCurve(pAnimLayer); if (fc) lNewFieldOfViewX = fc->Evaluate(pTime); fc = lCamera->FieldOfViewY.GetCurve(pAnimLayer); if (fc) lNewFieldOfViewY = fc->Evaluate(pTime); lCamera->FieldOfViewX.Set(lNewFieldOfViewX); lCamera->FieldOfViewY.Set(lNewFieldOfViewY); //update aspect double lUpdatedApertureX = lCamera->GetApertureWidth(); double lUpdatedApertureY = lCamera->GetApertureHeight(); lUpdatedApertureX *= tan( lNewFieldOfViewX * 0.5 * FBXSDK_PI_DIV_180) / tan( lOldFieldOfViewX * 0.5 * FBXSDK_PI_DIV_180); lUpdatedApertureY *= tan( lNewFieldOfViewY * 0.5 * FBXSDK_PI_DIV_180) / tan( lOldFieldOfViewY * 0.5 * FBXSDK_PI_DIV_180); lCamera->FilmWidth.Set( lUpdatedApertureX); lCamera->FilmHeight.Set( lUpdatedApertureY); lCamera->FilmAspectRatio.Set( lUpdatedApertureX / lUpdatedApertureY); } else if ( lCameraApertureMode == FbxCamera::eFocalLength) { double lFocalLength = lCamera->FocalLength.Get(); fc = lCamera->FocalLength.GetCurve(pAnimLayer); if (fc && fc ->Evaluate(pTime)) lFocalLength = fc->Evaluate( pTime); //update FOV and focal length lCamera->FocalLength.Set( lFocalLength); lCamera->FieldOfView.Set( lCamera->ComputeFieldOfView( lFocalLength)); } }
void WccToFbxExporter::addPositionKeyToNode(FbxNode *pNode, FbxAnimLayer *pAnimLayer, int timeMs, const QVector3D &position) { FbxAnimCurve* lCurve = nullptr; FbxTime lTime; int lKeyIndex = 0; lCurve = pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); if (lCurve) { lCurve->KeyModifyBegin(); lTime.SetMilliSeconds(timeMs); lKeyIndex = lCurve->KeyAdd(lTime); lCurve->KeySet(lKeyIndex, lTime, position.x(), FbxAnimCurveDef::eInterpolationCubic); lCurve->KeyModifyEnd(); } lCurve = pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); if (lCurve) { lCurve->KeyModifyBegin(); lTime.SetMilliSeconds(timeMs); lKeyIndex = lCurve->KeyAdd(lTime); lCurve->KeySet(lKeyIndex, lTime, position.y(), FbxAnimCurveDef::eInterpolationCubic); lCurve->KeyModifyEnd(); } lCurve = pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); if (lCurve) { lCurve->KeyModifyBegin(); lTime.SetMilliSeconds(timeMs); lKeyIndex = lCurve->KeyAdd(lTime); lCurve->KeySet(lKeyIndex, lTime, position.z(), FbxAnimCurveDef::eInterpolationCubic); lCurve->KeyModifyEnd(); } }
void ExportCurve(FbxAnimLayer* lAnimLayer, FbxNode* pNode, const Value& animCurve, uint32_t begin, uint32_t end) { int rx = -1, ry = -1, rz = -1, rw = -1; for (uint32_t i = begin; i < end; i++) { FbxAnimCurve* fbxCurve = NULL; const Value& curve = animCurve[i]; if (strcmp(curve["propertyName"].GetString(), "m_LocalPosition.x") == 0) { fbxCurve = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); } else if (strcmp(curve["propertyName"].GetString(), "m_LocalPosition.y") == 0) { fbxCurve = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); } else if (strcmp(curve["propertyName"].GetString(), "m_LocalPosition.z") == 0) { fbxCurve = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); } else if (strcmp(curve["propertyName"].GetString(), "m_LocalRotation.x") == 0) { rx = i; } else if (strcmp(curve["propertyName"].GetString(), "m_LocalRotation.y") == 0) { ry = i; } else if (strcmp(curve["propertyName"].GetString(), "m_LocalRotation.z") == 0) { rz = i; } else if (strcmp(curve["propertyName"].GetString(), "m_LocalRotation.w") == 0) { rw = i; } if (fbxCurve != NULL) { fbxCurve->KeyModifyBegin(); FbxTime lTime; const Value& time = curve["time"]; const Value& value = curve["value"]; for (uint32_t i = 0; i < time.Size(); i++) { double timeValue = time[i].GetDouble(); double v = value[i].GetDouble(); lTime.SetSecondDouble(timeValue); int lKeyIndex = fbxCurve->KeyAdd(lTime); fbxCurve->KeySetValue(lKeyIndex, v); fbxCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic); } fbxCurve->KeyModifyEnd(); } } // rotation animation will be convert from quaternion to euler angle if (rx != -1) { FbxAnimCurve* fbxCurve[3]; fbxCurve[0] = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); fbxCurve[1] = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); fbxCurve[2] = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); for (int i = 0; i < 3; i++) { fbxCurve[i]->KeyModifyBegin(); } FbxTime lTime; const Value& time = animCurve[rx]["time"]; for (uint32_t i = 0; i < time.Size(); i++) { double timeValue = time[i].GetDouble(); double x = animCurve[rx]["value"][i].GetDouble(); double y = animCurve[ry]["value"][i].GetDouble(); double z = animCurve[rz]["value"][i].GetDouble(); double w = animCurve[rw]["value"][i].GetDouble(); FbxQuaternion qRot(x, y, z, w); FbxVector4 euler = qRot.DecomposeSphericalXYZ(); for (int j = 0; j < 3; j++) { lTime.SetSecondDouble(timeValue); int lKeyIndex = fbxCurve[j]->KeyAdd(lTime); fbxCurve[j]->KeySetValue(lKeyIndex, euler[j]); fbxCurve[j]->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic); } } for (int i = 0; i < 3; i++) { fbxCurve[i]->KeyModifyEnd(); } } }
void FbxToHkxConverter::extractKeyFramesAndAnnotations(hkxScene *scene, FbxNode* fbxChildNode, hkxNode* newChildNode, int animStackIndex) { FbxAMatrix bindPoseMatrix; FbxAnimStack* lAnimStack = NULL; int numAnimLayers = 0; FbxTimeSpan animTimeSpan; if (animStackIndex >= 0) { lAnimStack = m_curFbxScene->GetSrcObject<FbxAnimStack>(animStackIndex); numAnimLayers = lAnimStack->GetMemberCount<FbxAnimLayer>(); animTimeSpan = lAnimStack->GetLocalTimeSpan(); } // Find the time offset (in the "time space" of the FBX file) of the first animation frame FbxTime timePerFrame; timePerFrame.SetTime(0, 0, 0, 1, 0, m_curFbxScene->GetGlobalSettings().GetTimeMode()); const FbxTime startTime = animTimeSpan.GetStart(); const FbxTime endTime = animTimeSpan.GetStop(); const hkReal startTimeSeconds = static_cast<hkReal>(startTime.GetSecondDouble()); const hkReal endTimeSeconds = static_cast<hkReal>(endTime.GetSecondDouble()); int numFrames = 0; bool staticNode = true; if (scene->m_sceneLength == 0) { bindPoseMatrix = fbxChildNode->EvaluateLocalTransform(startTime); } else { hkArray<hkStringOld> annotationStrings; hkArray<hkReal> annotationTimes; HK_ASSERT(0x0, newChildNode->m_keyFrames.getSize() == 0); // Sample each animation frame for (FbxTime time = startTime, priorSampleTime = endTime; time < endTime; priorSampleTime = time, time += timePerFrame, ++numFrames) { FbxAMatrix frameMatrix = fbxChildNode->EvaluateLocalTransform(time); staticNode = staticNode && (frameMatrix == bindPoseMatrix); hkMatrix4 mat; // Extract this frame's transform convertFbxXMatrixToMatrix4(frameMatrix, mat); newChildNode->m_keyFrames.pushBack(mat); // Extract all annotation strings for this frame using the deprecated // pipeline (new annotations are extracted when sampling attributes) if (m_options.m_exportAnnotations && numAnimLayers > 0) { FbxProperty prop = fbxChildNode->GetFirstProperty(); while(prop.IsValid()) { FbxString propName = prop.GetName(); FbxDataType lDataType = prop.GetPropertyDataType(); hkStringOld name(propName.Buffer(), (int) propName.GetLen()); if (name.asUpperCase().beginsWith("HK") && lDataType.GetType() == eFbxEnum) { FbxAnimLayer* lAnimLayer = lAnimStack->GetMember<FbxAnimLayer>(0); FbxAnimCurve* lAnimCurve = prop.GetCurve(lAnimLayer); int currentKeyIndex; const int keyIndex = (int) lAnimCurve->KeyFind(time, ¤tKeyIndex); const int priorKeyIndex = (int) lAnimCurve->KeyFind(priorSampleTime); // Only store annotations on frames where they're explicitly keyframed, or if this is the first keyframe if (priorKeyIndex != keyIndex) { const int currentEnumValueIndex = keyIndex < 0 ? (int) lAnimCurve->Evaluate(priorSampleTime) : (int) lAnimCurve->Evaluate(time); HK_ASSERT(0x0, currentEnumValueIndex < prop.GetEnumCount()); const char* enumValue = prop.GetEnumValue(currentEnumValueIndex); hkxNode::AnnotationData& annotation = newChildNode->m_annotations.expandOne(); annotation.m_time = (hkReal) (time - startTime).GetSecondDouble(); annotation.m_description = (name + hkStringOld(enumValue, hkString::strLen(enumValue))).cString(); } } prop = fbxChildNode->GetNextProperty(prop); } } } } // Replace animation key data for static nodes with just 1 or 2 frames of bind pose data if (staticNode) { // Static nodes in animated scene data are exported with two keys const bool exportTwoFramesForStaticNodes = (numFrames > 1); // replace transform newChildNode->m_keyFrames.setSize(exportTwoFramesForStaticNodes ? 2: 1); newChildNode->m_keyFrames.optimizeCapacity(0, true); // convert the bind pose transform to Havok format convertFbxXMatrixToMatrix4(bindPoseMatrix, newChildNode->m_keyFrames[0]); if (exportTwoFramesForStaticNodes) { newChildNode->m_keyFrames[1] = newChildNode->m_keyFrames[0]; } } // Extract all times of actual keyframes for the current node... this can be used by Vision if ( m_options.m_storeKeyframeSamplePoints && newChildNode->m_keyFrames.getSize() > 2 && numAnimLayers > 0 ) { FbxAnimLayer* lAnimLayer = lAnimStack->GetMember<FbxAnimLayer>(0); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_TRANSLATION, newChildNode, startTimeSeconds, endTimeSeconds); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_ROTATION, newChildNode, startTimeSeconds, endTimeSeconds); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_SCALING, newChildNode, startTimeSeconds, endTimeSeconds); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, newChildNode, startTimeSeconds, endTimeSeconds); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, newChildNode, startTimeSeconds, endTimeSeconds); extractKeyTimes(fbxChildNode, lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, newChildNode, startTimeSeconds, endTimeSeconds); if (newChildNode->m_linearKeyFrameHints.getSize() > 1) { hkSort(newChildNode->m_linearKeyFrameHints.begin(), newChildNode->m_linearKeyFrameHints.getSize()); } } }
void readKeys(FbxAnimCurve* curveX, FbxAnimCurve* curveY, FbxAnimCurve* curveZ, const FbxDouble3& defaultValue, std::vector<osgAnimation::Vec3CubicBezierKeyframe>& keyFrameCntr, float scalar = 1.0f) { FbxAnimCurve* curves[3] = {curveX, curveY, curveZ}; typedef std::set<double> TimeSet; typedef std::map<double, osgAnimation::FloatCubicBezier> TimeValueMap; TimeSet times; TimeValueMap curveTimeMap[3]; for (int nCurve = 0; nCurve < 3; ++nCurve) { FbxAnimCurve* pCurve = curves[nCurve]; int nKeys = pCurve ? pCurve->KeyGetCount() : 0; if (!nKeys) { times.insert(0.0); curveTimeMap[nCurve][0.0] = osgAnimation::FloatCubicBezier(defaultValue[nCurve] * scalar); } for (int i = 0; i < nKeys; ++i) { double fTime = pCurve->KeyGetTime(i).GetSecondDouble(); float val = pCurve->KeyGetValue(i); times.insert(fTime); FbxAnimCurveTangentInfo leftTangent = pCurve->KeyGetLeftDerivativeInfo(i); FbxAnimCurveTangentInfo rightTangent = pCurve->KeyGetRightDerivativeInfo(i); if (i > 0) { leftTangent.mDerivative *= fTime - pCurve->KeyGetTime(i - 1).GetSecondDouble(); } if (i + 1 < pCurve->KeyGetCount()) { rightTangent.mDerivative *= pCurve->KeyGetTime(i + 1).GetSecondDouble() - fTime; } osgAnimation::FloatCubicBezier key( val * scalar, (val - leftTangent.mDerivative / 3.0) * scalar, (val + rightTangent.mDerivative / 3.0) * scalar); curveTimeMap[nCurve][fTime] = key; } } for (TimeSet::iterator it = times.begin(); it != times.end(); ++it) { double fTime = *it; osg::Vec3 val, cpIn, cpOut; for (int i = 0; i < 3; ++i) { if (curveTimeMap[i].empty()) continue; TimeValueMap::iterator lb = curveTimeMap[i].lower_bound(fTime); if (lb == curveTimeMap[i].end()) --lb; val[i] = lb->second.getPosition(); cpIn[i] = lb->second.getControlPointIn(); cpOut[i] = lb->second.getControlPointOut(); } keyFrameCntr.push_back(osgAnimation::Vec3CubicBezierKeyframe(fTime, osgAnimation::Vec3CubicBezier(val, cpIn, cpOut))); } }
//-------------------------------------------------------------- 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; } } } } } }
void FBXConverter::processAnimations( FbxNode* node , std::vector<JointData> &skeleton , std::vector<VertexData> &verts , std::vector<IndexData> &indices ) { FbxMesh* theMesh = node->GetMesh(); FbxAnimStack* animationStack = node->GetScene()->GetSrcObject<FbxAnimStack>(); FbxAnimLayer* animationLayer = animationStack->GetMember<FbxAnimLayer>(); std::vector<FbxTime> frames; for ( int curveNodeIndex = 0; curveNodeIndex < animationLayer->GetMemberCount(); ++curveNodeIndex ) { FbxAnimCurveNode* currentCurve = animationLayer->GetMember<FbxAnimCurveNode>( curveNodeIndex ); for ( unsigned int channelIndex = 0; channelIndex < currentCurve->GetChannelsCount(); ++channelIndex ) { for ( int curve = 0; curve < currentCurve->GetCurveCount( channelIndex ); ++curve ) { FbxAnimCurve* theCurveVictim = currentCurve->GetCurve( channelIndex , curve ); for ( int keyIndex = 0; keyIndex < theCurveVictim->KeyGetCount(); ++keyIndex ) { bool alreadyIn = false; for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex ) { if ( ( unsigned int ) frames[frameIndex].GetFrameCount() == ( unsigned int ) theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() ) { alreadyIn = true; //std::cout << frames[frameIndex].GetFrameCount() << " " << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl; break; } } std::cout << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl; if(!alreadyIn) frames.push_back(theCurveVictim->KeyGet( keyIndex ).GetTime()); } } } } std::sort( frames.begin() , frames.end() , frameCompare ); FbxAMatrix geoTransform( node->GetGeometricTranslation( FbxNode::eSourcePivot ) , node->GetGeometricRotation( FbxNode::eSourcePivot ) , node->GetGeometricScaling( FbxNode::eSourcePivot ) ); for ( int i = 0; i < theMesh->GetDeformerCount(); ++i ) { FbxSkin* theSkin = reinterpret_cast< FbxSkin* >( theMesh->GetDeformer( i , FbxDeformer::eSkin ) ); if ( !theSkin ) continue; for ( int j = 0; j < theSkin->GetClusterCount(); ++j ) { FbxCluster* cluster = theSkin->GetCluster( j ); std::string jointName = cluster->GetLink()->GetName(); int currentJointIndex = -1; for ( unsigned int k = 0; k < skeleton.size(); ++k ) { if ( !skeleton[k].name.compare( jointName ) ) { currentJointIndex = k; break; } } if ( currentJointIndex < 0 ) { std::cout << "wrong bone" << std::endl; continue; } FbxAMatrix transformMatrix, transformLinkMatrix, offsetMatrix; cluster->GetTransformMatrix( transformMatrix ); cluster->GetTransformLinkMatrix( transformLinkMatrix ); //offsetMatrix = transformLinkMatrix.Inverse() * transformMatrix * geoTransform; FbxMatrix realMatrix( transformLinkMatrix.Inverse() * transformMatrix ); for ( unsigned int row = 0; row < 4; ++row ) { for ( unsigned int column = 0; column < 4; ++column ) { skeleton[currentJointIndex].offsetMatrix[row][column] = (float)realMatrix.Get( row , column ); } } for ( int k = 0; k < cluster->GetControlPointIndicesCount(); ++k ) { BlendingIndexWeightPair weightPair; weightPair.blendingIndex = currentJointIndex; weightPair.blendingWeight = (float)cluster->GetControlPointWeights()[k]; unsigned int controlPoint = cluster->GetControlPointIndices()[k]; for ( unsigned int z = 0; z < indices.size(); ++z ) { if ( indices[z].oldControlPoint == controlPoint ) { if ( verts[indices[z].index].blendingInfo.size() > 4 ) { std::cout << "Warning: vert has more than 4 bones connected, ignoring additional bone." << std::endl; } //else verts[indices[z].index].blendingInfo.push_back( weightPair ); bool found = false; for ( unsigned int omg = 0; omg < verts[indices[z].index].blendingInfo.size(); ++omg ) { if ( verts[indices[z].index].blendingInfo[omg].blendingIndex == weightPair.blendingIndex ) { found = true; break; } } if ( !found ) verts[indices[z].index].blendingInfo.push_back( weightPair ); } } } for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex ) { FbxVector4 translation = cluster->GetLink()->EvaluateLocalTranslation( frames[frameIndex] ); FbxVector4 rotation = cluster->GetLink()->EvaluateLocalRotation( frames[frameIndex] ); FbxVector4 scale = cluster->GetLink()->EvaluateLocalScaling( frames[frameIndex] ); AnimationData animData; animData.frame = (int)frames[frameIndex].GetFrameCount(); animData.translation = glm::vec3(translation[0],translation[1],translation[2]); animData.rotation = glm::angleAxis( glm::radians( (float)rotation[2] ), glm::vec3(0,0,1)) * glm::angleAxis(glm::radians((float) rotation[1]), glm::vec3(0,1,0)) * glm::angleAxis(glm::radians((float)rotation[0]), glm::vec3(1,0,0)); animData.scale = glm::vec3(scale[0],scale[1],scale[2]); skeleton[currentJointIndex].animation.push_back( animData ); } } } }
void ofxFBXScene::parseScaleCurve(ofxFBXNode & node, FbxAnimLayer * pAnimLayer, FbxPropertyT<FbxDouble3> &scale){ node.originalScale = toOf(scale.Get()); node.getNode().setScale(node.originalScale); ofLogVerbose("ofxFBXScene") << "original scale " << node.originalScale << endl; if(!scale.GetCurve(pAnimLayer)) return; FbxAnimCurve* lAnimCurveX = scale.GetCurve(pAnimLayer,"X"); FbxAnimCurve* lAnimCurveY = scale.GetCurve(pAnimLayer,"Y"); FbxAnimCurve* lAnimCurveZ = scale.GetCurve(pAnimLayer,"Z"); FbxTime lKeyTime; int lCount; int xKeyCount = lAnimCurveX? lAnimCurveX->KeyGetCount() : 0; int yKeyCount = lAnimCurveY? lAnimCurveY->KeyGetCount() : 0; int zKeyCount = lAnimCurveZ? lAnimCurveZ->KeyGetCount() : 0; ofxFBXKey<float> key; for(lCount = 0; lCount < xKeyCount; lCount++) { key.value = lAnimCurveX->KeyGetValue(lCount); lKeyTime = lAnimCurveX->KeyGetTime(lCount); key.timeMillis = lKeyTime.GetMilliSeconds(); node.xScaleKeys.push_back(key); } for(lCount = 0; lCount < yKeyCount; lCount++) { key.value = lAnimCurveY->KeyGetValue(lCount); lKeyTime = lAnimCurveY->KeyGetTime(lCount); key.timeMillis = lKeyTime.GetMilliSeconds(); node.yScaleKeys.push_back(key); } for(lCount = 0; lCount < zKeyCount; lCount++) { key.value = lAnimCurveZ->KeyGetValue(lCount); lKeyTime = lAnimCurveZ->KeyGetTime(lCount); key.timeMillis = lKeyTime.GetMilliSeconds(); node.zScaleKeys.push_back(key); } }
void fbxLoader2::processMesh(FbxNode* node) { FbxMesh* mesh = node->GetMesh(); this->readAnimationWeigths(mesh); if(mesh!=NULL && mesh->IsTriangleMesh()) { for (int i = 0; i<mesh->GetControlPointsCount(); i++) { readVertex(mesh, i, &vertex[i]); vertexArray[i].position = D3DXVECTOR3(vertex[i]); } int a = mesh->GetPolygonVertexCount(); for (int i = 0; i<mesh->GetPolygonVertexCount(); i++) { readUV(mesh, i, 0, &uv[i]); readNormal(mesh, i, &normal[i]); indices[i].indice = mesh->GetPolygonVertices()[i]; indices[i].normal1 = normal[i]; indices[i].uv1 = uv[i]; indicesMeshCount++; } } //vertexLists.push_back(vertexArray); indiceLists.push_back(indices); FbxAnimStack* pAnimStack = FbxCast<FbxAnimStack>(scene->GetSrcObject(FBX_TYPE(FbxAnimStack))); int numAnimLayers = pAnimStack->GetMemberCount(FBX_TYPE(FbxAnimLayer)); this->setBindPoseCluster(node); for (int i = 0; i < numAnimLayers; i++) { FbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(FbxAnimLayer), i); FbxAnimCurve* animCv = this->findSkeletonRootBone(scene->GetRootNode())->GetChild(0)->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); if (animCv) { FbxTimeSpan animationLength; int p = animCv->KeyGetCount(); animCv->GetTimeInterval(animationLength); for(int j = 0; j<animationStructure->GetFramesNumber();j++) { FbxTime timeKey = animCv->KeyGet(j).mTime; //FbxTime interval = (duration/p)*j + animationLength.GetStart(); //int intervalVal = (duration.GetSecondCount()/p)*j + animationLength.GetStart().GetSecondCount(); const FbxTime pTime = animCv->KeyGet(j).mTime; FbxAMatrix pGlobalPos = GetGlobalPosition(node, pTime, scene->GetPose(j)); ComputeSkinDeformation(pGlobalPos, mesh, timeKey, scene->GetPose(j), j); } } } for(int i = 0; i<node->GetChildCount(); i++) { processMesh(node->GetChild(i)); } }
// Find the current camera at the given time. FbxCamera* GetCurrentCamera(FbxScene* pScene, FbxTime& pTime, FbxAnimLayer* pAnimLayer, const FbxArray<FbxNode*>& pCameraArray) { FbxGlobalSettings& lGlobalSettings = pScene->GetGlobalSettings(); FbxGlobalCameraSettings& lGlobalCameraSettings = pScene->GlobalCameraSettings(); FbxString lCurrentCameraName = lGlobalSettings.GetDefaultCamera(); // check if we need to create the Producer cameras! if (lGlobalCameraSettings.GetCameraProducerPerspective() == NULL && lGlobalCameraSettings.GetCameraProducerBottom() == NULL && lGlobalCameraSettings.GetCameraProducerTop() == NULL && lGlobalCameraSettings.GetCameraProducerFront() == NULL && lGlobalCameraSettings.GetCameraProducerBack() == NULL && lGlobalCameraSettings.GetCameraProducerRight() == NULL && lGlobalCameraSettings.GetCameraProducerLeft() == NULL) { lGlobalCameraSettings.CreateProducerCameras(); } if (lCurrentCameraName.Compare(FBXSDK_CAMERA_PERSPECTIVE) == 0) { return lGlobalCameraSettings.GetCameraProducerPerspective(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_BOTTOM) == 0) { return lGlobalCameraSettings.GetCameraProducerBottom(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_TOP) == 0) { return lGlobalCameraSettings.GetCameraProducerTop(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_FRONT) == 0) { return lGlobalCameraSettings.GetCameraProducerFront(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_BACK) == 0) { return lGlobalCameraSettings.GetCameraProducerBack(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_RIGHT) == 0) { return lGlobalCameraSettings.GetCameraProducerRight(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_LEFT) == 0) { return lGlobalCameraSettings.GetCameraProducerLeft(); } else if (lCurrentCameraName.Compare(FBXSDK_CAMERA_SWITCHER) == 0) { FbxCameraSwitcher* lCameraSwitcher = pScene->GlobalCameraSettings().GetCameraSwitcher(); FbxAnimCurve* lCurve = NULL; if (lCameraSwitcher) { lCurve = lCameraSwitcher->CameraIndex.GetCurve(pAnimLayer); int lCameraIndex = lCurve ? int(lCurve->Evaluate(pTime)) - 1 : 0; if (lCameraIndex >= 0 && lCameraIndex < pCameraArray.GetCount()) { FbxNode* lNode = pCameraArray[lCameraIndex]; // Get the animated parameters of the camera. GetCameraAnimatedParameters(lNode, pTime, pAnimLayer); return (FbxCamera*) lNode->GetNodeAttribute(); } } } else { int i; FbxNode* lNode = NULL; // Find the camera in the camera array. for (i = 0; i < pCameraArray.GetCount(); i++) { if (lCurrentCameraName.Compare(pCameraArray[i]->GetName()) == 0) { lNode = pCameraArray[i]; break; } } if (lNode) { // Get the animated parameters of the camera. GetCameraAnimatedParameters(lNode, pTime, pAnimLayer); return (FbxCamera*) lNode->GetNodeAttribute(); } } return lGlobalCameraSettings.GetCameraProducerPerspective(); }