MorphThresholdPosition

MorphThresholdPosition

#Overview

name: MorphThresholdPosition

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 38 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of MorphThresholdPosition is to define a threshold for comparing vertex positions when computing morph target deltas in skeletal meshes. Here’s a detailed breakdown:

  1. Purpose: This variable is used in the skeletal mesh building and morph target processing systems. It determines how close two vertex positions need to be to be considered the same when calculating morph target deltas.

  2. Subsystems: The skeletal mesh system and morph target system in Unreal Engine rely on this setting variable. It’s primarily used in the mesh building process and when importing or processing morph targets.

  3. Value setting: The value is typically set in the FSkeletalMeshBuildSettings struct, which is part of the skeletal mesh import and build process. It can be modified through the Unreal Editor UI when importing or reimporting skeletal meshes.

  4. Interactions: This variable interacts with other threshold variables like ThresholdTangentNormal and ThresholdUV, which are used for similar comparison purposes but for different attributes (normals/tangents and UVs respectively).

  5. Developer awareness: Developers should be aware that this threshold affects the precision of morph target calculations. A lower value will result in more precise morph targets but may also increase data size and processing time.

  6. Best practices:

    • Use the default value (0.015f) unless you have specific reasons to change it.
    • If you need more precise morph targets, especially for facial animations or detailed deformations, consider lowering this value.
    • Be cautious when decreasing this value, as it may significantly increase the size of morph target data and impact performance.
    • Always test the results after changing this value to ensure it doesn’t negatively impact the visual quality or performance of your skeletal meshes and animations.

This setting is crucial for balancing between the precision of morph targets and the performance/data size of skeletal meshes in Unreal Engine.

#Setting Variables

#References In INI files

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

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Plugins/Experimental/Mutable/Source/CustomizableObject/Private/MuCO/CustomizableObjectInstance.cpp:3267

Scope (from outer to inner):

file
function     void UCustomizableInstancePrivate::InitSkeletalMeshData

Source code excerpt:

			LODInfo.BuildSettings.ThresholdTangentNormal = TNumericLimits<float>::Min();
			LODInfo.BuildSettings.ThresholdUV = TNumericLimits<float>::Min();
			LODInfo.BuildSettings.MorphThresholdPosition = TNumericLimits<float>::Min();
			LODInfo.BuildSettings.BoneInfluenceLimit = 0;
#endif
			LODInfo.LODMaterialMap.SetNumZeroed(1);
		}
	}

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

Scope (from outer to inner):

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

Source code excerpt:

		}

		GenericAssetPipeline->MeshPipeline->MorphThresholdPosition = SkeletalMeshImportData->MorphThresholdPosition;
		GenericAssetPipeline->MeshPipeline->ThresholdPosition = SkeletalMeshImportData->ThresholdPosition;
		GenericAssetPipeline->MeshPipeline->ThresholdTangentNormal = SkeletalMeshImportData->ThresholdTangentNormal;
		GenericAssetPipeline->MeshPipeline->ThresholdUV = SkeletalMeshImportData->ThresholdUV;

		if (SkeletalMeshImportData->VertexColorImportOption == EVertexColorImportOption::Ignore)
		{

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

Scope (from outer to inner):

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

Source code excerpt:

				}

				DestinationSkeletalMeshImportData->MorphThresholdPosition = GenericAssetPipeline->MeshPipeline->MorphThresholdPosition;
				DestinationSkeletalMeshImportData->ThresholdPosition = GenericAssetPipeline->MeshPipeline->ThresholdPosition;
				DestinationSkeletalMeshImportData->ThresholdTangentNormal = GenericAssetPipeline->MeshPipeline->ThresholdTangentNormal;
				DestinationSkeletalMeshImportData->ThresholdUV = GenericAssetPipeline->MeshPipeline->ThresholdUV;

				if (GenericAssetPipeline->CommonMeshesProperties->VertexColorImportOption == EInterchangeVertexColorImportOption::IVCIO_Ignore)
				{

#Loc: <Workspace>/Engine/Plugins/Interchange/Runtime/Source/FactoryNodes/Private/InterchangeSkeletalMeshFactoryNode.cpp:204

Scope (from outer to inner):

file
function     bool UInterchangeSkeletalMeshFactoryNode::FillCustomMorphThresholdPositionFromAsset

Source code excerpt:

bool UInterchangeSkeletalMeshFactoryNode::FillCustomMorphThresholdPositionFromAsset(UObject* Asset)
{
	IMPLEMENT_SKELETALMESH_BUILD_ASSET_TO_VALUE(MorphThresholdPosition, MorphThresholdPosition);
}

bool UInterchangeSkeletalMeshFactoryNode::GetCustomBoneInfluenceLimit(int32& AttributeValue) const
{
	IMPLEMENT_NODE_ATTRIBUTE_GETTER(BoneInfluenceLimit, int32)
}

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

Scope (from outer to inner):

file
function     void UInterchangeGenericAssetsPipeline::FilterPropertiesFromTranslatedData

Source code excerpt:

				LocalHideProperty(MeshPipeline, GET_MEMBER_NAME_CHECKED(UInterchangeGenericMeshPipeline, ThresholdTangentNormal));
				LocalHideProperty(MeshPipeline, GET_MEMBER_NAME_CHECKED(UInterchangeGenericMeshPipeline, ThresholdUV));
				LocalHideProperty(MeshPipeline, GET_MEMBER_NAME_CHECKED(UInterchangeGenericMeshPipeline, MorphThresholdPosition));
			}
			else if (MeshPipeline->SkeletalMeshImportContentType == EInterchangeSkeletalMeshContentType::Geometry)
			{
				LocalHideProperty(MeshPipeline, GET_MEMBER_NAME_CHECKED(UInterchangeGenericMeshPipeline, bUpdateSkeletonReferencePose));
			}
		}

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

