NormalTolerance

NormalTolerance

#Overview

name: NormalTolerance

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

#Summary

#Usage in the C++ source code

The purpose of NormalTolerance is to set a threshold for comparing normal vectors in various geometric calculations within Unreal Engine 5. It is primarily used in collision detection, mesh generation, and other 3D geometry-related operations.

Key points about NormalTolerance:

  1. It’s used in multiple Unreal Engine subsystems, including the rendering system, physics engine, and CAD import tools.

  2. The value is typically set as a small floating-point number, often around 1e-6 to 1e-3, depending on the specific use case and required precision.

  3. It’s used in comparisons to determine if two normal vectors are considered equal or nearly parallel.

  4. The variable is often used in conjunction with other tolerance variables like PositionTolerance or DistanceTolerance.

  5. It’s particularly important in collision detection algorithms, where it helps determine if surfaces are facing the same direction or if edges are colinear.

  6. The value may need to be adjusted based on the scale of the objects being compared, as seen in some implementations where it’s multiplied by object dimensions.

Best practices when using NormalTolerance:

  1. Choose an appropriate value based on the scale of your objects and the required precision of your calculations.

  2. Be consistent in its usage throughout related code to ensure uniform behavior.

  3. Consider making it configurable or scale-dependent for more robust implementations.

  4. Use it in conjunction with appropriate vector normalization to ensure consistent results.

  5. Be aware that too small a value may lead to floating-point precision issues, while too large a value may cause incorrect results in geometric calculations.

Developers should be aware that changing NormalTolerance can have significant effects on collision detection, mesh generation, and other geometric operations. It’s important to thoroughly test any changes to this value to ensure it doesn’t introduce unexpected behavior in your game or application.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Plugins/Enterprise/DatasmithImporter/Config/BaseDatasmithImporter.ini:8, section: [FileProducerTessellationOptions]

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/CADKernelSurface/Private/CADKernelSurfaceExtension.cpp:37

Scope (from outer to inner):

file
function     bool UCADKernelParametricSurfaceData::Tessellate

Source code excerpt:

	CADLibrary::FImportParameters ImportParameters;
	ImportParameters.SetModelCoordinateSystem((FDatasmithUtils::EModelCoordSystem) SceneParameters.ModelCoordSys);
	ImportParameters.SetTesselationParameters(RetessellateOptions.ChordTolerance, RetessellateOptions.MaxEdgeLength, RetessellateOptions.NormalTolerance, (CADLibrary::EStitchingTechnique) RetessellateOptions.StitchingTechnique);

	CADLibrary::FMeshParameters CadMeshParameters;
	CadMeshParameters.bNeedSwapOrientation = MeshParameters.bNeedSwapOrientation;
	CadMeshParameters.bIsSymmetric = MeshParameters.bIsSymmetric;
	CadMeshParameters.SymmetricNormal = (FVector3f) MeshParameters.SymmetricNormal;
	CadMeshParameters.SymmetricOrigin = (FVector3f) MeshParameters.SymmetricOrigin;

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/CADKernelSurface/Public/CADModelToCADKernelConverterBase.h:71

Scope (from outer to inner):

file
class        class FCADModelToCADKernelConverterBase : public CADLibrary::ICADModelConverter
function     virtual void SetImportParameters

Source code excerpt:

	}

	virtual void SetImportParameters(double ChordTolerance, double MaxEdgeLength, double NormalTolerance, CADLibrary::EStitchingTechnique StitchingTechnique) override
	{
		ImportParameters.SetTesselationParameters(ChordTolerance, MaxEdgeLength, NormalTolerance, StitchingTechnique);
	}

	virtual bool IsSessionValid() override
	{
		return true;
	}

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithCADTranslator/Private/DatasmithCADTranslator.cpp:177

Scope (from outer to inner):

file
function     bool FDatasmithCADTranslator::LoadScene

Source code excerpt:

	ImportParameters.SetTesselationParameters(CheckParameterValue(TesselationOptions.ChordTolerance, UE::DatasmithTessellation::MinTessellationChord, TEXT("Chord tolerance")),
		FMath::IsNearlyZero(TesselationOptions.MaxEdgeLength) ? 0. : CheckParameterValue(TesselationOptions.MaxEdgeLength, UE::DatasmithTessellation::MinTessellationEdgeLength, TEXT("Max Edge Length")),
		CheckParameterValue(TesselationOptions.NormalTolerance, UE::DatasmithTessellation::MinTessellationAngle, TEXT("Max Angle")),
		(EStitchingTechnique)TesselationOptions.StitchingTechnique);
	ImportParameters.SetModelCoordinateSystem(FDatasmithUtils::EModelCoordSystem::ZUp_RightHanded);

	UE_LOG(LogCADTranslator, Display, TEXT(" - Import parameters:"));
	UE_LOG(LogCADTranslator, Display, TEXT("     - ChordTolerance:     %lf"), ImportParameters.GetChordTolerance());
	UE_LOG(LogCADTranslator, Display, TEXT("     - MaxEdgeLength:      %lf"), ImportParameters.GetMaxEdgeLength());

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithOpenNurbsTranslator/Private/DatasmithOpenNurbsImportOptions.cpp:30

