stride3d / stride

Stride (formerly Xenko), a free and open-source cross-platform C# game engine.
https://stride3d.net
MIT License
6.65k stars 957 forks source link

Impossible to import FBX animation(s) #1567

Closed NicusorN5 closed 1 year ago

NicusorN5 commented 2 years ago

Release Type: Latest official release

Version: 4.1.0.1734

Platform(s): Windows

Describe the bug Loading animations from a FBX 3D animation literally takes hours before being shown a OutOfMemoryException.

To Reproduce Steps to reproduce the behavior:

  1. Use a animated 3D model and export it as a FBX. I've used for example (models are removed, sorry): https://sketchfab.com/3d-models/ak-47-47e1f4abe10e4ea9909708529b67a488 https://sketchfab.com/3d-models/m4-animations-95b877e551254a2e8cc42add94e11f13

    1.1) I've also used https://github.com/JackPilley/BlenderToStrideAnimationSeparator but I still get the out of memory exception. I don't get the multiple FBX stacks warning though.

    2.) Import the model and skeleton into Stride. Works successfully.

    3.) Import the animations. This will not work, atleast with the given examples.

Expected behavior Animations being properly imported.

Screenshots Error report (generated using a propietary model) image

Logs and callstacks Log reported with a example model from above:

Error: An exception occurred while generating the template.
OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at System.Collections.Generic.List`1.set_Capacity(Int32 value)
   at System.Collections.Generic.List`1.AddWithResize(T item)
   at Stride.Importer.FBX.AnimationConverter.ProcessAnimationCurveFloatsHelper<Stride::Core::Mathematics::Vector3>(FbxAnimCurve** curves, Vector3 defaultValue, Int32 numCurves)
   at Stride.Importer.FBX.AnimationConverter.ProcessAnimationCurveVector<Stride::Core::Mathematics::Vector3>(AnimationClip animationClip, String name, Int32 numCurves, FbxAnimCurve** curves, Vector3 defaultValue, Boolean isUserDefinedProperty)
   at Stride.Importer.FBX.AnimationConverter.ProcessAnimationByNode(Dictionary`2 animationClips, FbxAnimLayer* animLayer, FbxNode* pNode, Boolean importCustomAttributeAnimations)
   at Stride.Importer.FBX.AnimationConverter.ProcessAnimationByNode(Dictionary`2 animationClips, FbxAnimLayer* animLayer, FbxNode* pNode, Boolean importCustomAttributeAnimations)
   at Stride.Importer.FBX.AnimationConverter.ProcessAnimation(String inputFilename, String vfsOutputFilename, Boolean importCustomAttributeAnimations)
   at Stride.Importer.FBX.MeshConverter.GetAnimationDuration(String inputFileName)
   at Stride.Assets.Models.FbxAssetImporter.GetAnimationDuration(UFile localPath, Logger logger, AssetImporterParameters importParameters, TimeSpan& startTime, TimeSpan& endTime) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\engine\Stride.Assets.Models\FbxAssetImporter.cs:line 43
   at Stride.Assets.Models.ModelAssetImporter.Import(UFile localPath, AssetImporterParameters importParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\engine\Stride.Assets.Models\ModelAssetImporter.cs:line 81
   at Stride.Assets.Presentation.Templates.AnimationFromFileTemplateGenerator.CreateAssets(AssetTemplateGeneratorParameters parameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\editor\Stride.Assets.Presentation\Templates\AnimationFromFileTemplateGenerator.cs:line 46
   at Stride.Assets.Presentation.Templates.AssetTemplateGenerator.Run(AssetTemplateGeneratorParameters parameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\editor\Stride.Assets.Presentation\Templates\AssetTemplateGenerator.cs:line 32
   at Stride.Core.Assets.Editor.Components.TemplateDescriptions.TemplateGeneratorHelper.<>c__DisplayClass0_0`1.<RunTemplateGeneratorSafe>b__0() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\editor\Stride.Core.Assets.Editor\Components\TemplateDescriptions\TemplateGeneratorHelper.cs:line 56

Info: Nothing to import.
NicusorN5 commented 2 years ago

Update 1: Updated post with a log generated from importing a example provided above.

NicusorN5 commented 1 year ago

As of today, I tried to research this issue, here's what I found today:

I can't even properly debug this because the unmanaged variables are optimized away. The boolean expression

time < endTime || !lastFrame;

in L338 in the function ProcessAnimationCurveFloatsHelper is never true when the importer gets stuck. This is because oneFrame is 0 and that (speculation) endTime is approaching infinity.

I'm still investigating this issue...

NicusorN5 commented 1 year ago

Update from the previous post: FbxTime::GetOneFrameValue returns 0, so as consequence, the loop at L338 in AnimationConverter.h is infinite. The return type of FbxTime::GetOneFrameValue is FbxLongLong and it is a typedef of FbxInt64 (FbxInt64 is signed __int64).

A workaround by checking if oneFrame is 0 makes the importer return a empty animation. This is not acceptable behavior.

NicusorN5 commented 1 year ago

I just wrote a fix for this issue. This is why the issue existed.

The fix is checking if oneFrame is 0, then setting it again to a valid number. The valid number is set to FbxTime::GetOneFrameValue(FbxTime::eFrames1000) (the smallest value)

I will create a PR after this post.