Scope (from outer to inner):

file
function     UInterchangeSkeletalMeshFactoryNode* UInterchangeGenericMeshPipeline::CreateSkeletalMeshFactoryNode

Source code excerpt:

	SkeletalMeshFactoryNode->SetCustomThresholdTangentNormal(ThresholdTangentNormal);
	SkeletalMeshFactoryNode->SetCustomThresholdUV(ThresholdUV);
	SkeletalMeshFactoryNode->SetCustomMorphThresholdPosition(MorphThresholdPosition);
	SkeletalMeshFactoryNode->SetCustomBoneInfluenceLimit(BoneInfluenceLimit);

	return SkeletalMeshFactoryNode;
}

UInterchangeSkeletalMeshLodDataNode* UInterchangeGenericMeshPipeline::CreateSkeletalMeshLodDataNode(const FString& NodeName, const FString& NodeUniqueID)

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

Scope (from outer to inner):

file
class        class UInterchangeGenericMeshPipeline : public UInterchangePipelineBase

Source code excerpt:

	/** Threshold to compare vertex position equality when computing morph target deltas. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeletal Meshes", meta = (SubCategory = "Build"))
	float MorphThresholdPosition = 0.015f;

	/**
	 * The maximum number of bone influences to allow each vertex in this mesh to use.
	 * If set higher than the limit determined by the project settings, it has no effect.
	 * If set to 0, the value is taken from the DefaultBoneInfluenceLimit project setting.
	 */

#Loc: <Workspace>/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp:424

Scope (from outer to inner):

file
function     BEGIN_FUNCTION_BUILD_OPTIMIZATION bool F

Source code excerpt:

					ImportData->ThresholdPosition = TestPlan->ImportUI->SkeletalMeshImportData->ThresholdPosition;
					ImportData->ThresholdTangentNormal = TestPlan->ImportUI->SkeletalMeshImportData->ThresholdTangentNormal;
					ImportData->MorphThresholdPosition = TestPlan->ImportUI->SkeletalMeshImportData->MorphThresholdPosition;
					ImportData->ThresholdUV = TestPlan->ImportUI->SkeletalMeshImportData->ThresholdUV;
					ImportData->bPreserveSmoothingGroups = TestPlan->ImportUI->SkeletalMeshImportData->bPreserveSmoothingGroups;
					ImportData->bKeepSectionsSeparate = TestPlan->ImportUI->SkeletalMeshImportData->bKeepSectionsSeparate;
					ImportData->bUpdateSkeletonReferencePose = TestPlan->ImportUI->SkeletalMeshImportData->bUpdateSkeletonReferencePose;
					ImportData->bUseT0AsRefPose = TestPlan->ImportUI->SkeletalMeshImportData->bUseT0AsRefPose;
					//Copy UFbxMeshImportData

#Loc: <Workspace>/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/FbxAutomationTests.cpp:523

Scope (from outer to inner):

file
function     BEGIN_FUNCTION_BUILD_OPTIMIZATION bool F

Source code excerpt:

					ImportData->ThresholdTangentNormal = TestPlan->ImportUI->SkeletalMeshImportData->ThresholdTangentNormal;
					ImportData->ThresholdUV = TestPlan->ImportUI->SkeletalMeshImportData->ThresholdUV;
					ImportData->MorphThresholdPosition = TestPlan->ImportUI->SkeletalMeshImportData->MorphThresholdPosition;
					ImportData->bPreserveSmoothingGroups = TestPlan->ImportUI->SkeletalMeshImportData->bPreserveSmoothingGroups;
					ImportData->bKeepSectionsSeparate = TestPlan->ImportUI->SkeletalMeshImportData->bKeepSectionsSeparate;
					ImportData->bUpdateSkeletonReferencePose = TestPlan->ImportUI->SkeletalMeshImportData->bUpdateSkeletonReferencePose;
					ImportData->bUseT0AsRefPose = TestPlan->ImportUI->SkeletalMeshImportData->bUseT0AsRefPose;
					//Copy UFbxMeshImportData
					ImportData->bTransformVertexToAbsolute = TestPlan->ImportUI->SkeletalMeshImportData->bTransformVertexToAbsolute;

