bImportBoneTracks

bImportBoneTracks

#Overview

name: bImportBoneTracks

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 20 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of bImportBoneTracks is to control whether bone transform tracks should be imported during animation import in Unreal Engine 5.

This setting variable is primarily used in the animation import system, specifically for importing skeletal animations. It is utilized by the Interchange plugin and the FBX importer in Unreal Engine.

The value of this variable is typically set through import settings or configuration files. It can be found in UFbxAnimSequenceImportData and UInterchangeGenericAnimationPipeline classes.

bImportBoneTracks interacts with other animation import settings such as bImportCustomAttribute, bDeleteExistingNonCurveCustomAttributes, and bRemoveRedundantKeys.

Developers should be aware that setting this variable to false will discard any bone transform tracks during import. This can be useful for importing animations that only contain curve data without bone transformations.

Best practices when using this variable include:

  1. Keep it enabled (true) for most skeletal animations to ensure proper bone movement.
  2. Consider disabling it (false) when importing animations that only contain curve data or when you want to preserve existing bone tracks in the target animation.
  3. When disabled, ensure that other necessary animation data (like custom attributes or curves) are still being imported to maintain the intended animation behavior.
  4. Be consistent with its usage across related assets to avoid unexpected animation results.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEditorPerProjectUserSettings.ini:689, section: [/Script/UnrealEd.FbxAnimSequenceImportData]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Interchange/Editor/Source/InterchangeEditor/Private/InterchangeFbxAssetImportDataConverter.cpp:271

Scope (from outer to inner):

file
namespace    UE::Interchange::Private
function     void FillInterchangeGenericAssetsPipelineFromFbxAnimSequenceImportData

Source code excerpt:

		GenericAssetPipeline->AnimationPipeline->bDeleteExistingNonCurveCustomAttributes = AnimSequenceImportData->bDeleteExistingNonCurveCustomAttributes;
		GenericAssetPipeline->AnimationPipeline->bDoNotImportCurveWithZero = AnimSequenceImportData->bDoNotImportCurveWithZero;
		GenericAssetPipeline->AnimationPipeline->bImportBoneTracks = AnimSequenceImportData->bImportBoneTracks;
		GenericAssetPipeline->AnimationPipeline->bImportCustomAttribute = AnimSequenceImportData->bImportCustomAttribute;
		GenericAssetPipeline->CommonSkeletalMeshesAndAnimationsProperties->bImportMeshesInBoneHierarchy = AnimSequenceImportData->bImportMeshesInBoneHierarchy;
		GenericAssetPipeline->AnimationPipeline->bRemoveCurveRedundantKeys = AnimSequenceImportData->bRemoveRedundantKeys;
		GenericAssetPipeline->AnimationPipeline->bSetMaterialDriveParameterOnCustomAttribute = AnimSequenceImportData->bSetMaterialDriveParameterOnCustomAttribute;
		GenericAssetPipeline->AnimationPipeline->bSnapToClosestFrameBoundary = AnimSequenceImportData->bSnapToClosestFrameBoundary;
		GenericAssetPipeline->AnimationPipeline->bUse30HzToBakeBoneAnimation = AnimSequenceImportData->bUseDefaultSampleRate;

#Loc: <Workspace>/Engine/Plugins/Interchange/Editor/Source/InterchangeEditor/Private/InterchangeFbxAssetImportDataConverter.cpp:491

Scope (from outer to inner):

file
namespace    UE::Interchange::Private
function     UAssetImportData* ConvertToLegacyFbx

Source code excerpt:

				DestinationAnimSequenceImportData->bDeleteExistingNonCurveCustomAttributes = GenericAssetPipeline->AnimationPipeline->bDeleteExistingNonCurveCustomAttributes;
				DestinationAnimSequenceImportData->bDoNotImportCurveWithZero = GenericAssetPipeline->AnimationPipeline->bDoNotImportCurveWithZero;
				DestinationAnimSequenceImportData->bImportBoneTracks = GenericAssetPipeline->AnimationPipeline->bImportBoneTracks;
				DestinationAnimSequenceImportData->bImportCustomAttribute = GenericAssetPipeline->AnimationPipeline->bImportCustomAttribute;
				DestinationAnimSequenceImportData->bImportMeshesInBoneHierarchy = GenericAssetPipeline->CommonSkeletalMeshesAndAnimationsProperties->bImportMeshesInBoneHierarchy;
				DestinationAnimSequenceImportData->bPreserveLocalTransform = false;
				DestinationAnimSequenceImportData->bRemoveRedundantKeys = GenericAssetPipeline->AnimationPipeline->bRemoveCurveRedundantKeys;
				DestinationAnimSequenceImportData->bSetMaterialDriveParameterOnCustomAttribute = GenericAssetPipeline->AnimationPipeline->bSetMaterialDriveParameterOnCustomAttribute;
				DestinationAnimSequenceImportData->bSnapToClosestFrameBoundary = GenericAssetPipeline->AnimationPipeline->bSnapToClosestFrameBoundary;

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Import/Private/Animation/InterchangeAnimSequenceFactory.cpp:424