Scope (from outer to inner):

file
function     bool UDatasmithOpenNurbsImportOptions::CanEditChange

Source code excerpt:

	else if (PropertyFName == GET_MEMBER_NAME_CHECKED(FDatasmithOpenNurbsOptions, ChordTolerance)
		|| PropertyFName == GET_MEMBER_NAME_CHECKED(FDatasmithOpenNurbsOptions, MaxEdgeLength)
		|| PropertyFName == GET_MEMBER_NAME_CHECKED(FDatasmithOpenNurbsOptions, NormalTolerance)
		|| PropertyFName == GET_MEMBER_NAME_CHECKED(FDatasmithOpenNurbsOptions, StitchingTechnique)
		)
	{
		// Enable tessellation options only when using CAD library to tessellate
		return Options.Geometry == EDatasmithOpenNurbsBrepTessellatedSource::UseUnrealNurbsTessellation;
	}

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithOpenNurbsTranslator/Private/DatasmithOpenNurbsTranslator.cpp:2979

Scope (from outer to inner):

file
function     bool FOpenNurbsTranslatorImpl::TranslateBRep

Source code excerpt:

	{
		// Ref. visitBRep
		CADModelConverter->SetImportParameters(OpenNurbsOptions.ChordTolerance, OpenNurbsOptions.MaxEdgeLength, OpenNurbsOptions.NormalTolerance, (CADLibrary::EStitchingTechnique)OpenNurbsOptions.StitchingTechnique);

		CADModelConverter->InitializeProcess();

		OpenNurbsBRepConverter->AddBRep(*Brep, Offset);
		CADModelConverter->RepairTopology();

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithPLMXMLTranslator/Private/DatasmithPlmXmlImporter.cpp:251

Scope (from outer to inner):

file
namespace    PlmXml
class        class FPlmXmlMeshLoaderWithDatasmithDispatcher
function     FPlmXmlMeshLoaderWithDatasmithDispatcher

Source code excerpt:


			// Setup of import parameters for DatasmithDispatcher copied from FDatasmithCADTranslator's setup
			ImportParameters.SetTesselationParameters(TessellationOptions.ChordTolerance, TessellationOptions.MaxEdgeLength, TessellationOptions.NormalTolerance, (CADLibrary::EStitchingTechnique) TessellationOptions.StitchingTechnique);

			DatasmithDispatcher = MakeUnique<DatasmithDispatcher::FDatasmithDispatcher>(ImportParameters, CacheDir, CADFileToUEFileMap, CADFileToUEGeomMap);
		}

		// Adds geom file to load and returns Id to use in InstantiateMesh later(after all is loaded)
		int32 AddMeshToLoad(const FString& FullPath)

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithPLMXMLTranslator/Private/DatasmithPlmXmlTranslator.cpp:86

Scope (from outer to inner):

file
function     bool FDatasmithPlmXmlTranslator::LoadScene