#Loc: <Workspace>/Engine/Source/Developer/MeshUtilities/Private/MeshUtilities.cpp:6027

Scope (from outer to inner):

file
function     void FMeshUtilities::CreateImportDataFromLODModel

Source code excerpt:


					const TArray<FMorphTargetDelta>& MorphTargetDeltas = MorphTargetChannel.Value;
					ExistingMorphTarget->PopulateDeltas(MorphTargetDeltas, LodIndex, ToUpdateLODModel.Sections, ThisLODInfo->BuildSettings.bRecomputeNormals, false, ThisLODInfo->BuildSettings.MorphThresholdPosition);
				}
			}
			
			// The model got pulled out of the reduction storage, don't reset the LOD reduction settings,
			// since we may want to regenerate the mesh to those settings.
			bInResetReductionAsNeeded = false;

#Loc: <Workspace>/Engine/Source/Developer/MeshUtilities/Public/MeshUtilities.h:175

Scope (from outer to inner):

file
class        class IMeshUtilities : public IModuleInterface
function     void FillOptions

Source code excerpt:

			OverlappingThresholds.ThresholdTangentNormal = SkeletalMeshBuildSettings.ThresholdTangentNormal;
			OverlappingThresholds.ThresholdUV = SkeletalMeshBuildSettings.ThresholdUV;
			OverlappingThresholds.MorphThresholdPosition = SkeletalMeshBuildSettings.MorphThresholdPosition;
			BoneInfluenceLimit = SkeletalMeshBuildSettings.BoneInfluenceLimit;
			bComputeNormals = SkeletalMeshBuildSettings.bRecomputeNormals;
			bComputeTangents = SkeletalMeshBuildSettings.bRecomputeTangents;
			bUseMikkTSpace = SkeletalMeshBuildSettings.bUseMikkTSpace;
			bComputeWeightedNormals = SkeletalMeshBuildSettings.bComputeWeightedNormals;
			bRemoveDegenerateTriangles = SkeletalMeshBuildSettings.bRemoveDegenerates;

#Loc: <Workspace>/Engine/Source/Developer/SkeletalMeshUtilitiesCommon/Private/LODUtilities.cpp:3567

Scope (from outer to inner):

file
class        class FAsyncImportMorphTargetWork : public FNonAbandonableTask
function     void ComputeMorphDeltas

Source code excerpt:


				// check if position actually changed much
				if (PositionDelta.SizeSquared() > FMath::Square(Thresholds.MorphThresholdPosition) ||
					// since we can't get imported morph target normal from FBX
					// we can't compare normal unless it's calculated
					// this is special flag to ignore normal diff
					((ShouldImportNormals == false) && NormalDeltaZ.SizeSquared() > 0.01f))
				{
					// create a new entry

#Loc: <Workspace>/Engine/Source/Developer/SkeletalMeshUtilitiesCommon/Private/LODUtilities.cpp:3863

Scope (from outer to inner):

file
function     static void BuildMorphTargetsInternal

Source code excerpt:

		constexpr bool bCompareNormals = true;		// Ensure we include morphs that only modify normals and not positions. 
		constexpr bool bGeneratedByReduction = false;
		MorphTarget->PopulateDeltas(*Results[Index], LODIndex, BaseLODModel.Sections, bCompareNormals, bGeneratedByReduction, Thresholds.MorphThresholdPosition);

		// register does mark package as dirty
		if (MorphTarget->HasValidData())
		{
			bNeedToInvalidateRegisteredMorph |= BaseSkelMesh->RegisterMorphTarget(MorphTarget, false);
		}

#Loc: <Workspace>/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp:1947

Scope (from outer to inner):

file
function     float FSkeletalMeshBuildSettingsLayout::GetMorphThresholdPosition

Source code excerpt:

float FSkeletalMeshBuildSettingsLayout::GetMorphThresholdPosition() const
{
	return BuildSettings.MorphThresholdPosition;
}

void FSkeletalMeshBuildSettingsLayout::SetMorphThresholdPosition(float Value)
{
	if (BuildSettings.MorphThresholdPosition != Value)
	{
		FText TransactionText = FText::Format(LOCTEXT("PersonaSetMorphThresholdPositionLOD", "LOD{0} build settings: threshold for morph position changed"), LODIndex);
		FScopedTransaction Transaction(TransactionText);
		ModifyMeshLODSettingsDelegate.ExecuteIfBound(LODIndex);

		BuildSettings.MorphThresholdPosition = Value;
	}
}

int32 FSkeletalMeshBuildSettingsLayout::GetBoneInfluenceLimit() const
{
	return BuildSettings.BoneInfluenceLimit;

#Loc: <Workspace>/Engine/Source/Editor/Persona/Private/PersonaMeshDetails.cpp:4056

Scope (from outer to inner):

file
function     FReply FPersonaMeshDetails::ApplyLODChanges

Source code excerpt:

						SKImportData->ThresholdTangentNormal = LODInfo->BuildSettings.ThresholdTangentNormal;
						SKImportData->ThresholdUV = LODInfo->BuildSettings.ThresholdUV;
						SKImportData->MorphThresholdPosition = LODInfo->BuildSettings.MorphThresholdPosition;
					}
				}
			}

			RestoreNonReducedLOD(LODIndex);
		}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSceneImportOptionsSkeletalMesh.h:64

