/**
* 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;
}
Esempio n. 2
0
bool ModelImporter::ImportAnimations()
{
    if (!animationInfo_.Size())
    {
       if (!ImportAnimation(asset_->GetPath(), "RootAnim"))
           return false;
    }

    // embedded animations
    for (unsigned i = 0; i < animationInfo_.Size(); i++)
    {
        const SharedPtr<AnimationImportInfo>& info = animationInfo_[i];
        if (!ImportAnimation(asset_->GetPath(), info->GetName(), info->GetStartTime(), info->GetEndTime()))
            return false;
    }

    // add @ animations

    FileSystem* fs = GetSubsystem<FileSystem>();
    String pathName, fileName, ext;
    SplitPath(asset_->GetPath(), pathName, fileName, ext);

    Vector<String> results;

    fs->ScanDir(results, pathName, ext, SCAN_FILES, false);

    for (unsigned i = 0; i < results.Size(); i++)
    {
        const String& result = results[i];

        if (result.Contains("@"))
        {
            Vector<String> components = GetFileName(result).Split('@');

            if (components.Size() == 2 && components[1].Length() && components[0] == fileName)
            {
                String animationName = components[1];
                AssetDatabase* db = GetSubsystem<AssetDatabase>();
                Asset* asset = db->GetAssetByPath(pathName + result);
                assert(asset);
                assert(asset->GetImporter()->GetType() == ModelImporter::GetTypeStatic());

                ModelImporter* importer = (ModelImporter*) asset->GetImporter();

                if (!importer->animationInfo_.Size())
                {
                   if (!ImportAnimation(asset->GetPath(), animationName))
                       return false;
                }
                else
                {
                    // embedded animations
                    for (unsigned i = 0; i < importer->animationInfo_.Size(); i++)
                    {
                        const SharedPtr<AnimationImportInfo>& info = importer->animationInfo_[i];
                        if (!ImportAnimation(asset->GetPath(), info->GetName(), info->GetStartTime(), info->GetEndTime()))
                            return false;
                    }
                }


            }
        }
    }



    return true;
}
Esempio n. 3
0
bool MeshImportFBX::Import( const char* filename, NVSHARE::MeshImportInterface *callback  )
{
	char message[OUTPUT_TEXT_BUFFER_SIZE+1] = "";
	message[OUTPUT_TEXT_BUFFER_SIZE] = '\0';
	
    const char* localName = getFileName( filename );
	KString fileName = KString( filename );
	KString filePath = fileName.Left( localName - filename );

	m_sdkManager = KFbxSdkManager::Create();

	if(m_sdkManager == NULL)
		return false;


    // Create the importer.
    int fileFormat = -1;
    //int registeredCount;
    //int pluginId;
    //m_sdkManager->GetIOPluginRegistry()->RegisterReader( CreateFBXImporterReader, GetFBXImporterReaderInfo,
    //             pluginId, registeredCount, FillFBXImporterReaderIOSettings );

    m_importer = KFbxImporter::Create( m_sdkManager, "" );
	if( !m_sdkManager->GetIOPluginRegistry()->DetectFileFormat( filename, fileFormat ) )
    {
        // Unrecognizable file format. Try to fall back to KFbxImporter::eFBX_BINARY
        fileFormat = m_sdkManager->GetIOPluginRegistry()->FindReaderIDByDescription( "FBX binary (*.fbx)" );;
    }

    m_importer->SetFileFormat( fileFormat );


    // Initialize the importer by providing a filename.
    if( !m_importer->Initialize( filename ) )
		return false;

    // Create the scene.
    m_scene = KFbxScene::Create( m_sdkManager, "" );


    if (m_importer->IsFBX())
    {
        // Set the import states. By default, the import states are always set to 
        // true. The code below shows how to change these states.
        IOSREF.SetBoolProp(IMP_FBX_MATERIAL,        true);
        IOSREF.SetBoolProp(IMP_FBX_TEXTURE,         true);
        IOSREF.SetBoolProp(IMP_FBX_LINK,            true);
        IOSREF.SetBoolProp(IMP_FBX_SHAPE,           true);
        IOSREF.SetBoolProp(IMP_FBX_GOBO,            true);
        IOSREF.SetBoolProp(IMP_FBX_ANIMATION,       true);
        IOSREF.SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true);
    }



	sprintf_s( message, OUTPUT_TEXT_BUFFER_SIZE, "Importing file %s", filename );
	outputMessage( message );
	if( !m_importer->Import(m_scene) )
		return false;

	//// Convert Axis System to what is used in this example, if needed
	//KFbxAxisSystem sceneAxisSystem = m_scene->GetGlobalSettings().GetAxisSystem();
	//KFbxAxisSystem ourAxisSystem(sceneAxisSystem.KFbxAxisSystem::ZAxis, KFbxAxisSystem::ParityOdd, KFbxAxisSystem::LeftHanded);
	//if( sceneAxisSystem != ourAxisSystem )
	//{
	//     ourAxisSystem.ConvertScene(m_scene);
	//}

	//// Convert Unit System to what is used in this example, if needed
	//KFbxSystemUnit sceneSystemUnit = m_scene->GetGlobalSettings().GetSystemUnit();
	//if( sceneSystemUnit.GetScaleFactor() != 1.0 )
	//{
	//	
	//    KFbxSystemUnit ourSystemUnit(1.0);
	//	ourSystemUnit.ConvertScene(m_scene);
	//	
	//}

	m_callback = callback;
	
	ImportSkeleton();

	m_takeName = NULL;
	m_takeInfo = NULL;
	m_takeNameArray.Clear();

    int takeCount = m_importer->GetTakeCount();
	int tSelected = -1;

	for(int t = 0; t < takeCount; t++ )
	{
		m_takeInfo = m_importer->GetTakeInfo(t);
		m_takeNameArray.Add( &m_takeInfo->mName );
		if(m_takeInfo->mSelect)
			tSelected = t;
	}        
	if(tSelected == -1 && takeCount > 0)
		tSelected = 0;

	if(tSelected >= 0)
	{
		m_takeInfo = m_importer->GetTakeInfo(tSelected);
		m_takeName = m_takeNameArray[tSelected];
		m_scene->SetCurrentTake( m_takeName->Buffer() );

		if (!ImportAnimation())
		{
			Release();
			return false;
		}
	}

    m_scene->FillMaterialArray(m_MaterialArray);


    ProcessScene();
				
	//// Load the texture data in memory (for supported formats)
	//LoadSupportedTextures(m_scene, m_textureArray);
				
	sprintf_s( message, OUTPUT_TEXT_BUFFER_SIZE, "done!" );
	outputMessage( message );


	m_scene->Destroy(true, true);
	m_scene = NULL;

	m_importer->Destroy(true, true);
	m_importer = NULL;

	m_sdkManager->Destroy();
	m_sdkManager = NULL;

	return true;
}