Scope (from outer to inner):

file
namespace    UE::Interchange::Private
function     void RetrieveAnimationPayloads

Source code excerpt:

		const bool bShouldTransact = bIsReimporting;

		bool bImportBoneTracks = false;
		AnimSequenceFactoryNode->GetCustomImportBoneTracks(bImportBoneTracks);
		if (bImportBoneTracks)
		{
			//Get the sample rate, default to 30Hz in case the attribute is missing
			double SampleRate = 30.0;
			AnimSequenceFactoryNode->GetCustomImportBoneTracksSampleRate(SampleRate);

			double RangeStart = 0.0;

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Import/Private/Animation/InterchangeAnimSequenceFactory.cpp:1053

Scope (from outer to inner):

file
function     UInterchangeFactoryBase::FImportAssetResult UInterchangeAnimSequenceFactory::ImportAsset_Async

Source code excerpt:

	const bool bIsReImport = (Arguments.ReimportObject != nullptr);

	bool bImportBoneTracks = false;
	AnimSequenceFactoryNode->GetCustomImportBoneTracks(bImportBoneTracks);
	if (bImportBoneTracks)
	{
		USkeleton* Skeleton = AnimSequence->GetSkeleton();
		check(Skeleton);

		TMap<const UInterchangeSceneNode*, TFuture<TOptional<UE::Interchange::FAnimationPayloadData>>> AnimationPayloads;

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Import/Private/Animation/InterchangeAnimSequenceFactory.cpp:1286

Scope (from outer to inner):

file
function     UInterchangeFactoryBase::FImportAssetResult UInterchangeAnimSequenceFactory::EndImportAsset_GameThread

Source code excerpt:

		double SampleRate = 30.0;

		bool bImportBoneTracks = false;
		if (AnimSequenceFactoryNode->GetCustomImportBoneTracks(bImportBoneTracks) && bImportBoneTracks)
		{
			if (AnimSequenceFactoryNode->GetCustomImportBoneTracksSampleRate(SampleRate))
			{
				FrameRate = UE::Interchange::Animation::ConvertSampleRatetoFrameRate(SampleRate);
			}
		}

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Import/Private/Animation/InterchangeAnimSequenceFactory.cpp:1407

Scope (from outer to inner):

file
function     bool UInterchangeAnimSequenceFactory::IsBoneTrackAnimationValid

Source code excerpt:

	double SampleRate = 30.0;

	bool bImportBoneTracks = false;
	if (AnimSequenceFactoryNode->GetCustomImportBoneTracks(bImportBoneTracks) && bImportBoneTracks)
	{
		if (AnimSequenceFactoryNode->GetCustomImportBoneTracksSampleRate(SampleRate))
		{
			FrameRate = UE::Interchange::Animation::ConvertSampleRatetoFrameRate(SampleRate);
		}

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Pipelines/Private/InterchangeGenericAnimationPipeline.cpp:30

Scope (from outer to inner):

file
function     bool UInterchangeGenericAnimationPipeline::CanEditChange

Source code excerpt:

	if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UInterchangeGenericAnimationPipeline, FrameImportRange))
	{
		return ParentVal && bImportAnimations && bImportBoneTracks && AnimationRange == EInterchangeAnimationRange::SetRange;
	}
	return ParentVal;
}
#endif

void UInterchangeGenericAnimationPipeline::AdjustSettingsForContext(EInterchangePipelineContext ImportType, TObjectPtr<UObject> ReimportAsset)

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Pipelines/Private/InterchangeGenericAnimationPipeline.cpp:458

Scope (from outer to inner):

file
function     void UInterchangeGenericAnimationPipeline::CreateAnimSequenceFactoryNode