Scope (from outer to inner):

file
class        class UFbxSceneImportOptionsSkeletalMesh : public UObject

Source code excerpt:

	/** Threshold to compare vertex position equality when computing morph target deltas. */
	UPROPERTY(EditAnywhere, config, Category = "SkeletalMesh|Thresholds", meta = (NoSpinbox = "true", ClampMin = "0.0"))
	float MorphThresholdPosition;

	//////////////////////////////////////////////////////////////////////////
	// Animation section

	/** True to import animations from the FBX File */
	UPROPERTY(EditAnywhere, config, Category = Animation)

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Classes/Factories/FbxSkeletalMeshImportData.h:106

Scope (from outer to inner):

file
class        class UFbxSkeletalMeshImportData : public UFbxMeshImportData

Source code excerpt:

	/** Threshold to compare vertex position equality when computing morph target deltas. */
	UPROPERTY(EditAnywhere, config, Category = "Mesh", meta = (editcondition = "bImportMorphTargets", ImportType = "SkeletalMesh|GeoOnly", SubCategory = "Thresholds", NoSpinbox = "true", ClampMin = "0.0", ClampMax = "1.0"))
	float MorphThresholdPosition;

	/** Gets or creates fbx import data for the specified skeletal mesh */
	static UFbxSkeletalMeshImportData* GetImportDataForSkeletalMesh(USkeletalMesh* SkeletalMesh, UFbxSkeletalMeshImportData* TemplateForCreation);

	bool CanEditChange( const FProperty* InProperty ) const override;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp:6710

Scope (from outer to inner):

file
function     EReimportResult::Type UReimportFbxSkeletalMeshFactory::Reimport

Source code excerpt:

				LODInfo->BuildSettings.ThresholdTangentNormal = SKImportData->ThresholdTangentNormal;
				LODInfo->BuildSettings.ThresholdUV = SKImportData->ThresholdUV;
				LODInfo->BuildSettings.MorphThresholdPosition = SKImportData->MorphThresholdPosition;
			}
		}
	}

	UE_LOG(LogEditorFactories, Log, TEXT("Performing atomic reimport of [%s]"), *Filename);
	CurrentFilename = Filename;

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

Scope (from outer to inner):

file
namespace    UnFbx
function     void ApplyImportUIToImportOptions

