Example #1
0
		void FbxLoader::LoadAnimationClipData()
		{
			// load animation data
			const int animCount = scene->GetSrcObjectCount<FbxAnimStack>();

			for(int ac = 0; ac < animCount; ++ac) {
				FbxAnimStack* currAnimStack = scene->GetSrcObject<FbxAnimStack>(ac);
				if(!currAnimStack) return;

				FbxString animStackName = currAnimStack->GetName();
				FbxTakeInfo* takeInfo = scene->GetTakeInfo(animStackName);

				if(!takeInfo) return;
				FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
				FbxTime stop = takeInfo->mLocalTimeSpan.GetStop();
				FbxTime::EMode mode = FbxTime::eDefaultMode;
				int startFrame = (int)start.GetFrameCount(mode);
				int stopFrame = (int)stop.GetFrameCount(mode);
				int animLength = stopFrame - startFrame + 1;

				shared_ptr<AnimClip> clip = make_shared<AnimClip>();
				clip->name = animStackName;
				animationClips[clip->name] = clip;
			}
		}
Example #2
0
std::string OsgFbxReader::readFbxAnimation(FbxNode* pNode, const char* targetName)
{
    std::string result;
    for (int i = 0; i < fbxScene.GetSrcObjectCount<FbxAnimStack>(); ++i)
    {
        FbxAnimStack* pAnimStack = FbxCast<FbxAnimStack>(fbxScene.GetSrcObject<FbxAnimStack>(i));

        int nbAnimLayers = pAnimStack->GetMemberCount<FbxAnimLayer>();

        const char* pTakeName = pAnimStack->GetName();

        if (!pTakeName || !*pTakeName)
            continue;

        for (int j = 0; j < nbAnimLayers; j++)
        {
            FbxAnimLayer* pAnimLayer = pAnimStack->GetMember<FbxAnimLayer>(j);
            osgAnimation::Animation* pAnimation = ::readFbxAnimation(pNode, pAnimLayer, pTakeName, targetName, pAnimationManager);
            if (pAnimation)
            {
                result = targetName;
            }
        }
    }
    return result;
}
void Tools::DisplayAnimation::DisplayAnimation(FbxScene* i_scene)
{
	DisplayCommon::DisplayString( "\n\n--------------------\nAnimation\n--------------------" );

	int i;
	for ( i = 0; i < i_scene->GetSrcObjectCount<FbxAnimStack>(); i++ )
	{
		FbxAnimStack *animStack = i_scene->GetSrcObject<FbxAnimStack>( i );

		FbxString string = "Animation Stack Name: ";
		string += animStack->GetName();
		string += "\n";
		FBXSDK_printf( string );
		DisplayCommon::DisplayString( string );

		DisplayAnimation( animStack, i_scene->GetRootNode(), true );
		DisplayAnimation( animStack, i_scene->GetRootNode() );
	}
}
/**
* Add to the animation set, the animations contained within the FBX document, for the given skeleton
*/
UAnimSequence * UnFbx::FFbxImporter::ImportAnimations(USkeleton* Skeleton, UObject* Outer, TArray<FbxNode*>& SortedLinks, const FString& Name, UFbxAnimSequenceImportData* TemplateImportData, TArray<FbxNode*>& NodeArray)
{
	// we need skeleton to create animsequence
	if (Skeleton == NULL)
	{
		return NULL;
	}

	int32 ValidTakeCount = 0;
	if (IsValidAnimationData(SortedLinks, NodeArray, ValidTakeCount) == false)
	{
		AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Warning, LOCTEXT("FBXImport_InvalidAnimationData", "This does not contain any valid animation takes.")), FFbxErrors::Animation_InvalidData);
		return NULL;
	}

	UAnimSequence* LastCreatedAnim = NULL;

	int32 ResampleRate = DEFAULT_SAMPLERATE;
	if ( ImportOptions->bResample )
	{
		// For FBX data, "Frame Rate" is just the speed at which the animation is played back.  It can change
		// arbitrarily, and the underlying data can stay the same.  What we really want here is the Sampling Rate,
		// ie: the number of animation keys per second.  These are the individual animation curve keys
		// on the FBX nodes of the skeleton.  So we loop through the nodes of the skeleton and find the maximum number 
		// of keys that any node has, then divide this by the total length (in seconds) of the animation to find the 
		// sampling rate of this set of data 

		// we want the maximum resample rate, so that we don't lose any precision of fast anims,
		// and don't mind creating lerped frames for slow anims
		int32 MaxStackResampleRate = GetMaxSampleRate(SortedLinks, NodeArray);

		if(MaxStackResampleRate != 0)
		{
			ResampleRate = MaxStackResampleRate;
		}

	}

	int32 AnimStackCount = Scene->GetSrcObjectCount<FbxAnimStack>();
	for( int32 AnimStackIndex = 0; AnimStackIndex < AnimStackCount; AnimStackIndex++ )
	{
		FbxAnimStack* CurAnimStack = Scene->GetSrcObject<FbxAnimStack>(AnimStackIndex);

		FbxTimeSpan AnimTimeSpan = GetAnimationTimeSpan(SortedLinks[0], CurAnimStack);
		bool bValidAnimStack = ValidateAnimStack(SortedLinks, NodeArray, CurAnimStack, ResampleRate, ImportOptions->bImportMorph, AnimTimeSpan);
		// no animation
		if (!bValidAnimStack)
		{
			continue;
		}
		
		FString SequenceName = Name;

		if (ValidTakeCount > 1)
		{
			SequenceName += "_";
			SequenceName += UTF8_TO_TCHAR(CurAnimStack->GetName());
		}

		// See if this sequence already exists.
		SequenceName = ObjectTools::SanitizeObjectName(SequenceName);

		FString 	ParentPath = FString::Printf(TEXT("%s/%s"), *FPackageName::GetLongPackagePath(*Outer->GetName()), *SequenceName);
		UObject* 	ParentPackage = CreatePackage(NULL, *ParentPath);
		UObject* Object = LoadObject<UObject>(ParentPackage, *SequenceName, NULL, LOAD_None, NULL);
		UAnimSequence * DestSeq = Cast<UAnimSequence>(Object);
		// if object with same name exists, warn user
		if (Object && !DestSeq)
		{
			AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("Error_AssetExist", "Asset with same name exists. Can't overwrite another asset")), FFbxErrors::Generic_SameNameAssetExists);
			continue; // Move on to next sequence...
		}

		// If not, create new one now.
		if(!DestSeq)
		{
			DestSeq = NewObject<UAnimSequence>(ParentPackage, *SequenceName, RF_Public | RF_Standalone);
	
			// Notify the asset registry
			FAssetRegistryModule::AssetCreated(DestSeq);
		}
		else
		{
			DestSeq->RecycleAnimSequence();
		}

		DestSeq->SetSkeleton(Skeleton);

		// since to know full path, reimport will need to do same
		UFbxAnimSequenceImportData* ImportData = UFbxAnimSequenceImportData::GetImportDataForAnimSequence(DestSeq, TemplateImportData);
		ImportData->Update(UFactory::CurrentFilename);

		ImportAnimation(Skeleton, DestSeq, Name, SortedLinks, NodeArray, CurAnimStack, ResampleRate, AnimTimeSpan);

		LastCreatedAnim = DestSeq;
	}

	return LastCreatedAnim;
}
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 );
}
// This method is templated on the implementation of hctMayaSceneExporter/hctMaxSceneExporter::createScene()
bool FbxToHkxConverter::createSceneStack(int animStackIndex)
{
	hkxScene *scene = new hkxScene;

	scene->m_modeller.set(m_modeller.cString());
	scene->m_asset = m_curFbxScene->GetSceneInfo()->Original_FileName.Get();

	if (m_rootNode) 
	{
		// create root node
		hkxNode* rootNode = new hkxNode;
		bool rigPass = (animStackIndex == -1);
		int currentAnimStackIndex = -1;

		FbxAnimStack* lAnimStack = NULL;
		
		if (rigPass && m_numAnimStacks > 0)
		{
			currentAnimStackIndex = 0;
		}
		else if (animStackIndex >= 0)
		{
			currentAnimStackIndex = animStackIndex;
		}
		
		if (currentAnimStackIndex != -1)
		{
			lAnimStack = m_curFbxScene->GetSrcObject<FbxAnimStack>(currentAnimStackIndex);
			m_curFbxScene->GetEvaluator()->SetContext(lAnimStack);
		}

		if (rigPass)
		{
			rootNode->m_name = "ROOT_NODE";
			scene->m_sceneLength = 0.f;
			scene->m_numFrames = 1;
			printf("Converting nodes for root...\n");
		}
		else
		{
			rootNode->m_name = lAnimStack->GetName();

			const FbxTimeSpan animTimeSpan = lAnimStack->GetLocalTimeSpan();
			scene->m_sceneLength = static_cast<hkReal>( animTimeSpan.GetDuration().GetSecondDouble() );
			scene->m_numFrames = static_cast<hkUint32>( animTimeSpan.GetDuration().GetFrameCount(m_curFbxScene->GetGlobalSettings().GetTimeMode()) );
			
			printf("Converting nodes for [%s]...\n", rootNode->m_name.cString());
		}

		scene->m_rootNode = rootNode;
		rootNode->removeReference();

		// Setup (identity) keyframes(s) for the 'static' root node
		rootNode->m_keyFrames.setSize( scene->m_numFrames > 1 ? 2 : 1, hkMatrix4::getIdentity() );

		addNodesRecursive(scene, m_rootNode, scene->m_rootNode, currentAnimStackIndex);
	}

	m_scenes.pushBack(scene);

	return true;
}
Example #7
0
//===============================================================================================================================
void FBXLoader::LoadJointsAndAnimation(FbxNode* inNode)
{
	// This is how each subset gets its bone/joint for animation
	FBXSubsets* subset = mSubsets[iCurrentSubset];
	
	FbxMesh* mesh = inNode->GetMesh();
	
	uint32 numOfDeformers = mesh->GetDeformerCount();
	
	FbxAMatrix geomTrans = ZShadeSandboxMesh::FBXHelper::GetGeometryTransformation(inNode);
	
	// A deformer contains clusters.
	// A cluster contains a link, which is a joint.
	// Normally, There is only one deformer in a mesh but Maya has many types.
	for (uint32 deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex)
	{
		// Lets see if this deformer is a skin
		FbxSkin* skin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
		
		if (!skin) continue;
		
		uint32 numOfClusters = skin->GetClusterCount();
		
		for (uint32 clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex)
		{
			FbxCluster* cluster = skin->GetCluster(clusterIndex);
			
			string jointName = cluster->GetLink()->GetName();
			uint32 jointIndex = FindJointIndexUsingName(jointName);
			
			subset->mJoints.push_back(jointIndex);
			
			FbxAMatrix transform;
			FbxAMatrix transformLink;
			FbxAMatrix globalBindposeInverse;
			
			// The transformation of the mesh at binding time
			cluster->GetTransformMatrix(transform);
			
			// The transformation of the cluster (joint) at binding time from joint space to world space
			cluster->GetTransformLinkMatrix(transformLink);
			
			globalBindposeInverse = transformLink.Inverse() * transform * geomTrans;
			
			
			// Update skeletal information
			mSkeleton.joints[jointIndex].globalBindposeInverse = globalBindposeInverse;
			mSkeleton.joints[jointIndex].node = cluster->GetLink();
			
			// Associate each joint with the control points it affects
			uint32 numOfIndices = cluster->GetControlPointIndicesCount();
			
			for (uint32 i = 0; i < numOfIndices; ++i)
			{
				ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair;
				currBlendingIndexWeightPair.blendingIndex = jointIndex;
				currBlendingIndexWeightPair.blendingWeight = cluster->GetControlPointWeights()[i];
				mControlPoints[cluster->GetControlPointIndices()[i]]->blendingInfo.push_back(currBlendingIndexWeightPair);
			}
			
			// Animation information
			FbxAnimStack* animStack = m_pFbxScene->GetSrcObject<FbxAnimStack>(0);
			FbxString animStackName = animStack->GetName();
			mAnimationName = animStackName.Buffer();
			FbxTakeInfo* takeInfo = m_pFbxScene->GetTakeInfo(animStackName);
			FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
			FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
			mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;
			FBXKeyframe** anim = &mSkeleton.joints[jointIndex].animation;
			
			for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i)
			{
				FbxTime time;
				time.SetFrame(i, FbxTime::eFrames24);
				*anim = new FBXKeyframe();
				(*anim)->frameNum = i;
				FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(time) * geomTrans;
				(*anim)->globalTransform = currentTransformOffset.Inverse() * cluster->GetLink()->EvaluateGlobalTransform(time);
				anim = &((*anim)->next);
			}
		}
	}
	
	// Some control points have less than 4 joints
	// For a normal renderer, there are usually 4 joints
	ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair;
	currBlendingIndexWeightPair.blendingIndex = 0;
	currBlendingIndexWeightPair.blendingWeight = 0;
	for (auto itr = mControlPoints.begin(); itr != mControlPoints.end(); ++itr)
	{
		for (unsigned int i = itr->second->blendingInfo.size(); i <= 4; ++i)
		{
			itr->second->blendingInfo.push_back(currBlendingIndexWeightPair);
		}
	}
}
Example #8
0
    //-----------------------------------------------------------------------------------
    static void ImportMotions(SceneImport* import, FbxScene* scene, Matrix4x4& matrixStackTop, std::map<int, FbxNode*>& map, float framerate)
    {
        int animationCount = scene->GetSrcObjectCount<FbxAnimStack>();
        if (animationCount == 0)
        {
            return;
        }
        if (import->skeletons.size() == 0)
        {
            return;
        }

        //Timing information for animation in this scene. How fast is the framerate in this file?
        FbxGlobalSettings& settings = scene->GetGlobalSettings();
        FbxTime::EMode timeMode = settings.GetTimeMode();
        double sceneFramerate;
        if (timeMode == FbxTime::eCustom)
        {
            sceneFramerate = settings.GetCustomFrameRate();
        }
        else
        {
            sceneFramerate = FbxTime::GetFrameRate(timeMode);
        }

        //Only supporting one skeleton for now, update when needed.
        uint32_t skeletonCount = import->skeletons.size();
        Skeleton* skeleton= import->skeletons.at(0);
        ASSERT_OR_DIE(skeletonCount == 1, "Had multiple skeletons, we only support 1!");

        //Time between frames
        FbxTime advance;
        advance.SetSecondDouble((double)(1.0f / framerate));

        for (int animIndex = 0; animIndex < animationCount; ++animIndex)
        {
            //Import Motions
            FbxAnimStack* anim = scene->GetSrcObject<FbxAnimStack>();
            if (nullptr == anim)
            {
                continue;
            }

            FbxTime startTime = anim->LocalStart;
            FbxTime endTime = anim->LocalStop;
            FbxTime duration = endTime - startTime;

            scene->SetCurrentAnimationStack(anim);

            const char* motionName = anim->GetName();
            float timeSpan = duration.GetSecondDouble();
            AnimationMotion* motion = new AnimationMotion(motionName, timeSpan, framerate, skeleton);

            int jointCount = skeleton->GetJointCount();
            for (int jointIndex = 0; jointIndex < jointCount; ++jointIndex)
            {
                FbxNode* node = map[jointIndex];

                //Extracting world position
                //local, you would need to grab parent as well
                Matrix4x4* boneKeyframes = motion->GetJointKeyframes(jointIndex);

                FbxTime evalTime = FbxTime(0);
                for (uint32_t frameIndex = 0; frameIndex < motion->m_frameCount; ++frameIndex)
                {
                    Matrix4x4* boneKeyframe = boneKeyframes + frameIndex;

                    Matrix4x4 boneTransform = GetNodeWorldTransformAtTime(node, evalTime, matrixStackTop);
                    double seconds = evalTime.GetSecondDouble();
                    seconds = seconds;
                    *boneKeyframe = boneTransform;

                    evalTime += advance;
                }
            }
            import->motions.push_back(motion);
        }
    }