Source code excerpt:

	bool bTimeRangeIsValid = false;

	if (bImportBoneTracks)
	{
		if (const UInterchangeSourceNode* SourceNode = UInterchangeSourceNode::GetUniqueInstance(BaseNodeContainer))
		{
			int32 Numerator, Denominator;
			if (!bUse30HzToBakeBoneAnimation && CustomBoneAnimationSampleRate == 0 && SourceNode->GetCustomSourceFrameRateNumerator(Numerator))
			{

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Pipelines/Private/InterchangeGenericAnimationPipeline.cpp:584

Scope (from outer to inner):

file
function     void UInterchangeGenericAnimationPipeline::CreateAnimSequenceFactoryNode

Source code excerpt:

	}

	AnimSequenceFactoryNode->SetCustomImportBoneTracks(bImportBoneTracks);
	AnimSequenceFactoryNode->SetCustomImportBoneTracksSampleRate(SampleRate);
	if (bTimeRangeIsValid)
	{
		AnimSequenceFactoryNode->SetCustomImportBoneTracksRangeStart(StartTime);
		AnimSequenceFactoryNode->SetCustomImportBoneTracksRangeStop(StopTime);
	}

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/Pipelines/Public/InterchangeGenericAnimationPipeline.h:56

Scope (from outer to inner):

file
class        class UInterchangeGenericAnimationPipeline : public UInterchangePipelineBase

Source code excerpt:

	/** Import bone transform tracks. If false, this will discard any bone transform tracks.*/
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animations", meta = (EditCondition = "bImportAnimations"))
	bool bImportBoneTracks = true;

	/** Determines which animation range to import: the range defined at export, the range of frames with animation, or a manually defined range. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animations", meta = (EditCondition = "bImportAnimations && bImportBoneTracks", DisplayName = "Animation Length"))
	EInterchangeAnimationRange AnimationRange = EInterchangeAnimationRange::Timeline;

	/** The frame range used when the Animation Length setting is set to Set Range. */

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxAnimSequenceImportData.h:87

Scope (from outer to inner):

file
class        class UFbxAnimSequenceImportData : public UFbxAssetImportData

Source code excerpt:

	/** Import bone transform tracks. If false, this will discard any bone transform tracks. (useful for curves only animations)*/
	UPROPERTY(EditAnywhere, AdvancedDisplay, config, Category = ImportSettings)
	bool bImportBoneTracks;

	/** Set Material Curve Type for all custom attributes that exists */
	UPROPERTY(EditAnywhere, AdvancedDisplay, config, Category = ImportSettings, meta = (EditCondition = "bImportCustomAttribute", DisplayName="Set Material Curve Type"))
	bool bSetMaterialDriveParameterOnCustomAttribute;

	/** Whether to automatically add curve metadata to an animation's skeleton. If this is disabled, curve metadata will be added to skeletal meshes for morph targets, but no metadata entry will be created for general curves. */

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxAnimSequenceImportData.cpp:7

Scope (from outer to inner):

file
function     UFbxAnimSequenceImportData::UFbxAnimSequenceImportData

Source code excerpt:

	, bImportMeshesInBoneHierarchy(true)
	, bImportCustomAttribute(true)
	, bImportBoneTracks(true)
	, bAddCurveMetadataToSkeleton(true)
	, bRemoveRedundantKeys(true)
	, bDoNotImportCurveWithZero(true)
{
	FrameImportRange.Min = 0;
	FrameImportRange.Max = 0;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxAnimSequenceImportData.cpp:88

Scope (from outer to inner):

file
function     void UFbxAnimSequenceImportData::CopyAnimationValues

Source code excerpt:

	bDeleteExistingNonCurveCustomAttributes = Other->bDeleteExistingNonCurveCustomAttributes;
	bDoNotImportCurveWithZero = Other->bDoNotImportCurveWithZero;
	bImportBoneTracks = Other->bImportBoneTracks;
	bImportCustomAttribute = Other->bImportCustomAttribute;
	bImportMeshesInBoneHierarchy = Other->bImportMeshesInBoneHierarchy;
	bPreserveLocalTransform = Other->bPreserveLocalTransform;
	bRemoveRedundantKeys = Other->bRemoveRedundantKeys;
	bSetMaterialDriveParameterOnCustomAttribute = Other->bSetMaterialDriveParameterOnCustomAttribute;
	bAddCurveMetadataToSkeleton = Other->bAddCurveMetadataToSkeleton;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp:513

Scope (from outer to inner):

file
namespace    UnFbx
function     void ApplyImportUIToImportOptions

Source code excerpt:

		InOutImportOptions.bDeleteExistingCustomAttributeCurves = ImportUI->AnimSequenceImportData->bDeleteExistingCustomAttributeCurves;
		InOutImportOptions.bDeleteExistingNonCurveCustomAttributes = ImportUI->AnimSequenceImportData->bDeleteExistingNonCurveCustomAttributes;
		InOutImportOptions.bImportBoneTracks			= ImportUI->AnimSequenceImportData->bImportBoneTracks;
		InOutImportOptions.bSetMaterialDriveParameterOnCustomAttribute = ImportUI->AnimSequenceImportData->bSetMaterialDriveParameterOnCustomAttribute;
		InOutImportOptions.bAddCurveMetadataToSkeleton	= ImportUI->AnimSequenceImportData->bAddCurveMetadataToSkeleton;
		InOutImportOptions.MaterialCurveSuffixes		= ImportUI->AnimSequenceImportData->MaterialCurveSuffixes;
	}
}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxMainImport.cpp:1790

Scope (from outer to inner):

file
lambda-function

Source code excerpt:

							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt AnimationRange"), CaptureImportOptions->AnimationRange.ToString()));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt DoNotImportCurveWithZero"), CaptureImportOptions->bDoNotImportCurveWithZero));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt ImportBoneTracks"), CaptureImportOptions->bImportBoneTracks));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt ImportCustomAttribute"), CaptureImportOptions->bImportCustomAttribute));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt DeleteExistingCustomAttributeCurves"), CaptureImportOptions->bDeleteExistingCustomAttributeCurves));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt DeleteExistingNonCurveCustomAttributes"), CaptureImportOptions->bDeleteExistingNonCurveCustomAttributes));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt PreserveLocalTransform"), CaptureImportOptions->bPreserveLocalTransform));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt RemoveRedundantKeys"), CaptureImportOptions->bRemoveRedundantKeys));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("AnimOpt Resample"), CaptureImportOptions->bResample));

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportFactory.cpp:1873