Source code excerpt:

		InOutImportOptions.OverlappingThresholds.ThresholdTangentNormal = ImportUI->SkeletalMeshImportData->ThresholdTangentNormal;
		InOutImportOptions.OverlappingThresholds.ThresholdUV = ImportUI->SkeletalMeshImportData->ThresholdUV;
		InOutImportOptions.OverlappingThresholds.MorphThresholdPosition = ImportUI->SkeletalMeshImportData->MorphThresholdPosition;
		InOutImportOptions.bImportMeshesInBoneHierarchy = ImportUI->SkeletalMeshImportData->bImportMeshesInBoneHierarchy;
	}

	//Static mesh unshared options
	{
		InOutImportOptions.bCombineToSingle				= ImportUI->StaticMeshImportData->bCombineMeshes;

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

Scope (from outer to inner):

file
namespace    UnFbx
function     bool FFbxImporter::ImportFromFile

Source code excerpt:

				  * @EventParam ThresholdTangentNormal float Returns the threshold delta to weld tangents and normals
				  * @EventParam ThresholdUV float Returns the threshold delta to weld UVs
				  * @EventParam MorphThresholdPosition float Returns the morph target threshold delta to compute deltas
				  * @EventParam AutoComputeLodDistances boolean Returns whether the importer should set the auto compute LOD distance
				  * @EventParam LodNumber integer Returns the LOD number we should have after the import
				  * @EventParam BuildReversedIndexBuffer boolean Returns whether the importer should fill the reverse index buffer when building the static mesh
				  * @EventParam GenerateLightmapUVs boolean Returns whether the importer should generate light map UVs
				  * @EventParam ImportStaticMeshLODs boolean Returns whether the importer should import the LODs
				  * @EventParam RemoveDegenerates boolean Returns whether the importer should remove the degenerated triangles when building the static mesh
				  * @EventParam MinimumLodNumber integer Returns the minimum LOD use by the rendering
				  * @EventParam StaticMeshLODGroup string Returns the LOD Group settings we use to build this imported static mesh
				  * @EventParam VertexColorImportOption string Returns how the importer should import the vertex color
				  * @EventParam VertexOverrideColor string Returns the color use if we need to override the vertex color
				  * @EventParam AnimationLengthImportType string Returns how we choose the animation time span
				  * @EventParam DeleteExistingMorphTargetCurves boolean Returns whether the importer should delete the existing morph target curves
				  * @EventParam AnimationRange string Returns the range of animation the importer should sample if the time span is custom
				  * @EventParam DoNotImportCurveWithZero boolean Returns whether the importer should import curves containing only zero value
				  * @EventParam ImportBoneTracks boolean Returns whether the importer should import the bone tracks
				  * @EventParam ImportCustomAttribute boolean Returns whether the importer should import the custom attribute curves
				  * @EventParam PreserveLocalTransform boolean Returns whether the importer should preserve the local transform when importing the animation
				  * @EventParam RemoveRedundantKeys boolean Returns whether the importer should remove all redundant key in an animation
				  * @EventParam Resample boolean Returns whether the importer should re-sample the animation
				  * @EventParam SetMaterialDriveParameterOnCustomAttribute boolean Returns whether the importer should hook all custom attribute curve to unreal material attribute
				  * @EventParam SetMaterialDriveParameterOnCustomAttribute boolean Returns whether the importer should hook some custom attribute (having the suffix) curve to unreal material attribute
				  * @EventParam ResampleRate float Returns the rate the exporter is suppose to re-sample any imported animations
				  * 
				  * @Owner Alexis.Matte
				*/
				FbxDocumentInfo* DocInfo = Scene->GetSceneInfo();
				if (DocInfo)
				{
					if( FEngineAnalytics::IsAvailable() )
					{
						const static UEnum* FBXImportTypeEnum = StaticEnum<EFBXImportType>();
						const static UEnum* FBXAnimationLengthImportTypeEnum = StaticEnum<EFBXAnimationLengthImportType>();
						const static UEnum* MaterialSearchLocationEnum = StaticEnum<EMaterialSearchLocation>();
						const static UEnum* FBXNormalGenerationMethodEnum = StaticEnum<EFBXNormalGenerationMethod::Type>();
						const static UEnum* FBXNormalImportMethodEnum = StaticEnum<EFBXNormalImportMethod>();
						const static UEnum* VertexColorImportOptionEnum = StaticEnum<EVertexColorImportOption::Type>();
						
						TArray<FAnalyticsEventAttribute> Attribs;

						FString LastSavedVendor(UTF8_TO_TCHAR(DocInfo->LastSaved_ApplicationVendor.Get().Buffer()));
						FString LastSavedAppName(UTF8_TO_TCHAR(DocInfo->LastSaved_ApplicationName.Get().Buffer()));
						FString LastSavedAppVersion(UTF8_TO_TCHAR(DocInfo->LastSaved_ApplicationVersion.Get().Buffer()));

						Attribs.Add(FAnalyticsEventAttribute(TEXT("LastSaved Application Vendor"), LastSavedVendor));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("LastSaved Application Name"), LastSavedAppName));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("LastSaved Application Version"), LastSavedAppVersion));

						Attribs.Add(FAnalyticsEventAttribute(TEXT("FBX Version"), FbxFileVersion));

						//////////////////////////////////////////////////////////////////////////
						//FBX import options
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportType"), FBXImportTypeEnum->GetNameStringByValue(ImportOptions->ImportType)));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ConvertScene"), ImportOptions->bConvertScene));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ConvertSceneUnit"), ImportOptions->bConvertSceneUnit));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ForceFrontXAxis"), ImportOptions->bForceFrontXAxis));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportMaterials"), ImportOptions->bImportMaterials));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportTextures"), ImportOptions->bImportTextures));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt InvertNormalMap"), ImportOptions->bInvertNormalMap));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt RemoveNameSpace"), ImportOptions->bRemoveNameSpace));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt UsedAsFullName"), ImportOptions->bUsedAsFullName));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportTranslation"), ImportOptions->ImportTranslation.ToString()));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportRotation"), ImportOptions->ImportRotation.ToString()));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ImportUniformScale"), ImportOptions->ImportUniformScale));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt MaterialBasePath"), ImportOptions->MaterialBasePath));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt MaterialSearchLocation"), MaterialSearchLocationEnum->GetNameStringByValue((uint64)(ImportOptions->MaterialSearchLocation))));
						Attribs.Add(FAnalyticsEventAttribute(TEXT("GenOpt ReorderMaterialToFbxOrder"), ImportOptions->bReorderMaterialToFbxOrder));

						//We cant capture a this member, so just assign the pointer here
						FBXImportOptions* CaptureImportOptions = ImportOptions;
						auto AddMeshAnalytic = [&Attribs, &CaptureImportOptions]()
						{
							Attribs.Add(FAnalyticsEventAttribute(TEXT("MeshOpt AutoGenerateCollision"), CaptureImportOptions->bAutoGenerateCollision));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("MeshOpt CombineToSingle"), CaptureImportOptions->bCombineToSingle));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("MeshOpt BakePivotInVertex"), CaptureImportOptions->bBakePivotInVertex));

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