Source code excerpt:

	CommonTessellationOptions.ChordTolerance = CheckParameterValue(CommonTessellationOptions.ChordTolerance, UE::DatasmithTessellation::MinTessellationChord, TEXT("Chord tolerance"));
	CommonTessellationOptions.MaxEdgeLength = FMath::IsNearlyZero(CommonTessellationOptions.MaxEdgeLength) ? 0. : CheckParameterValue(CommonTessellationOptions.MaxEdgeLength, UE::DatasmithTessellation::MinTessellationEdgeLength, TEXT("Max Edge Length"));
	CommonTessellationOptions.NormalTolerance = CheckParameterValue(CommonTessellationOptions.NormalTolerance, UE::DatasmithTessellation::MinTessellationAngle, TEXT("Max Angle"));

	UE_LOG(LogDatasmithXMLPLMTranslator, Display, TEXT(" - Import parameters:"));
	UE_LOG(LogDatasmithXMLPLMTranslator, Display, TEXT("     - ChordTolerance:     %f"), CommonTessellationOptions.ChordTolerance);
	UE_LOG(LogDatasmithXMLPLMTranslator, Display, TEXT("     - MaxEdgeLength:      %f"), CommonTessellationOptions.MaxEdgeLength);
	UE_LOG(LogDatasmithXMLPLMTranslator, Display, TEXT("     - MaxNormalAngle:     %f"), CommonTessellationOptions.NormalTolerance);

	FString StitchingTechnique;
	switch ((EStitchingTechnique)CommonTessellationOptions.StitchingTechnique)
	{
	case EStitchingTechnique::StitchingHeal:
		StitchingTechnique = TEXT("Heal");

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithWireTranslator/Private/DatasmithWireTranslator.cpp:480

Scope (from outer to inner):

file
namespace    UE_DATASMITHWIRETRANSLATOR_NAMESPACE
function     void FWireTranslatorImpl::SetTessellationOptions

Source code excerpt:

{
	TessellationOptions = Options;
	CADModelConverter->SetImportParameters(Options.ChordTolerance, Options.MaxEdgeLength, Options.NormalTolerance, (CADLibrary::EStitchingTechnique)Options.StitchingTechnique);
	SceneFileHash = HashCombine(Options.GetHash(), GetSceneFileHash(SceneFullPath, SceneName));
}

bool FWireTranslatorImpl::Read()
{
	// Initialize Alias.

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/DatasmithWireTranslator/Private/DatasmithWireTranslator.cpp:2436

Scope (from outer to inner):

file
namespace    UE_DATASMITHWIRETRANSLATOR_NAMESPACE
function     bool FDatasmithWireTranslator::LoadScene

Source code excerpt:

	UE_LOG(LogDatasmithWireTranslator, Display, TEXT("     - ChordTolerance:     %lf"), TessellationOptions.ChordTolerance);
	UE_LOG(LogDatasmithWireTranslator, Display, TEXT("     - MaxEdgeLength:      %lf"), TessellationOptions.MaxEdgeLength);
	UE_LOG(LogDatasmithWireTranslator, Display, TEXT("     - MaxNormalAngle:     %lf"), TessellationOptions.NormalTolerance);
	FString StitchingTechnique;
	switch (TessellationOptions.StitchingTechnique)
	{
	case EDatasmithCADStitchingTechnique::StitchingHeal:
		StitchingTechnique = TEXT("Heal");
		break;

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurface/Private/TechSoft/TechSoftParametricSurface.cpp:36

Scope (from outer to inner):

file
function     bool UTechSoftParametricSurfaceData::Tessellate

Source code excerpt:

	{
		CADLibrary::FImportParameters ImportParameters((FDatasmithUtils::EModelCoordSystem)SceneParameters.ModelCoordSys);
		ImportParameters.SetTesselationParameters(RetessellateOptions.ChordTolerance, RetessellateOptions.MaxEdgeLength, RetessellateOptions.NormalTolerance, (CADLibrary::EStitchingTechnique)RetessellateOptions.StitchingTechnique);

		FMeshConversionContext Context(ImportParameters, MeshParameters);

		CADLibrary::FTechSoftInterface& TechSoftInterface = CADLibrary::FTechSoftInterface::Get();
		bSuccessfulTessellation = TechSoftInterface.InitializeKernel(*FPaths::EnginePluginsDir());
		if (bSuccessfulTessellation)

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurface/Public/CADModelConverter.h:48

Scope (from outer to inner):

file
namespace    CADLibrary
class        class ICADModelConverter

Source code excerpt:

	 * @param ChordTolerance : SAG
	 * @param MaxEdgeLength : max length of element's edge
	 * @param NormalTolerance : Angle between two adjacent triangles
	 * @param StitchingTechnique : CAD topology correction technique
	 * @param bScaleUVMap : Scale the UV map to a world unit.
	 */
	virtual void SetImportParameters(double ChordTolerance, double MaxEdgeLength, double NormalTolerance, CADLibrary::EStitchingTechnique StitchingTechnique) = 0;

	virtual bool IsSessionValid() = 0;

	virtual void AddSurfaceDataForMesh(const TCHAR* InFilePath, const FMeshParameters& InMeshParameters, const FDatasmithTessellationOptions& InTessellationOptions, FDatasmithMeshElementPayload& OutMeshPayload) const = 0;

};

}

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurface/Public/CADModelToTechSoftConverterBase.h:37

Scope (from outer to inner):

file
class        class FCADModelToTechSoftConverterBase : public CADLibrary::ICADModelConverter
function     virtual void SetImportParameters

Source code excerpt:

	virtual bool Tessellate(const CADLibrary::FMeshParameters& InMeshParameters, FMeshDescription& OutMeshDescription) override;

	virtual void SetImportParameters(double ChordTolerance, double MaxEdgeLength, double NormalTolerance, CADLibrary::EStitchingTechnique StitchingTechnique) override
	{
		ImportParameters.SetTesselationParameters(ChordTolerance, MaxEdgeLength, NormalTolerance, StitchingTechnique);
	}

	virtual bool IsSessionValid() override
	{
		return true;
	}

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurfaceExtension/Private/DataprepTessellationOperation.cpp:28

Scope (from outer to inner):

file
function     void UDataprepTessellationOperation::PostLoad

Source code excerpt:

		ChordTolerance = TessellationSettings_DEPRECATED.ChordTolerance;
		MaxEdgeLength = TessellationSettings_DEPRECATED.MaxEdgeLength;
		NormalTolerance = TessellationSettings_DEPRECATED.NormalTolerance;
		// Mark TessellationSettings_DEPRECATED as non usable
		TessellationSettings_DEPRECATED.ChordTolerance = -MAX_FLT;
	}

	Super::PostLoad();
}

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurfaceExtension/Private/DataprepTessellationOperation.h:26