Scope (from outer to inner):

file
function     UObject* UFbxSceneImportFactory::ImportOneSkeletalMesh

Source code excerpt:

	bool Old_bBakePivotInVertex = GlobalImportSettings->bBakePivotInVertex;
	GlobalImportSettings->bBakePivotInVertex = false;
	GlobalImportSettings->bImportBoneTracks = true;
	//if (GlobalImportSettings->bBakePivotInVertex && RootNodeInfo->AttributeInfo->PivotNodeUid == INVALID_UNIQUE_ID)
	//{
		//GlobalImportSettings->bBakePivotInVertex = false;
	//}

	// check if there is LODGroup for this skeletal mesh

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp:1098

Scope (from outer to inner):

file
function     EReimportResult::Type UReimportFbxSceneFactory::ImportSkeletalMesh

Source code excerpt:

	bool Old_bBakePivotInVertex = GlobalImportSettings->bBakePivotInVertex;
	GlobalImportSettings->bBakePivotInVertex = false;
	GlobalImportSettings->bImportBoneTracks = true;
	//if (GlobalImportSettings->bBakePivotInVertex && MeshInfo->PivotNodeUid == INVALID_UNIQUE_ID)
	//{
		//GlobalImportSettings->bBakePivotInVertex = false;
	//}

	TArray< TArray<FbxNode*>* > SkelMeshArray;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/ReimportFbxSceneFactory.cpp:1296

Scope (from outer to inner):

file
function     EReimportResult::Type UReimportFbxSceneFactory::ReimportSkeletalMesh

Source code excerpt:

	bool Old_bBakePivotInVertex = GlobalImportSettings->bBakePivotInVertex;
	GlobalImportSettings->bBakePivotInVertex = false;
	GlobalImportSettings->bImportBoneTracks = true;
	//if (GlobalImportSettings->bBakePivotInVertex && MeshInfo->PivotNodeUid == INVALID_UNIQUE_ID)
	//{
		//GlobalImportSettings->bBakePivotInVertex = false;
	//}
	TArray<FbxNode*> OutSkeletalMeshArray;
	EReimportResult::Type ReimportResult = EReimportResult::Succeeded;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/SkeletalMeshEdit.cpp:1848

Scope (from outer to inner):

file
function     bool UnFbx::FFbxImporter::ImportAnimation

Source code excerpt:


	// import animation
	if (ImportOptions->bImportBoneTracks)
	{
		FbxNode* SkeletalMeshRootNode = NodeArray.Num() > 0 ? NodeArray[0] : nullptr;
		ImportBoneTracks(Skeleton, AnimImportSettings, SkeletalMeshRootNode, ResampleRate, TransformDebugData, TotalNumKeys, bReimport);

		AnimationTransformDebug::OutputAnimationTransformDebugData(TransformDebugData, TotalNumKeys, RefSkeleton);
	}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Public/FbxImporter.h:200

Scope (from outer to inner):

file
namespace    UnFbx

Source code excerpt:

	bool	bDeleteExistingCustomAttributeCurves;
	bool	bDeleteExistingNonCurveCustomAttributes;
	bool	bImportBoneTracks;
	bool	bSetMaterialDriveParameterOnCustomAttribute;
	bool	bAddCurveMetadataToSkeleton;
	bool	bRemoveRedundantKeys;
	bool	bDoNotImportCurveWithZero;
	bool	bResetToFbxOnMaterialConflict;
	TArray<FString> MaterialCurveSuffixes;