/** * 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 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; }
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; }