Scope (from outer to inner):

file
class        class UDataprepTessellationOperation : public UDataprepOperation
function     UDataprepTessellationOperation

Source code excerpt:

		: ChordTolerance(0.2f)
		, MaxEdgeLength(0.0f)
		, NormalTolerance(20.0f)
		// Mark TessellationSettings_DEPRECATED as non usable
		, TessellationSettings_DEPRECATED(-MAX_FLT)
	{
	}

	// UObject interface

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithCADImporter/Source/ParametricSurfaceExtension/Private/DataprepTessellationOperation.h:61

Scope (from outer to inner):

file
class        class UDataprepTessellationOperation : public UDataprepOperation

Source code excerpt:

	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, AdvancedDisplay, Category = "Tessellation Options", meta = (Units = deg, ToolTip = "Maximum angle between adjacent triangles. Smaller values make more triangles.", ClampMin = "0.0", ClampMax = "90.0"))
	float NormalTolerance;

	/** Version 4.24 : Deprecated - not serialized anymore */
	UPROPERTY()
	FDatasmithTessellationOptions TessellationSettings_DEPRECATED;

	//~ Begin UDataprepOperation Interface

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithContent/Source/DatasmithContent/Public/DatasmithImportOptions.h:226

Scope (from outer to inner):

file
function     FDatasmithTessellationOptions