Scope (from outer to inner):

file
lambda-function

Source code excerpt:

							Attribs.Add(FAnalyticsEventAttribute(TEXT("SkeletalMeshOpt OverlappingThresholds.ThresholdTangentNormal"), CaptureImportOptions->OverlappingThresholds.ThresholdTangentNormal));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("SkeletalMeshOpt OverlappingThresholds.ThresholdUV"), CaptureImportOptions->OverlappingThresholds.ThresholdUV));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("SkeletalMeshOpt OverlappingThresholds.MorphThresholdPosition"), CaptureImportOptions->OverlappingThresholds.MorphThresholdPosition));
						};

						auto AddSMAnalytic = [&Attribs, &CaptureImportOptions]()
						{
							Attribs.Add(FAnalyticsEventAttribute(TEXT("StaticMeshOpt AutoComputeLodDistances"), CaptureImportOptions->bAutoComputeLodDistances));
							Attribs.Add(FAnalyticsEventAttribute(TEXT("StaticMeshOpt LodNumber"), CaptureImportOptions->LodNumber));

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp:141

Scope (from outer to inner):

file
function     UnFbx::FBXImportOptions *JSONToFbxOption

Source code excerpt:

		if ((*DataObj)->TryGetNumberField(TEXT("MorphThresholdPosition"), MorphPos))
		{
			Option->OverlappingThresholds.MorphThresholdPosition = (float)MorphPos;
		}
	}

	FString MaterialBasePath;
	if (OptionObj->TryGetStringField(TEXT("MaterialBasePath"), MaterialBasePath))
	{

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportData.cpp:216

Scope (from outer to inner):

file
function     FString FbxOptionToJSON

Source code excerpt:

		Option->OverlappingThresholds.ThresholdTangentNormal,
		Option->OverlappingThresholds.ThresholdUV,
		Option->OverlappingThresholds.MorphThresholdPosition
		);

	JsonString += FString::Printf(TEXT("\"MaterialBasePath\" : \"%s\"}"), *(Option->MaterialBasePath.ToString()));
	return JsonString;
}

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportOptionsSkeletalMesh.cpp:23

Scope (from outer to inner):

file
function     UFbxSceneImportOptionsSkeletalMesh::UFbxSceneImportOptionsSkeletalMesh

Source code excerpt:

	, ThresholdTangentNormal(THRESH_NORMALS_ARE_SAME)
	, ThresholdUV(THRESH_UVS_ARE_SAME)
	, MorphThresholdPosition(THRESH_POINTS_ARE_NEAR)
	, bImportAnimations(true)
	, AnimationLength(EFBXAnimationLengthImportType::FBXALIT_AnimatedKey)
	, FrameImportRange(0, 0)
	, bUseDefaultSampleRate(false)
	, CustomSampleRate(0)
	, bImportCustomAttribute(true)

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSceneImportOptionsSkeletalMesh.cpp:47

Scope (from outer to inner):

file
function     void UFbxSceneImportOptionsSkeletalMesh::FillSkeletalMeshInmportData

Source code excerpt:

	SkeletalMeshImportData->ThresholdTangentNormal = ThresholdTangentNormal;
	SkeletalMeshImportData->ThresholdUV = ThresholdUV;
	SkeletalMeshImportData->MorphThresholdPosition = MorphThresholdPosition;
	SkeletalMeshImportData->bPreserveSmoothingGroups = bPreserveSmoothingGroups;
	SkeletalMeshImportData->bKeepSectionsSeparate = bKeepSectionsSeparate;
	SkeletalMeshImportData->bUpdateSkeletonReferencePose = bUpdateSkeletonReferencePose;
	SkeletalMeshImportData->bUseT0AsRefPose = bUseT0AsRefPose;

	SkeletalMeshImportData->bImportMeshLODs = SceneImportOptions->bImportSkeletalMeshLODs;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp:1827

