I’ve done some more digging.
In the Unreal source code, FbxAnimationExport.cpp appears to be responsible for setting the framerate in the FBX file.
# https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxAnimationExport.cpp
# Line 36
const double FrameRate = AnimSeq->GetDataModel()->GetFrameRate().AsDecimal();
//Configure the scene time line
{
FbxGlobalSettings& SceneGlobalSettings = Scene->GetGlobalSettings();
double CurrentSceneFrameRate = FbxTime::GetFrameRate(SceneGlobalSettings.GetTimeMode());
if (!bSceneGlobalTimeLineSet || FrameRate > CurrentSceneFrameRate)
{
FbxTime::EMode ComputeTimeMode = FbxTime::ConvertFrameRateToTimeMode(FrameRate);
FbxTime::SetGlobalTimeMode(ComputeTimeMode, ComputeTimeMode == FbxTime::eCustom ? FrameRate : 0.0);
SceneGlobalSettings.SetTimeMode(ComputeTimeMode);
if (ComputeTimeMode == FbxTime::eCustom)
{
SceneGlobalSettings.SetCustomFrameRate(FrameRate);
}
bSceneGlobalTimeLineSet = true;
}
}
Line 36 should get the framerate from the sequence and and then the lines following should interpret that framerate and correctly set it inside the FBX GlobalSettings.
The FBX GlobalSettings can be found in the Autodesk FBX documentation, here:
FBX SDK Documentation: C++: FbxGlobalSettings Class Reference (autodesk.com)
In there, you’ll find the two functions that FbxAnimationExport.cpp
calls on, listed under Time Settings
:
# FBX C++ API Reference > Class Hierarchy > FbxEmitter > FbxObject > FbxGlobalSettings
void SetTimeMode ( FbxTime::EMode pTimeMode )
Sets the time mode.
Parameters:
pTimeMode One of the defined modes in class FbxTime.
FBX Time
has supported FPS presets:
# FBX C++ API Reference > Class Hierarchy > FbxTime
eMode:
eDefaultMode
eFrames120
eFrames100
eFrames60
eFrames50
eFrames48
eFrames30
eFrames30Drop
eNTSCDropFrame
eNTSCFullFrame
ePAL
eFrames24
eFrames1000
eFilmFullFrame
eCustom
eFrames96
eFrames72
eFrames59dot94
eModesCount
eFrames24
exists as an enum, so in theory the code inside FbxAnimationExport.cpp
should be working. The difficulty for me is I don’t have the skills to actually debug what the engine itself is doing at runtime while running this code, so I don’t know what values it’s outputting and working with!
# Step 1:
# FbxAnimationExport.cpp, line 43
FbxTime::EMode ComputeTimeMode = FbxTime::ConvertFrameRateToTimeMode(FrameRate);
# Which runs: FBX C++ API Reference > Class Hierarchy > FbxTime
static EMode ConvertFrameRateToTimeMode( double pFrameRate, double pPrecision = 0.00000001)
# "Get time mode associated with frame rate."
# "The corresponding time mode identifier or eDefaultMode if no time mode associated to the given frame rate is found."
# Step 2: FbxAnimationExport.cpp, line 44
FbxTime::SetGlobalTimeMode(ComputeTimeMode, ComputeTimeMode == FbxTime::eCustom ? FrameRate : 0.0);
# Which runs: FBX C++ API Reference > Class Hierarchy > FbxTime
static void SetGlobalTimeMode( EMode pTimeMode, double pFrameRate = 0.0 )
# "Set default time mode."
# Parameters:
# pTimeMode: Time mode identifier.
# pFrameRate: Custom framerate, only have effect in case of pTimeMode = FbxTime::eCustom
#Remarks:
#It is meaningless to set default time mode to eDefaultMode.
# So if Step 1 produces a eDefaultMode EMode enum, then Step 2 does nothing.
# Step 3: FbxAnimationExport.cpp, line 45
SceneGlobalSettings.SetTimeMode(ComputeTimeMode);
if (ComputeTimeMode == FbxTime::eCustom)
{
SceneGlobalSettings.SetCustomFrameRate(FrameRate);
}
bSceneGlobalTimeLineSet = true;
# If the eMode returned from Step 1 is eCustom (because the framerate assessed in step one is not an existing EMode enum) then set a totally custom framerate.
And we should be good.
But just thinking through the logic, looking at line 41:
# FbxAnimationExport.cpp, line 41
if (!bSceneGlobalTimeLineSet || FrameRate > CurrentSceneFrameRate)
If we’ve already set the value, skip…
OR
if FrameRate is greater than CurrentSceneFrameRate, skip…
# FbxAnimationExport.cpp, line 41
const double FrameRate = AnimSeq->GetDataModel()->GetFrameRate().AsDecimal();
# Therefore:
FrameRate = 24.0
So what is the FbxTime default value?
# FbxAnimationExport.cpp, line 41
double CurrentSceneFrameRate = FbxTime::GetFrameRate(SceneGlobalSettings.GetTimeMode());
# Therefore:
FrameRate = [unknown value]
Going back to our conditional:
# FbxAnimationExport.cpp, line 41
if (!bSceneGlobalTimeLineSet || 24 > [unknown])
# There's the possibility setting the framerate won't work because the unknown value is larger than 24.
Based on the code, I figure the assumption is that if the FbxScene hasn’t been setup yet, that line 41 FbxTime::GetFrameRate(SceneGlobalSettings.GetTimeMode());
is likely feeding through an EMode
value of eDefaultMode
, which when assessed by GetFrameRate()
, resolves into 0
.
Instead, I took a different approach. I manually inspected the FBX export using the autodesk fbx converter tool, and found something interesting:
TimeMode
is being exported as 6
, instead of what it shouold be, 11
!
# fbxsdk/core/base/fbxtime.h Source File
enum EMode
{
eDefaultMode, # 0
eFrames120, # 1
eFrames100, # 2
eFrames60, # 3
eFrames50, # 4
eFrames48, # 5
eFrames30, # 6 <- !!!!!!!!
eFrames30Drop, # 7
eNTSCDropFrame, # 8
eNTSCFullFrame, # 9
ePAL, # 10
eFrames24, # 11 <- What it should be
eFrames1000, # 12
eFilmFullFrame, # 13
eCustom, # 14
eFrames96, # 15
eFrames72, # 16
eFrames59dot94, # 17
eModesCount # 18
};
And from there, I know exactly what the solution is. I’ll explain it in the next post for those with the same problem.