Source code excerpt:

		: ChordTolerance(InChordTolerance)
		, MaxEdgeLength(InMaxEdgeLength)
		, NormalTolerance(InNormalTolerance)
		, StitchingTechnique(InStitchingTechnique)
	{
	}

	/**
	 * Maximum distance between any point on a triangle generated by the tessellation process and the actual surface.

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithContent/Source/DatasmithContent/Public/DatasmithImportOptions.h:254

Scope: file

Source code excerpt:

	 */
	UPROPERTY(config, EditAnywhere, BlueprintReadWrite, AdvancedDisplay, Category = "Geometry & Tessellation Options", meta = (Units = deg, ToolTip = "Maximum angle between adjacent triangles. Smaller values make more triangles.", ClampMin = "5.0", ClampMax = "90.0"))
	float NormalTolerance;


	/**
	 * Stitching technique applied on neighbouring surfaces before tessellation.
	 * None : No stitching applied. This is the default.
	 * Sewing : Connects surfaces which physically share a boundary but not topologically within a set of objects.

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithContent/Source/DatasmithContent/Public/DatasmithImportOptions.h:275

Scope (from outer to inner):

file
function     bool operator ==

Source code excerpt:

		return FMath::IsNearlyEqual(ChordTolerance, Other.ChordTolerance)
			&& FMath::IsNearlyEqual(MaxEdgeLength, Other.MaxEdgeLength)
			&& FMath::IsNearlyEqual(NormalTolerance, Other.NormalTolerance)
			&& StitchingTechnique == Other.StitchingTechnique;
	}

	uint32 GetHash() const
	{
		uint32 Hash = uint32(StitchingTechnique);
		for (float Param : {ChordTolerance, MaxEdgeLength, NormalTolerance})
		{
			Hash = HashCombine(Hash, GetTypeHash(Param));
		}
		return Hash;
	}
};

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithContent/Source/DatasmithContent/Public/DatasmithImportOptions.h:309

Scope (from outer to inner):

file
function     void operator =

Source code excerpt:

		ChordTolerance = Other.ChordTolerance;
		MaxEdgeLength = Other.MaxEdgeLength;
		NormalTolerance = Other.NormalTolerance;
		StitchingTechnique = Other.StitchingTechnique;
	}
};

/**
 * Base class for all import options in datasmith.

#Loc: <Workspace>/Engine/Plugins/Enterprise/DatasmithImporter/Source/DatasmithImporter/Private/DatasmithFileProducer.cpp:1929

Scope (from outer to inner):

file
function     void UDatasmithFileProducer::LoadDefaultSettings

Source code excerpt:

		GConfig->GetFloat( TessellationSectionName, TEXT("ChordTolerance"), DefaultTessellationOptions.ChordTolerance, DatasmithImporterIni);
		GConfig->GetFloat( TessellationSectionName, TEXT("MaxEdgeLength"), DefaultTessellationOptions.MaxEdgeLength, DatasmithImporterIni);
		GConfig->GetFloat( TessellationSectionName, TEXT("NormalTolerance"), DefaultTessellationOptions.NormalTolerance, DatasmithImporterIni);

		FString StitchingTechnique = GConfig->GetStr( TessellationSectionName, TEXT("StitchingTechnique"), DatasmithImporterIni);
		if(StitchingTechnique == TEXT("StitchingHeal"))
		{
			DefaultTessellationOptions.StitchingTechnique =  EDatasmithCADStitchingTechnique::StitchingHeal;
		}

#Loc: <Workspace>/Engine/Plugins/Runtime/MeshModelingToolset/Source/ModelingComponentsEditorOnly/Private/ConversionUtils/DynamicMeshToVolume.cpp:866

Scope (from outer to inner):

file
namespace    UE
namespace    Conversion
function     void GetPolygonFaces

Source code excerpt:

	Normals.SetDegenerateTriangleNormalsToNeighborNormal(); // See comment above

	double NormalTolerance = FMathf::ZeroTolerance;

	auto TrianglesShouldBeInSameComponent = [&InputMesh, &Normals, NormalTolerance, bRespectGroupBoundaries](int32 Triangle0, int32 Triangle1)
	{
		return (!bRespectGroupBoundaries || InputMesh.GetTriangleGroup(Triangle0) == InputMesh.GetTriangleGroup(Triangle1))

			// This test is only performed if triangles share an edge, so checking the normal is 
			// sufficient for coplanarity.
			&& Normals[Triangle0].Dot(Normals[Triangle1]) >= 1 - NormalTolerance;
	};

	FMeshConnectedComponents Components(&InputMesh);
	Components.FindConnectedTriangles(TrianglesShouldBeInSameComponent);

	// Used for removing colinear verts in the loop ahead

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp:2041

Scope (from outer to inner):

file
function     bool UUnrealEdEngine::Exec_Actor

Source code excerpt:


		// The rejection tolerance.  When figuring out which planes to cut the blocking volume cube with
		// the code will reject any planes that are less than "NormalTolerance" different in their normals.
		//
		// This cuts down on the number of planes that will be used for generating the cutting planes and,
		// as a side effect, eliminates duplicates.

		float NormalTolerance = 0.25f;
		FParse::Value( Str, TEXT("NORMALTOLERANCE="), NormalTolerance );

		FVector3f NormalLimits( 1.0f, 1.0f, 1.0f );
		FParse::Value( Str, TEXT("NLIMITX="), NormalLimits.X );
		FParse::Value( Str, TEXT("NLIMITY="), NormalLimits.Y );
		FParse::Value( Str, TEXT("NLIMITZ="), NormalLimits.Z );

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/UnrealEdSrv.cpp:2111

Scope (from outer to inner):

file
function     bool UUnrealEdEngine::Exec_Actor

Source code excerpt:

					FPlane* plane = SplitterPlanes[x];

					if( plane->GetSafeNormal().Equals( SplittingPlane->GetSafeNormal(), NormalTolerance ) )
					{
						bAddPlaneToList = false;
						break;
					}
				}

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:153

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

	{
		const FReal PositionTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal NormalTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal CullDistance = FReal(3);
		const FReal Sin10 = FMath::Sin(FMath::DegreesToRadians(10));
		const FReal Cos10 = FMath::Cos(FMath::DegreesToRadians(10));

		const FTriangle Triangle(FVec3(0, 0, 0), FVec3(100, -100, 0), FVec3(100, 0, 0));
		const FImplicitCapsule3 Capsule(FVec3(50, -10, 10 + 50 * Sin10), FVec3(150, -10, 10 - 50 * Sin10), FReal(20));

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:172

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

			
			// The normal should be vertical because we are within the face angle threshold
			EXPECT_NEAR(ContactPoints[1].ShapeContactNormal.Z, FReal(1), NormalTolerance);

			// Make sure both points are on the capsule surface
			EXPECT_TRUE(IsPointOnCapsuleSurface(Capsule, ContactPoints[0].ShapeContactPoints[0], PositionTolerance));
			EXPECT_TRUE(IsPointOnCapsuleSurface(Capsule, ContactPoints[1].ShapeContactPoints[0], PositionTolerance));
		}
	}

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:191

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

	{
		const FReal PositionTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal NormalTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal CullDistance = FReal(3);

		FTriangle Triangle(FVec3(0, 0, 0), FVec3(100, -100, 0), FVec3(100, 0, 0));
		FImplicitCapsule3 Capsule(FVec3(50, -10, 50), FVec3(150, -10, -50), FReal(10));

		FContactPointManifold ContactPoints;

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:204

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

		{
			EXPECT_NEAR(ContactPoints[0].Phi, -Capsule.GetRadius(), PositionTolerance);
			EXPECT_NEAR(FVec3::DotProduct(ContactPoints[0].ShapeContactNormal, FVec3(0,0,1)), FMath::Cos(FMath::DegreesToRadians(45)), NormalTolerance);
		}
	}

	// Capsule at a 45 degree angle to the triangle, and the capsule axis passes right through an edge.
	// This time we have an end cap within the edge planes, so we should get a face contact at that location.
	// The edge contact will be ignored because it would generate an inward-facing normal, and we are

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:222

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

	{
		const FReal PositionTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal NormalTolerance = UE_KINDA_SMALL_NUMBER;
		const FReal CullDistance = FReal(3);

		FTriangle Triangle(FVec3(0, 0, 0), FVec3(100, -100, 0), FVec3(100, 0, 0));
		FImplicitCapsule3 Capsule(FVec3(50, -10, -50), FVec3(150, -10, 50), FReal(10));

		FContactPointManifold ContactPoints;

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestCapsuleTriangleCollision.cpp:238

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

			EXPECT_NEAR(ContactPoints[0].ShapeContactPoints[0].Z, Capsule.GetX1().Z - Capsule.GetRadius(), PositionTolerance);

			EXPECT_NEAR(ContactPoints[0].ShapeContactNormal.Z, FReal(1), NormalTolerance);
		}
	}
}

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestConvex.cpp:449

Scope (from outer to inner):

file
namespace    ChaosTest
function     void TestConvexPlaneVertices

Source code excerpt:

	void TestConvexPlaneVertices(const ConvexType& Convex)
	{
		const FReal NormalTolerance = UE_SMALL_NUMBER;
		const FReal PositionTolerance = UE_KINDA_SMALL_NUMBER;

		for (int32 PlaneIndex = 0; PlaneIndex < Convex.NumPlanes(); ++PlaneIndex)
		{
			const FVec3 PlaneN = Convex.GetPlane(PlaneIndex).Normal();
			const FVec3 PlaneX = Convex.GetPlane(PlaneIndex).X();

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestConvex.cpp:568

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:

		};

		const FReal NormalTolerance = UE_SMALL_NUMBER;
		const FReal PositionTolerance = UE_KINDA_SMALL_NUMBER;

		const FVec3 Center = FVec3(0, 0, 0);
		const FVec3 HalfExtent = FVec3(100, 200, 300);
		const FReal Margin = FReal(0);

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestConvex.cpp:597

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:


			// Normals are in the expected direction
			EXPECT_NEAR(Plane.Normal().X, PlaneNormals[PlaneIndex].X, NormalTolerance) << "PlaneIndex=" << PlaneIndex;
			EXPECT_NEAR(Plane.Normal().Y, PlaneNormals[PlaneIndex].Y, NormalTolerance) << "PlaneIndex=" << PlaneIndex;
			EXPECT_NEAR(Plane.Normal().Z, PlaneNormals[PlaneIndex].Z, NormalTolerance) << "PlaneIndex=" << PlaneIndex;

			// Positions are in the correct plane
			const FReal PlaneDistance = FVec3::DotProduct(Plane.Normal(), Plane.X());
			const FReal ExpectedPlaneDistance = FVec3::DotProduct(PlaneNormals[PlaneIndex], PlaneNormals[PlaneIndex] * HalfExtent);
			EXPECT_NEAR(PlaneDistance, ExpectedPlaneDistance, PositionTolerance);
		}

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestConvex.cpp:705

Scope (from outer to inner):

file
namespace    ChaosTest
function     GTEST_TEST

Source code excerpt:


		// All planes normals should be...normalized
		const FReal NormalTolerance = 1.e-4;
		for (int32 PlaneIndex = 0; PlaneIndex < Convex.NumPlanes(); ++PlaneIndex)
		{
			const FVec3 PlaneN = Convex.GetPlane(PlaneIndex).Normal();
			EXPECT_NEAR(PlaneN.Size(), FReal(1), NormalTolerance);
		}

	}

	// Create a tet with an extra degenerate triangle in it. Verify that MergeColinearEdges handles this case
	// and does not leave an invalid 2-vertex face behind.

#Loc: <Workspace>/Engine/Source/Programs/HeadlessChaos/Private/HeadlessChaosTestDetectCollision.cpp:19

Scope (from outer to inner):

file
namespace    ChaosTest
function     void CheckContactPoint

Source code excerpt:

	{
		const FReal DistanceTolerance = 1.e-3f;
		const FReal NormalTolerance = 1.e-3f;

		EXPECT_NEAR(ContactPoint.ShapeContactPoints[0].X, ShapeContactPos0.X, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactPoints[0].Y, ShapeContactPos0.Y, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactPoints[0].Z, ShapeContactPos0.Z, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactPoints[1].X, ShapeContactPos1.X, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactPoints[1].Y, ShapeContactPos1.Y, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactPoints[1].Z, ShapeContactPos1.Z, DistanceTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactNormal.X, ShapeContactNormal.X, NormalTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactNormal.Y, ShapeContactNormal.Y, NormalTolerance);
		EXPECT_NEAR(ContactPoint.ShapeContactNormal.Z, ShapeContactNormal.Z, NormalTolerance);
		EXPECT_NEAR(ContactPoint.Phi, Phi, DistanceTolerance);
	}

	//
	//
	// SPHERE - CONVEX TESTS

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Particles/Location/ParticleModuleLocationSkelVertSurface.h:121

Scope (from outer to inner):

file
class        class UParticleModuleLocationSkelVertSurface : public UParticleModuleLocationBase

Source code excerpt:

	TArray<FName> ValidAssociatedBones;

	/** When true use the RestrictToNormal and NormalTolerance values to check surface normals */
	UPROPERTY(EditAnywhere, Category=VertSurface)
	uint32 bEnforceNormalCheck:1;

	/** Use this normal to restrict spawning locations */
	UPROPERTY(EditAnywhere, Category=VertSurface)
	FVector NormalToCompare;

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/CapsuleTriangleContactPoint.cpp:69

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructCapsuleTriangleOneShotManifold2

