static void GetCustomVisionData(FbxNode* fbxNode, hkStringPtr& userPropertiesStr) { userPropertiesStr = ""; for(FbxProperty prop = fbxNode->GetFirstProperty(); prop.IsValid(); prop = fbxNode->GetNextProperty(prop)) { EFbxType type = prop.GetPropertyDataType().GetType(); if (type == eFbxString) { FbxString propertyData = prop.Get<FbxString>(); const char* text = propertyData.Buffer(); if (!hkString::strNcasecmp(text, "vision", 6)) { userPropertiesStr = text; break; } } } }
void Tools::DisplayAnimation::DisplayChannels( FbxNode* i_node, FbxAnimLayer* i_animLayer, void (*DisplayCurve) (FbxAnimCurve* i_curve), void (*DisplayListCurve) (FbxAnimCurve* i_curve, FbxProperty* i_property), bool isSwitcher ) { FbxAnimCurve *animCurve = NULL; // Display general curves. if (!isSwitcher) { animCurve = i_node->LclTranslation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_X ); if( animCurve ) { FBXSDK_printf( " TX\n" ); DisplayCommon::DisplayString( " TX" ); DisplayCurve( animCurve ); } animCurve = i_node->LclTranslation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Y ); if( animCurve ) { FBXSDK_printf( " TY\n" ); DisplayCommon::DisplayString( " TY" ); DisplayCurve( animCurve ); } animCurve = i_node->LclTranslation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Z ); if( animCurve ) { FBXSDK_printf( " TZ\n" ); DisplayCommon::DisplayString( " TZ" ); DisplayCurve( animCurve ); } animCurve = i_node->LclRotation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_X ); if( animCurve ) { FBXSDK_printf( " RX\n" ); DisplayCommon::DisplayString( " RX" ); DisplayCurve( animCurve ); } animCurve = i_node->LclRotation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Y ); if( animCurve ) { FBXSDK_printf( " RY\n" ); DisplayCommon::DisplayString( " RY" ); DisplayCurve( animCurve ); } animCurve = i_node->LclRotation.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Z ); if( animCurve ) { FBXSDK_printf( " RZ\n" ); DisplayCommon::DisplayString( " RZ" ); DisplayCurve( animCurve ); } animCurve = i_node->LclScaling.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_X ); if( animCurve ) { FBXSDK_printf( " SX\n" ); DisplayCommon::DisplayString( " SX" ); DisplayCurve( animCurve ); } animCurve = i_node->LclScaling.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Y ); if( animCurve ) { FBXSDK_printf( " SY\n" ); DisplayCommon::DisplayString( " SY" ); DisplayCurve( animCurve ); } animCurve = i_node->LclScaling.GetCurve( i_animLayer, FBXSDK_CURVENODE_COMPONENT_Z ); if( animCurve ) { FBXSDK_printf( " SZ\n" ); DisplayCommon::DisplayString( " SZ" ); DisplayCurve( animCurve ); } } // Display curves specific to a light or marker. FbxNodeAttribute *nodeAttribute = i_node->GetNodeAttribute(); if( nodeAttribute ) { animCurve = nodeAttribute->Color.GetCurve( i_animLayer, FBXSDK_CURVENODE_COLOR_RED ); if( animCurve ) { FBXSDK_printf( " Red\n" ); DisplayCommon::DisplayString( " Red" ); DisplayCurve( animCurve ); } animCurve = nodeAttribute->Color.GetCurve( i_animLayer, FBXSDK_CURVENODE_COLOR_GREEN ); if( animCurve ) { FBXSDK_printf( " Green\n" ); DisplayCommon::DisplayString( " Green" ); DisplayCurve( animCurve ); } animCurve = nodeAttribute->Color.GetCurve( i_animLayer, FBXSDK_CURVENODE_COLOR_BLUE ); if( animCurve ) { FBXSDK_printf( " Blue\n" ); DisplayCommon::DisplayString( " Blue" ); DisplayCurve( animCurve ); } // Display curves specific to a light. FbxLight *light = i_node->GetLight(); if( light ) { animCurve = light->Intensity.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Intensity\n" ); DisplayCommon::DisplayString( " Intensity" ); DisplayCurve( animCurve ); } animCurve = light->OuterAngle.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Outer Angle\n" ); DisplayCommon::DisplayString( " Outer Angle" ); DisplayCurve( animCurve ); } animCurve = light->Fog.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Fog\n" ); DisplayCommon::DisplayString( " Fog" ); DisplayCurve( animCurve ); } } // Display curves specific to a camera. FbxCamera *camera = i_node->GetCamera(); if( camera ) { animCurve = camera->FieldOfView.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Field of View\n" ); DisplayCommon::DisplayString( " Field of View" ); DisplayCurve( animCurve ); } animCurve = camera->FieldOfViewX.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Field of View X\n" ); DisplayCommon::DisplayString( " Field of View X" ); DisplayCurve( animCurve ); } animCurve = camera->FieldOfViewY.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Field of View Y\n" ); DisplayCommon::DisplayString( " Field of View Y" ); DisplayCurve( animCurve ); } animCurve = camera->OpticalCenterX.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Optical Center X\n" ); DisplayCommon::DisplayString( " Optical Center X" ); DisplayCurve( animCurve ); } animCurve = camera->OpticalCenterY.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Optical Center Y\n" ); DisplayCommon::DisplayString( " Optical Center Y" ); DisplayCurve( animCurve ); } animCurve = camera->Roll.GetCurve( i_animLayer ); if( animCurve ) { FBXSDK_printf( " Roll\n" ); DisplayCommon::DisplayString( " Roll" ); DisplayCurve( animCurve ); } } // Display curves specific to a geometry. if (nodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh || nodeAttribute->GetAttributeType() == FbxNodeAttribute::eNurbs || nodeAttribute->GetAttributeType() == FbxNodeAttribute::ePatch) { FbxGeometry *geometry = (FbxGeometry*) nodeAttribute; int blendShapeDeformerCount = geometry->GetDeformerCount( FbxDeformer::eBlendShape ); for( int blendShapeIndex = 0; blendShapeIndex<blendShapeDeformerCount; blendShapeIndex++ ) { FbxBlendShape *blendShape = (FbxBlendShape*)geometry->GetDeformer( blendShapeIndex, FbxDeformer::eBlendShape ); int blendShapeChannelCount = blendShape->GetBlendShapeChannelCount(); for( int channelIndex = 0; channelIndex<blendShapeChannelCount; channelIndex++ ) { FbxBlendShapeChannel *channel = blendShape->GetBlendShapeChannel( channelIndex ); const char *channelName = channel->GetName(); animCurve = geometry->GetShapeChannel( blendShapeIndex, channelIndex, i_animLayer, true ); if( animCurve ) { FBXSDK_printf( " Shape %s\n", channelName ); DisplayCommon::DisplayString( " Shape ", channelName ); DisplayCurve( animCurve ); } } } } } // Display curves specific to properties FbxProperty lProperty = i_node->GetFirstProperty(); while( lProperty.IsValid() ) { if( lProperty.GetFlag(FbxPropertyAttr::eUserDefined) ) { FbxString lFbxFCurveNodeName = lProperty.GetName(); FbxAnimCurveNode* curveNode = lProperty.GetCurveNode( i_animLayer ); if( !curveNode ) { lProperty = i_node->GetNextProperty( lProperty ); continue; } FbxDataType dataType = lProperty.GetPropertyDataType(); if( dataType.GetType() == eFbxBool || dataType.GetType() == eFbxDouble || dataType.GetType() == eFbxFloat || dataType.GetType() == eFbxInt ) { FbxString message; message = " Property "; message += lProperty.GetName(); if( lProperty.GetLabel().GetLen() > 0 ) { message += " (Label: "; message += lProperty.GetLabel(); message += ")"; }; DisplayCommon::DisplayString( message ); for( int c = 0; c < curveNode->GetCurveCount(0U); c++ ) { animCurve = curveNode->GetCurve( 0U, c ); if( animCurve ) DisplayCurve( animCurve ); } } else if( dataType.GetType() == eFbxDouble3 || dataType.GetType() == eFbxDouble4 || dataType.Is(FbxColor3DT) || dataType.Is(FbxColor4DT) ) { char* componentName1 = (dataType.Is(FbxColor3DT) ||dataType.Is(FbxColor4DT)) ? (char*)FBXSDK_CURVENODE_COLOR_RED : (char*)"X"; char* componentName2 = (dataType.Is(FbxColor3DT) ||dataType.Is(FbxColor4DT)) ? (char*)FBXSDK_CURVENODE_COLOR_GREEN : (char*)"Y"; char* componentName3 = (dataType.Is(FbxColor3DT) ||dataType.Is(FbxColor4DT)) ? (char*)FBXSDK_CURVENODE_COLOR_BLUE : (char*)"Z"; FbxString message; message = " Property "; message += lProperty.GetName(); if( lProperty.GetLabel().GetLen() > 0 ) { message += " (Label: "; message += lProperty.GetLabel(); message += ")"; } DisplayCommon::DisplayString( message ); for( int c = 0; c < curveNode->GetCurveCount(0U); c++ ) { animCurve = curveNode->GetCurve( 0U, c ); if( animCurve ) { DisplayCommon::DisplayString( " Component ", componentName1 ); DisplayCurve( animCurve ); } } for( int c = 0; c < curveNode->GetCurveCount(1U); c++ ) { animCurve = curveNode->GetCurve(1U, c); if( animCurve ) { DisplayCommon::DisplayString( " Component ", componentName2 ); DisplayCurve( animCurve ); } } for( int c = 0; c < curveNode->GetCurveCount(2U); c++ ) { animCurve = curveNode->GetCurve( 2U, c ); if( animCurve ) { DisplayCommon::DisplayString( " Component ", componentName3 ); DisplayCurve( animCurve ); } } } else if( dataType.GetType() == eFbxEnum ) { FbxString message; message = " Property "; message += lProperty.GetName(); if( lProperty.GetLabel().GetLen() > 0 ) { message += " (Label: "; message += lProperty.GetLabel(); message += ")"; }; DisplayCommon::DisplayString( message ); for( int c = 0; c < curveNode->GetCurveCount(0U); c++ ) { animCurve = curveNode->GetCurve( 0U, c ); if( animCurve ) DisplayListCurve( animCurve, &lProperty ); } } } lProperty = i_node->GetNextProperty( lProperty ); } // while }
void Tools::DisplayMaterial::DisplayMaterial( FbxGeometry *i_geometry ) { DisplayCommon::DisplayString( "\n\n--------------------\nMaterial\n--------------------" ); int materialCount = 0; FbxNode *node = NULL; if( i_geometry ) { node = i_geometry->GetNode(); if( node ) materialCount = node->GetMaterialCount(); } if( materialCount > 0 ) { FbxPropertyT<FbxDouble3> double3; FbxPropertyT<FbxDouble> double1; FbxColor theColor; for( int ctr = 0; ctr < materialCount; ctr++ ) { DisplayCommon::DisplayInt( " Material ", ctr ); FbxSurfaceMaterial *material = node->GetMaterial( ctr ); DisplayCommon::DisplayString( " Name: \"", (char *) material->GetName(), "\"" ); #ifdef DISPLAY_HARDWARE_SHADER_INFORMATION //Get the implementation to see if it's a hardware shader. // Note:: this cause memory leak const FbxImplementation* implementation = GetImplementation( material, FBXSDK_IMPLEMENTATION_HLSL ); FbxString implementationType = "HLSL"; if( !implementation ) { implementation = GetImplementation( material, FBXSDK_IMPLEMENTATION_CGFX ); implementationType = "CGFX"; } if( implementation ) { //Now we have a hardware shader, let's read it FBXSDK_printf( " Hardware Shader Type: %s\n", implemenationType.Buffer() ); DisplayCommon::DisplayString( " Hardware Shader Type: ", implemenationType ); const FbxBindingTable* rootTable = implementation->GetRootTable(); FbxString fileName = rootTable->DescAbsoluteURL.Get(); FbxString techniqueName = rootTable->DescTAG.Get(); const FbxBindingTable* table = implementation->GetRootTable(); size_t entryNum = table->GetEntryCount(); for( int i = 0; i < (int)entryNum; i++ ) { const FbxBindingTableEntry& entry = table->GetEntry( i ); const char *entrySrcType = entry.GetEntryType( true ); FbxProperty fbxProp; FbxString test = entry.GetSource(); FBXSDK_printf( " Entry: %s\n", test.Buffer() ); DisplayCommon::DisplayString( " Entry: %s\n", test ); if ( strcmp( FbxPropertyEntryView::sEntryType, entrySrcType ) == 0 ) { fbxProp = material->FindPropertyHierarchical(entry.GetSource()); if( !fbxProp.IsValid() ) { fbxProp = material->RootProperty.FindHierarchical( entry.GetSource() ); } } else if( strcmp( FbxConstantEntryView::sEntryType, entrySrcType ) == 0 ) { fbxProp = implementation->GetConstants().FindHierarchical( entry.GetSource() ); } if( fbxProp.IsValid() ) { if( fbxProp.GetSrcObjectCount<FbxTexture>() > 0 ) { //do what you want with the textures for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxFileTexture>(); j++ ) { FbxFileTexture *tex = fbxProp.GetSrcObject<FbxFileTexture>( j ); FBXSDK_printf( " File Texture: %s\n", tex->GetFileName() ); DisplayCommon::DisplayString( " File Texture: %s\n", tex->GetFileName() ); } for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxLayeredTexture>(); j++ ) { FbxLayeredTexture *tex = fbxProp.GetSrcObject<FbxLayeredTexture>( j ); FBXSDK_printf( " Layered Texture: %s\n", tex->GetName() ); DisplayCommon::DisplayString( " Layered Texture: %s\n", tex->GetName() ); } for( int j = 0; j < fbxProp.GetSrcObjectCount<FbxProceduralTexture>(); j++ ) { FbxProceduralTexture *tex = fbxProp.GetSrcObject<FbxProceduralTexture>( j ); FBXSDK_printf( " Procedural Texture: %s\n", tex->GetName() ); DisplayCommon::DisplayString( " Procedural Texture: %s\n", tex->GetName() ); } } else { FbxDataType fbxType = fbxProp.GetPropertyDataType(); FbxString fbxName = fbxType.GetName(); if( FbxBoolDT == fbxType ) { DisplayCommon::DisplayBool( " Bool: ", fbxProp.Get<FbxBool>() ); } else if( FbxIntDT == fbxType || FbxEnumDT == fbxType ) { DisplayCommon::DisplayInt( " Int: ", fbxProp.Get<FbxInt>() ); } else if( FbxFloatDT == fbxType ) { DisplayCommon::DisplayDouble( " Float: ", fbxProp.Get<FbxFloat>() ); } else if( FbxDoubleDT == fbxType ) { DisplayCommon::DisplayDouble( " Double: ", fbxProp.Get<FbxDouble>() ); } else if( FbxStringDT == fbxType || FbxUrlDT == fbxType || FbxXRefUrlDT == fbxType ) { DisplayCommon::DisplayString( " String: ", fbxProp.Get<FbxString>().Buffer() ); } else if( FbxDouble2DT == fbxType ) { FbxDouble2 double2 = fbxProp.Get<FbxDouble2>(); FbxVector2 vector; vector[0] = double2[0]; vector[1] = double2[1]; DisplayCommon::Display2DVector( " 2D vector: ", vector ); } else if( (FbxDouble3DT == fbxType) || (FbxColor3DT == fbxType) ) { FbxDouble3 double3 = fbxProp.Get<FbxDouble3>(); FbxVector4 vector; vector[0] = double3[0]; vector[1] = double3[1]; vector[2] = double3[2]; DisplayCommon::Display3DVector( " 3D vector: ", vector ); } else if( (FbxDouble4DT == fbxType) || (FbxColor4DT == fbxType) ) { FbxDouble4 double4 = fbxProp.Get<FbxDouble4>(); FbxVector4 vector; vector[0] = double4[0]; vector[1] = double4[1]; vector[2] = double4[2]; vector[3] = double4[3]; DisplayCommon::Display4DVector( " 4D vector: ", vector ); } else if( FbxDouble4x4DT == fbxType ) { FbxDouble4x4 double44 = fbxProp.Get<FbxDouble4x4>(); for( int j = 0; j < 4; j++ ) { FbxVector4 vector; vector[0] = double44[j][0]; vector[1] = double44[j][1]; vector[2] = double44[j][2]; vector[3] = double44[j][3]; DisplayCommon::Display4DVector( " 4x4D vector: ", vector ); } } } } } } else #endif // #ifdef DISPLAY_HARDWARE_SHADER_INFORMATION if( material->GetClassId().Is(FbxSurfacePhong::ClassId) ) { // We found a Phong material. Display its properties. // Display the Ambient Color double3 = ((FbxSurfacePhong *) material)->Ambient; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Ambient: ", theColor ); // Display the Diffuse Color double3 = ((FbxSurfacePhong *) material)->Diffuse; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Diffuse: ", theColor ); // Display the Specular Color (unique to Phong materials) double3 = ((FbxSurfacePhong *) material)->Specular; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Specular: ", theColor ); // Display the Emissive Color double3 = ((FbxSurfacePhong *) material)->Emissive; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Emissive: ", theColor ); //Opacity is Transparency factor now double1 = ((FbxSurfacePhong *) material)->TransparencyFactor; DisplayCommon::DisplayDouble( " Opacity: ", 1.0-double1.Get() ); // Display the Shininess double1 = ((FbxSurfacePhong *) material)->Shininess; DisplayCommon::DisplayDouble( " Shininess: ", double1.Get() ); // Display the Reflectivity double1 = ((FbxSurfacePhong *) material)->ReflectionFactor; DisplayCommon::DisplayDouble( " Reflectivity: ", double1.Get() ); } else if( material->GetClassId().Is(FbxSurfaceLambert::ClassId) ) { // We found a Lambert material. Display its properties. // Display the Ambient Color double3 = ((FbxSurfaceLambert *)material)->Ambient; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Ambient: ", theColor ); // Display the Diffuse Color double3 = ((FbxSurfaceLambert *)material)->Diffuse; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Diffuse: ", theColor ); // Display the Emissive double3 = ((FbxSurfaceLambert *)material)->Emissive; theColor.Set( double3.Get()[0], double3.Get()[1], double3.Get()[2] ); DisplayCommon::DisplayColor( " Emissive: ", theColor ); // Display the Opacity double1 = ((FbxSurfaceLambert *)material)->TransparencyFactor; DisplayCommon::DisplayDouble( " Opacity: ", 1.0-double1.Get() ); } else DisplayCommon::DisplayString( "Unknown type of Material" ); FbxPropertyT<FbxString> string; string = material->ShadingModel; DisplayCommon::DisplayString( " Shading Model: ", string.Get() ); } } }
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; }
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 Tools::DisplayGenericInfo::DisplayProperties( FbxObject *i_object ) { DisplayCommon::DisplayString( "Name: ", (char *)i_object->GetName() ); // Display all the properties int i, count = 0; FbxProperty lProperty = i_object->GetFirstProperty(); while( lProperty.IsValid() ) { count++; lProperty = i_object->GetNextProperty( lProperty ); } FbxString lTitleStr = " Property Count: "; if( count == 0 ) return; // there are no properties to display DisplayCommon::DisplayInt( lTitleStr.Buffer(), count ); i = 0; lProperty = i_object->GetFirstProperty(); while( lProperty.IsValid() ) { // exclude user properties FbxString string; DisplayCommon::DisplayInt( " Property ", i ); string = lProperty.GetLabel(); DisplayCommon::DisplayString( " Display Name: ", string ); string = lProperty.GetName(); DisplayCommon::DisplayString( " Internal Name: ", string.Buffer() ); string = lProperty.GetPropertyDataType().GetName(); DisplayCommon::DisplayString( " Type: ",string.Buffer() ); if (lProperty.HasMinLimit()) DisplayCommon::DisplayDouble( " Min Limit: ", lProperty.GetMinLimit() ); if (lProperty.HasMaxLimit()) DisplayCommon::DisplayDouble( " Max Limit: ", lProperty.GetMaxLimit() ); DisplayCommon::DisplayBool( " Is Animatable: ", lProperty.GetFlag(FbxPropertyAttr::eAnimatable) ); switch( lProperty.GetPropertyDataType().GetType() ) { case eFbxBool: DisplayCommon::DisplayBool( " Default Value: ", lProperty.Get<FbxBool>() ); break; case eFbxDouble: DisplayCommon::DisplayDouble( " Default Value: ", lProperty.Get<FbxDouble>() ); break; case eFbxDouble4: { FbxColor lDefault; char buffer[64]; lDefault = lProperty.Get<FbxColor>(); FBXSDK_sprintf( buffer, 64, "R=%f, G=%f, B=%f, A=%f", lDefault.mRed, lDefault.mGreen, lDefault.mBlue, lDefault.mAlpha ); DisplayCommon::DisplayString( " Default Value: ", buffer ); } break; case eFbxInt: DisplayCommon::DisplayInt( " Default Value: ", lProperty.Get<FbxInt>() ); break; case eFbxDouble3: { FbxDouble3 lDefault; char buffer[64]; lDefault = lProperty.Get<FbxDouble3>(); FBXSDK_sprintf( buffer, 64, "X=%f, Y=%f, Z=%f", lDefault[0], lDefault[1], lDefault[2] ); DisplayCommon::DisplayString( " Default Value: ", buffer ); } break; //case FbxEnumDT: // DisplayInt(" Default Value: ", lProperty.Get<FbxEnum>()); // break; case eFbxFloat: DisplayCommon::DisplayDouble( " Default Value: ", lProperty.Get<FbxFloat>() ); break; case eFbxString: string = lProperty.Get<FbxString>(); DisplayCommon::DisplayString( " Default Value: ", string.Buffer() ); break; default: DisplayCommon::DisplayString( " Default Value: UNIDENTIFIED" ); break; } i++; lProperty = i_object->GetNextProperty( lProperty ); } }