Scope (from outer to inner):

file
function     USkeletalMesh* UnFbx::FFbxImporter::ImportSkeletalMesh

Source code excerpt:

	BuildOptions.ThresholdTangentNormal = ImportOptions->OverlappingThresholds.ThresholdTangentNormal;
	BuildOptions.ThresholdUV = ImportOptions->OverlappingThresholds.ThresholdUV;
	BuildOptions.MorphThresholdPosition = ImportOptions->OverlappingThresholds.MorphThresholdPosition;
	
	TSharedPtr<FExistingSkelMeshData> ExistSkelMeshDataPtr;
	if (ExistingSkelMesh)
	{
		ExistingSkelMesh->PreEditChange(NULL);
		//We update the build settings before saving the asset data we want to restore after the re-import

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/FbxSkeletalMeshImport.cpp:2456

Scope (from outer to inner):

file
function     USkeletalMesh* UnFbx::FFbxImporter::ReimportSkeletalMesh

Source code excerpt:

				LODInfo->BuildSettings.ThresholdTangentNormal = SKImportData->ThresholdTangentNormal;
				LODInfo->BuildSettings.ThresholdUV = SKImportData->ThresholdUV;
				LODInfo->BuildSettings.MorphThresholdPosition = SKImportData->MorphThresholdPosition;
			}
		}
	}

	// get meshes in Fbx file
	//the function also fill the collision models, so we can update collision models correctly

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/SFbxSceneOptionWindow.cpp:1500

Scope (from outer to inner):

file
function     void SFbxSceneOptionWindow::CopySkeletalMeshOptionsToFbxOptions

Source code excerpt:

	ImportSettings->OverlappingThresholds.ThresholdTangentNormal = SkeletalMeshOptions->ThresholdTangentNormal;
	ImportSettings->OverlappingThresholds.ThresholdUV = SkeletalMeshOptions->ThresholdUV;
	ImportSettings->OverlappingThresholds.MorphThresholdPosition = SkeletalMeshOptions->MorphThresholdPosition;
	ImportSettings->bPreserveSmoothingGroups = SkeletalMeshOptions->bPreserveSmoothingGroups;
	ImportSettings->bKeepSectionsSeparate = SkeletalMeshOptions->bKeepSectionsSeparate;
	ImportSettings->bUpdateSkeletonReferencePose = SkeletalMeshOptions->bUpdateSkeletonReferencePose;
	ImportSettings->bUseT0AsRefPose = SkeletalMeshOptions->bUseT0AsRefPose;

	ImportSettings->bImportAnimations = SkeletalMeshOptions->bImportAnimations;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Fbx/SFbxSceneOptionWindow.cpp:1529

Scope (from outer to inner):

file
function     void SFbxSceneOptionWindow::CopyFbxOptionsToSkeletalMeshOptions

Source code excerpt:

	SkeletalMeshOptions->ThresholdTangentNormal = ImportSettings->OverlappingThresholds.ThresholdTangentNormal;
	SkeletalMeshOptions->ThresholdUV = ImportSettings->OverlappingThresholds.ThresholdUV;
	SkeletalMeshOptions->MorphThresholdPosition = ImportSettings->OverlappingThresholds.MorphThresholdPosition;
	SkeletalMeshOptions->bPreserveSmoothingGroups = ImportSettings->bPreserveSmoothingGroups;
	SkeletalMeshOptions->bKeepSectionsSeparate = ImportSettings->bKeepSectionsSeparate;
	SkeletalMeshOptions->bUpdateSkeletonReferencePose = ImportSettings->bUpdateSkeletonReferencePose;
	SkeletalMeshOptions->bUseT0AsRefPose = ImportSettings->bUseT0AsRefPose;

	SkeletalMeshOptions->bImportAnimations = ImportSettings->bImportAnimations;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/FbxMeshUtils.cpp:658

Scope (from outer to inner):

file
namespace    FbxMeshUtils
function     bool ImportSkeletalMeshLOD

Source code excerpt:

					LODInfo->BuildSettings.ThresholdTangentNormal = ImportOptions->OverlappingThresholds.ThresholdTangentNormal;
					LODInfo->BuildSettings.ThresholdUV = ImportOptions->OverlappingThresholds.ThresholdUV;
					LODInfo->BuildSettings.MorphThresholdPosition = ImportOptions->OverlappingThresholds.MorphThresholdPosition;
				}
			}

			// Populate the mesh array
			FFbxImporter->FillFbxSkelMeshArrayInScene(FFbxImporter->Scene->GetRootNode(), MeshArray, false, ImportOptions->bImportAsSkeletalGeometry || ImportOptions->bImportAsSkeletalSkinning, ImportOptions->bImportScene);

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/SkinWeightsUtilities.cpp:287

Scope (from outer to inner):