Source code excerpt:

		// need to cope with very larger or small segments and triangles). This will probably not be good enough...(add some tests)
		const FReal DistanceTolerance = FReal(1.e-5) * Capsule.GetHeight();
		const FReal NormalTolerance = FReal(1.e-5);
		const FReal NormalToleranceSq = NormalTolerance * NormalTolerance;
		const FReal FaceContactSinAngleThreshold = FReal(0.34);	// ~Sin(20deg)

		// Face plane
		const FVec3& FaceP = Triangle.GetVertex(0);	// Use centroid?
		FVec3 FaceN = FVec3::CrossProduct(Triangle.GetVertex(1) - Triangle.GetVertex(0), Triangle.GetVertex(2) - Triangle.GetVertex(0));
		if (!FaceN.Normalize(NormalToleranceSq))

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/CapsuleTriangleContactPoint.cpp:180

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructCapsuleTriangleOneShotManifold2

Source code excerpt:

				// Treat CullDistance as zero when colliding with the underneath of a triangle
				FReal SeparationAxisCullDistance = RejectDistance;
				if (DotFace < -NormalTolerance)
				{
					SeparationAxisCullDistance = R;
				}

				if (SegmentEdgeDistSq > FMath::Square(SeparationAxisCullDistance))
				{

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/CapsuleTriangleContactPoint.cpp:280

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructCapsuleTriangleOneShotManifold2

Source code excerpt:

		{
			FVec3 RadialAxis = FVec3::CrossProduct(FVec3::CrossProduct(Axis, FaceN), Axis);
			if (RadialAxis.Normalize(NormalTolerance))
			{
				// We want Radial axis to point against the normal
				if (FVec3::DotProduct(RadialAxis, FaceN) > FReal(0))
				{
					RadialAxis = -RadialAxis;
				}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/CapsuleTriangleContactPoint.cpp:395

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructCapsuleTriangleOneShotManifold2

Source code excerpt:

					// @todo(chaos): size dependence issue?
					const FReal DotCentroid = FVec3::DotProduct(EdgeP - Centroid, SegmentEdgeN);
					if (DotCentroid < -NormalTolerance)
					{
						continue;
					}
				
					// For Vertex contacts, the normal needs to be outside both planes
					if ((EdgeT == FReal(0)) && ((SegmentT == FReal(0)) || (SegmentT == FReal(1))))

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/CapsuleTriangleContactPoint.cpp:405

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructCapsuleTriangleOneShotManifold2

Source code excerpt:

						const int32 PrevEdgeIndex = (EdgeIndex > 0) ? EdgeIndex - 1 : 2;
						const FReal PrevDotEdge = FVec3::DotProduct(EdgeNs[PrevEdgeIndex], SegmentEdgeN);
						if (PrevDotEdge < -NormalTolerance)
						{
							continue;
						}
					}
					if ((EdgeT == FReal(1)) && ((SegmentT == FReal(0)) || (SegmentT == FReal(1))))
					{
						const int32 NextEdgeIndex = (EdgeIndex < 2) ? EdgeIndex + 1 : 0;
						const FReal NextDotEdge = FVec3::DotProduct(EdgeNs[NextEdgeIndex], SegmentEdgeN);
						if (NextDotEdge < -NormalTolerance)
						{
							continue;
						}
					}
				}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/ConvexTriangleContactPoint.cpp:142

Scope (from outer to inner):

file
namespace    Chaos
function     void ConstructConvexTriangleOneShotManifold2

Source code excerpt:

	void ConstructConvexTriangleOneShotManifold2(const ConvexType& Convex, const FTriangle& Triangle, const FReal CullDistance, FContactPointManifold& OutContactPoints)
	{
		const FReal NormalTolerance = FReal(1.e-8);
		const FReal NormalToleranceSq = NormalTolerance * NormalTolerance;
		const FReal InvalidPhi = std::numeric_limits<FReal>::lowest();

		// Triangle (same space as convex)
		const FVec3 TriN = Triangle.GetNormal();
		const FVec3 TriC = Triangle.GetCentroid();

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/ConvexTriangleContactPoint.cpp:853

Scope (from outer to inner):

file
namespace    Chaos::Private
function     bool GetConvexFeature

Source code excerpt:

	bool GetConvexFeature(const ConvexType& Convex, const FVec3& Position, const FVec3& Normal, Private::FConvexFeature& OutFeature)
	{
		const FReal NormalTolerance = FReal(1.e-6);
		const FReal PositionTolerance = FReal(1.e-4);
		const FReal ToleranceSizeMultiplier = Convex.BoundingBox().Extents().GetAbsMax();
		const FReal EdgeNormalTolerance = ToleranceSizeMultiplier * FReal(1.e-3);

		int32 BestPlaneIndex = INDEX_NONE;
		FReal BestPlaneDotNormal = FReal(-1);

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/ConvexTriangleContactPoint.cpp:876

Scope (from outer to inner):

file
namespace    Chaos::Private
function     bool GetConvexFeature

Source code excerpt:

				Convex.GetPlaneNX(PlaneIndex, PlaneN, PlaneX);
				const FReal PlaneDotNormal = FVec3::DotProduct(PlaneN, Normal);
				if (FMath::IsNearlyEqual(PlaneDotNormal, FReal(1), NormalTolerance))
				{
					OutFeature.FeatureType = Private::EConvexFeatureType::Plane;
					OutFeature.PlaneIndex = PlaneIndex;
					OutFeature.PlaneFeatureIndex = 0;
					return true;
				}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Collision/PBDCollisionConstraint.cpp:595

Scope (from outer to inner):

file
namespace    Chaos
function     bool FPBDCollisionConstraint::AreMatchingContactPoints

Source code excerpt:

			return false;
		}
		const FReal NormalTolerance = Chaos_Manifold_MatchNormalTolerance;

		// If normal has changed a lot, it is a different contact
		// (This was only here to detect bad normals - it is not right for edge-edge contact tracking, but we don't do a good job of that yet anyway!)
		FReal NormalDot = FVec3::DotProduct(A.ShapeContactNormal, B.ShapeContactNormal);
		if (NormalDot < 1.0f - NormalTolerance)
		{
			return false;
		}

		// If either point in local space is the same, it is the same contact
		if (DistanceTolerance > 0.0f)

#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Public/SQVerifier.h:97

Scope (from outer to inner):

file
function     bool SQComparisonHelper

Source code excerpt:

	bool bTestPassed = true;
	const float DistanceTolerance = 1e-1f;
	const float NormalTolerance = 1e-2f;
	FPendingSpatialDataQueue Empty;

	const FSQCapture& CapturedSQ = *Serializer.GetSQCapture();
	switch (CapturedSQ.SQType)
	{
	case FSQCapture::ESQType::Raycast:

#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Public/SQVerifier.h:145

Scope (from outer to inner):

file
function     bool SQComparisonHelper

Source code excerpt:

			bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldPosition.Z, CapturedSQ.PhysXRaycastBuffer.block.position.z, DistanceTolerance));

			bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.X, CapturedSQ.PhysXRaycastBuffer.block.normal.x, NormalTolerance));
			bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.Y, CapturedSQ.PhysXRaycastBuffer.block.normal.y, NormalTolerance));
			bTestPassed &= SQ_REPLAY_TEST(FMath::IsNearlyEqual(ChaosHitBuffer->GetBlock()->WorldNormal.Z, CapturedSQ.PhysXRaycastBuffer.block.normal.z, NormalTolerance));
		}
		break;
	}
	case FSQCapture::ESQType::Sweep:
	{
		//For sweep there are many solutions (many contacts possible) so we only bother testing for Distance

#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Public/SQVerifier.h:216

Scope (from outer to inner):

file
function     bool SQValidityHelper

Source code excerpt:

	bool bTestPassed = true;
	const float DistanceTolerance = 1e-1f;
	const float NormalTolerance = 1e-2f;
	FPendingSpatialDataQueue Empty;

	const FSQCapture& CapturedSQ = *Serializer.GetSQCapture();
	switch (CapturedSQ.SQType)
	{
		case FSQCapture::ESQType::Raycast: