void FVertexAnimTools::ImportVertexAnimtion(UnFbx::FFbxImporter* FFbxImporter, USkeletalMesh * SkelMesh, UPackage * Package, FString& Filename)
{
	check(SkelMesh);
	check(SkelMesh->GetImportedResource()->LODModels.Num() > 0);
	FStaticLODModel& Model = SkelMesh->GetImportedResource()->LODModels[0];
	if(Model.MeshToImportVertexMap.Num() == 0)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Mesh does not contain necessary vertex anim mapping."));
		return;
	}

	FbxNode* RootNodeToImport = FFbxImporter->Scene->GetRootNode();

	/* Exporting from Maya with skin and vertex cache seems to throw away the skin deformer, so not sure how to find the 'right' mesh...
	TArray<FbxNode*> MeshArray;
	FName RootBoneName = (SkelMesh->Skeleton)? SkelMesh->Skeleton->GetBoneName(0) : SkelMesh->RefSkeleton.RefBoneInfo(0).Name;
	FFbxImporter->FindFBXMeshesByBone(RootBoneName, false, MeshArray);
	*/

	// Find mesh with vertex deformer
	TArray<FbxMesh*> VertexCacheMeshes;
	RecursiveFindVertexAnimMeshes(RootNodeToImport, VertexCacheMeshes);
	if(VertexCacheMeshes.Num() == 0)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: No vertex cache deformed mesh found."));
		return;
	}

	// Get deformer and open cache
	FbxMesh* Mesh = VertexCacheMeshes[0];
	FbxVertexCacheDeformer* Deformer = static_cast<FbxVertexCacheDeformer*>(Mesh->GetDeformer(0, FbxDeformer::eVertexCache));
	check(Deformer != NULL); // tested in RecursiveFindVertexAnimMeshes
	FbxCache* Cache = Deformer->GetCache();
	bool bOpenSuccess = Cache->OpenFileForRead();
	if(!bOpenSuccess)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Unable to open cache file."));
		return;
	}

	// Check cache format
	if(Cache->GetCacheFileFormat() != FbxCache::eMayaCache)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Only Maya vertex animation supported."));
		return;
	}

	// Get channel
	FbxString DeformerChannelName = Deformer->Channel.Get();
	int ChannelIndex = Cache->GetChannelIndex(DeformerChannelName);
	if(ChannelIndex == -1)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: No Cache channel for deformer."));
		return;
	}

	// Get data type
	FbxCache::EMCDataType DataType;
	bool bGetDataTypeOk = Cache->GetChannelDataType(ChannelIndex, DataType);
	check(bGetDataTypeOk);
	if(DataType != FbxCache::EMCDataType::eDoubleVectorArray)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Only double array format supported at the moment."));
		return;
	}

	// Get other info about anim
	FbxTime StartTime, DeltaTime;
	int32 NumFrames, NumAnimatedPoints;
	bool bInfoOk = GetVertexAnimInfo(Cache, ChannelIndex, StartTime, DeltaTime, NumFrames, NumAnimatedPoints);
	if(!bInfoOk)
	{
		UE_LOG(LogFbx, Warning, TEXT("ImportVertexAnimtion: Invalid vertex animation."));
		return;
	}

	UVertexAnimation* NewVertexAnim = UnFbx::FFbxImporter::CreateAsset<UVertexAnimation>( Package->GetName(), *FPaths::GetBaseFilename(Filename) );
	if (NewVertexAnim != NULL)
	{
		// Save the mesh we are importing for
		NewVertexAnim->BaseSkelMesh = SkelMesh;
		NewVertexAnim->NumAnimatedVerts = NumAnimatedPoints;

		ConvertCacheToAnim(Cache, ChannelIndex, NewVertexAnim, StartTime, DeltaTime, NumFrames);

		UE_LOG(LogFbx, Log, TEXT("ImportVertexAnimtion: Success! %d frames."), NewVertexAnim->GetNumFrames());
	}
}
Ejemplo n.º 2
0
    void PreparePointCacheData(FbxScene* pScene, FbxTime &pCache_Start, FbxTime &pCache_Stop)
    {
        // This function show how to cycle through scene elements in a linear way.
		const int lNodeCount = pScene->GetSrcObjectCount<FbxNode>();

        for (int lIndex=0; lIndex<lNodeCount; lIndex++)
        {
            FbxNode* lNode = pScene->GetSrcObject<FbxNode>(lIndex);

            if (lNode->GetGeometry()) 
            {
                int i, lVertexCacheDeformerCount = lNode->GetGeometry()->GetDeformerCount(FbxDeformer::eVertexCache);

                // There should be a maximum of 1 Vertex Cache Deformer for the moment
                lVertexCacheDeformerCount = lVertexCacheDeformerCount > 0 ? 1 : 0;

                for (i=0; i<lVertexCacheDeformerCount; ++i )
                {
                    // Get the Point Cache object
                    FbxVertexCacheDeformer* lDeformer = static_cast<FbxVertexCacheDeformer*>(lNode->GetGeometry()->GetDeformer(i, FbxDeformer::eVertexCache));
                    if( !lDeformer ) continue;
                    FbxCache* lCache = lDeformer->GetCache();
                    if( !lCache ) continue;

                    // Process the point cache data only if the constraint is active
                    if (lDeformer->IsActive())
                    {
                        if (lCache->GetCacheFileFormat() == FbxCache::eMaxPointCacheV2)
                        {
                            // This code show how to convert from PC2 to MC point cache format
                            // turn it on if you need it.
#if 0 
                            if (!lCache->ConvertFromPC2ToMC(FbxCache::eMCOneFile, 
                                FbxTime::GetFrameRate(pScene->GetGlobalTimeSettings().GetTimeMode())))
                            {
                                // Conversion failed, retrieve the error here
                                FbxString lTheErrorIs = lCache->GetError().GetLastErrorString();
                            }
#endif
                        }
                        else if (lCache->GetCacheFileFormat() == FbxCache::eMayaCache)
                        {
                            // This code show how to convert from MC to PC2 point cache format
                            // turn it on if you need it.
                            //#if 0 
                            if (!lCache->ConvertFromMCToPC2(FbxTime::GetFrameRate(pScene->GetGlobalSettings().GetTimeMode()), 0))
                            {
                                // Conversion failed, retrieve the error here
                                FbxString lTheErrorIs = lCache->GetError().GetLastErrorString();
                            }
                            //#endif
                        }


                        // Now open the cache file to read from it
                        if (!lCache->OpenFileForRead())
                        {
                            // Cannot open file 
                            FbxString lTheErrorIs = lCache->GetError().GetLastErrorString();

                            // Set the deformer inactive so we don't play it back
                            lDeformer->SetActive(false);
                        }
						else
						{
							// get the start and stop time of the cache
							int lChannelCount = lCache->GetChannelCount();
							
							for (int iChannelNo=0; iChannelNo < lChannelCount; iChannelNo++)
							{
								FbxTime lChannel_Start;
								FbxTime lChannel_Stop;

								if(lCache->GetAnimationRange(iChannelNo, lChannel_Start, lChannel_Stop))
								{
									// get the smallest start time
									if(lChannel_Start < pCache_Start) pCache_Start = lChannel_Start;

									// get the biggest stop time
									if(lChannel_Stop  > pCache_Stop)  pCache_Stop  = lChannel_Stop;
								}
							}
						}
                    }
                }
            }
        }
    }