file
function     bool FSkinWeightsUtilities::ImportAlternateSkinWeight

Source code excerpt:

				BuildOptions.OverlappingThresholds.ThresholdTangentNormal = LODInfo->BuildSettings.ThresholdTangentNormal;
				BuildOptions.OverlappingThresholds.ThresholdUV = LODInfo->BuildSettings.ThresholdUV;
				BuildOptions.OverlappingThresholds.MorphThresholdPosition = LODInfo->BuildSettings.MorphThresholdPosition;
				BuildOptions.bComputeNormals = LODInfo->BuildSettings.bRecomputeNormals;
				BuildOptions.bComputeTangents = LODInfo->BuildSettings.bRecomputeTangents;
				BuildOptions.bUseMikkTSpace = LODInfo->BuildSettings.bUseMikkTSpace;
				BuildOptions.bComputeWeightedNormals = LODInfo->BuildSettings.bComputeWeightedNormals;
				// There's currently no import option for this. We could add one if needed.
				BuildOptions.BoneInfluenceLimit = 0;

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/SkinWeightsUtilities.cpp:401

Scope (from outer to inner):

file
function     bool FSkinWeightsUtilities::RemoveSkinnedWeightProfileData

Source code excerpt:

		BuildOptions.OverlappingThresholds.ThresholdTangentNormal = LODInfo->BuildSettings.ThresholdTangentNormal;
		BuildOptions.OverlappingThresholds.ThresholdUV = LODInfo->BuildSettings.ThresholdUV;
		BuildOptions.OverlappingThresholds.MorphThresholdPosition = LODInfo->BuildSettings.MorphThresholdPosition;
		BuildOptions.bComputeNormals = LODInfo->BuildSettings.bRecomputeNormals;
		BuildOptions.bComputeTangents = LODInfo->BuildSettings.bRecomputeTangents;
		BuildOptions.bUseMikkTSpace = LODInfo->BuildSettings.bUseMikkTSpace;
		BuildOptions.bComputeWeightedNormals = LODInfo->BuildSettings.bComputeWeightedNormals;
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h:2796

Scope: file

Source code excerpt:

	/** Threshold to compare vertex position equality when computing morph target deltas. */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BuildSettings)
	float MorphThresholdPosition;

	/**
	 * The maximum number of bone influences to allow each vertex in this mesh to use.
	 * 
	 * If set higher than the limit determined by the project settings, it has no effect.
	 * 

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h:2822

Scope (from outer to inner):

file
function     FSkeletalMeshBuildSettings

Source code excerpt:

		, ThresholdTangentNormal(0.00002f)
		, ThresholdUV(0.0009765625f)
		, MorphThresholdPosition(0.015f)
		, BoneInfluenceLimit(0)
	{}

	/** Equality operator. */
	bool operator==(const FSkeletalMeshBuildSettings& Other) const
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h:2841

Scope (from outer to inner):

file
function     bool operator==

Source code excerpt:

			&& ThresholdTangentNormal == Other.ThresholdTangentNormal
			&& ThresholdUV == Other.ThresholdUV
			&& MorphThresholdPosition == Other.MorphThresholdPosition
			&& BoneInfluenceLimit == Other.BoneInfluenceLimit;
	}

	/** Inequality. */
	bool operator!=(const FSkeletalMeshBuildSettings& Other) const
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkinnedAssetCommon.cpp:75

Scope (from outer to inner):

file
function     static void SerializeBuildSettingsForDDC

Source code excerpt:

	Ar << BuildSettings.ThresholdTangentNormal;
	Ar << BuildSettings.ThresholdUV;
	Ar << BuildSettings.MorphThresholdPosition;
	Ar << BuildSettings.BoneInfluenceLimit;
}

FGuid FSkeletalMeshLODInfo::ComputeDeriveDataCacheKey(const FSkeletalMeshLODGroupSettings* SkeletalMeshLODGroupSettings)
{
	// Serialize the LOD info members, the BuildSettings and the ReductionSettings into a temporary array.

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/MeshBuild.h:17

Scope (from outer to inner):

file
function     FOverlappingThresholds

Source code excerpt:

		, ThresholdTangentNormal(UE_THRESH_NORMALS_ARE_SAME)
		, ThresholdUV(UE_THRESH_UVS_ARE_SAME)
		, MorphThresholdPosition(UE_THRESH_POINTS_ARE_NEAR)
	{}

	/** Threshold use to decide if two vertex position are equal. */
	float ThresholdPosition;
	
	/** Threshold use to decide if two normal, tangents or bi-normals are equal. */

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/MeshBuild.h:30

Scope: file

Source code excerpt:


	/** Threshold use to decide if two vertex position are equal. */
	float MorphThresholdPosition;
};


/**
 * Returns true if the specified points are about equal
 */