p.Chaos.AccelerationStructureSplitStaticDynamic

p.Chaos.AccelerationStructureSplitStaticDynamic

#Overview

name: p.Chaos.AccelerationStructureSplitStaticDynamic

This variable is created as a Console Variable (cvar).

It is referenced in 15 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of p.Chaos.AccelerationStructureSplitStaticDynamic is to control the sorting of dynamic and static bodies into separate acceleration structures within the Chaos physics system in Unreal Engine 5.

This setting variable is primarily used in the Chaos physics subsystem, which is an experimental physics engine in Unreal Engine 5. It affects how the engine organizes and manages physics objects for efficient collision detection and spatial queries.

The value of this variable is set through the Unreal Engine console variable system. It’s defined as an int32 with a default value of 1, which enables the feature. Any other value disables it.

The associated variable AccelerationStructureSplitStaticAndDynamic interacts directly with p.Chaos.AccelerationStructureSplitStaticDynamic. They share the same value and purpose.

Developers should be aware that:

  1. When set to 1, the engine separates dynamic and static bodies into different acceleration structures, which can potentially improve performance for scenes with many static objects.
  2. This setting affects how spatial indices are assigned to physics objects, which in turn influences how these objects are organized and queried in the physics simulation.
  3. Changing this value may have performance implications, especially in scenes with a mix of static and dynamic objects.

Best practices when using this variable include:

  1. Test performance with both enabled (1) and disabled (0) settings to determine which works best for your specific scene and use case.
  2. Be consistent in its usage across your project to avoid unexpected behavior.
  3. Consider the composition of your scene (ratio of static to dynamic objects) when deciding whether to enable this feature.

The associated variable AccelerationStructureSplitStaticAndDynamic serves the same purpose and is used in the same way as p.Chaos.AccelerationStructureSplitStaticDynamic. It’s the internal representation of the console variable within the Chaos physics code. Developers should treat it with the same considerations as mentioned above.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:37

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:


	CHAOS_API int32 AccelerationStructureSplitStaticAndDynamic = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureSplitStaticAndDynamic(TEXT("p.Chaos.AccelerationStructureSplitStaticDynamic"), AccelerationStructureSplitStaticAndDynamic, TEXT("Set to 1: Sort Dynamic and Static bodies into seperate acceleration structures, any other value will disable the feature"));

	CHAOS_API int32 AccelerationStructureUseDynamicTree = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureUseDynamicTree(TEXT("p.Chaos.AccelerationStructureUseDynamicTree"), AccelerationStructureUseDynamicTree, TEXT("Use a dynamic BVH tree structure for dynamic objects"));

	CHAOS_API int32 AccelerationStructureUseDirtyTreeInsteadOfGrid = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureUseDirtyTreeInsteadOfGrid(TEXT("p.Chaos.AccelerationStructureUseDirtyTreeInsteadOfGrid"), AccelerationStructureUseDirtyTreeInsteadOfGrid, TEXT("Use a dynamic tree structure for dirty elements instead of a 2D grid"));

#Associated Variable and Callsites

This variable is associated with another variable named AccelerationStructureSplitStaticAndDynamic. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/ClusterUnionManager.cpp:330

Scope (from outer to inner):

file
namespace    Chaos
function     FClusterUnionIndex FClusterUnionManager::CreateNewClusterUnion

Source code excerpt:


			NewUnion.InternalCluster->SetInternalCluster(true);
			if (AccelerationStructureSplitStaticAndDynamic == 1)
			{
				NewUnion.InternalCluster->SetSpatialIdx(FSpatialAccelerationIdx{ 0, 1 });
			}
			else
			{
				NewUnion.InternalCluster->SetSpatialIdx(FSpatialAccelerationIdx{ 0, 0 });

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:36

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:

	FAutoConsoleVariableRef CVarAccelerationStructureIsolateQueryOnlyObjects(TEXT("p.Chaos.AccelerationStructureIsolateQueryOnlyObjects"), AccelerationStructureIsolateQueryOnlyObjects, TEXT("Set to 1: QueryOnly Objects will not be moved to acceleration structures on the Physics Thread"));

	CHAOS_API int32 AccelerationStructureSplitStaticAndDynamic = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureSplitStaticAndDynamic(TEXT("p.Chaos.AccelerationStructureSplitStaticDynamic"), AccelerationStructureSplitStaticAndDynamic, TEXT("Set to 1: Sort Dynamic and Static bodies into seperate acceleration structures, any other value will disable the feature"));

	CHAOS_API int32 AccelerationStructureUseDynamicTree = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureUseDynamicTree(TEXT("p.Chaos.AccelerationStructureUseDynamicTree"), AccelerationStructureUseDynamicTree, TEXT("Use a dynamic BVH tree structure for dynamic objects"));

	CHAOS_API int32 AccelerationStructureUseDirtyTreeInsteadOfGrid = 1;
	FAutoConsoleVariableRef CVarAccelerationStructureUseDirtyTreeInsteadOfGrid(TEXT("p.Chaos.AccelerationStructureUseDirtyTreeInsteadOfGrid"), AccelerationStructureUseDirtyTreeInsteadOfGrid, TEXT("Use a dynamic tree structure for dirty elements instead of a 2D grid"));

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:92

Scope (from outer to inner):

file
namespace    Chaos
function     TUniquePtr<ISpatialAccelerationCollection<FAccelerationStructureHandle, FReal, 3>> CreateEmptyCollection

Source code excerpt:


				// Always create this if QueryOnlyObjects are isolated to ensure all consecutive indices are created (within buckets)
				if (AccelerationStructureSplitStaticAndDynamic == 1 || AccelerationStructureIsolateQueryOnlyObjects == 1) 
				{
					// Non static bodies
					Collection->AddSubstructure(CreateAccelerationPerBucket_Threaded(Empty, BucketIdx, true, IsDynamicTree(FSpatialAccelerationIdx{BucketIdx, ESpatialAccelerationCollectionBucketInnerIdx::Dynamic }), true), BucketIdx, ESpatialAccelerationCollectionBucketInnerIdx::Dynamic);
				}
			}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:103

Scope (from outer to inner):

file
namespace    Chaos
function     TUniquePtr<ISpatialAccelerationCollection<FAccelerationStructureHandle, FReal, 3>> CreateEmptyCollection

Source code excerpt:

				constexpr uint16 BucketIdx = 0;
				Collection->AddSubstructure(CreateAccelerationPerBucket_Threaded(Empty, BucketIdx, true, false, false), BucketIdx, ESpatialAccelerationCollectionBucketInnerIdx::DefaultQueryOnly);
				if (AccelerationStructureSplitStaticAndDynamic == 1)
				{
					// Non static bodies
					Collection->AddSubstructure(CreateAccelerationPerBucket_Threaded(Empty, BucketIdx, true, IsDynamicTree(FSpatialAccelerationIdx{ BucketIdx,  ESpatialAccelerationCollectionBucketInnerIdx::DynamicQueryOnly }), false), BucketIdx, ESpatialAccelerationCollectionBucketInnerIdx::DynamicQueryOnly);
				}
			}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:383

Scope (from outer to inner):

file
namespace    Chaos
function     void FPBDRigidsEvolutionBase::FChaosAccelerationStructureTask::UpdateStructure

Source code excerpt:

			}
			
			if (CreatingNewTimeSlicedStructures && !SubStructure->ShouldRebuild() && AccelerationStructureSplitStaticAndDynamic == 1)
			{
				ensure(SubStructure->IsAsyncTimeSlicingComplete());

				if (AccelerationSUBStructureCopy)
				{
					AccelerationSUBStructureCopy->PrepareCopyTimeSliced(*SubStructure);

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:529

Scope (from outer to inner):

file
namespace    Chaos
function     void FPBDRigidsEvolutionBase::FChaosAccelerationStructureTask::DoTask

Source code excerpt:

		//CSV_SCOPED_TIMING_STAT(ChaosPhysicsTimers, AccelerationStructBuildTask);
#endif
		if (AccelerationStructureSplitStaticAndDynamic == 1)
		{
			UpdateStructure(InternalStructure, ExternalStructure);
		}
		else
		{
			//Rebuild both structures. TODO: probably faster to time slice the copy instead of doing two time sliced builds (This happens with AccelerationStructureSplitStaticAndDynamic)
			UpdateStructure(InternalStructure);
			UpdateStructure(ExternalStructure);
		}
	}

	void FPBDRigidsEvolutionBase::ApplyParticlePendingData(const FPendingSpatialData& SpatialData, FAccelerationStructure& AccelerationStructure, bool bUpdateCache, bool bUpdateDynamicTrees)

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:771

Scope (from outer to inner):

file
namespace    Chaos
function     void FPBDRigidsEvolutionBase::ComputeIntermediateSpatialAcceleration

Source code excerpt:

				FlushAsyncAccelerationQueue();
				
				if (AccelerationStructureSplitStaticAndDynamic == 1)
				{
					FlushInternalAccelerationQueue();
				}
				else
				{
					//other queues are no longer needed since we've flushed all operations and now have a pristine structure

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp:800

Scope (from outer to inner):

file
namespace    Chaos
function     void FPBDRigidsEvolutionBase::ComputeIntermediateSpatialAcceleration

Source code excerpt:

					}
				}
				if (AccelerationStructureSplitStaticAndDynamic == 1)
				{
					// If the new InternalAcceleration structure have constituents with no changes, we can copy it to the  AsyncInternalAcceleration for reuse
					// This step can be left out to remove a copy here, at the cost of an unnecessary recalculation in the ChaosAccelerationStructureTask
					// For structures that don't change often both source and destination will be pristine and no copies will be made (most of the time)
					//CopyPristineAccelerationStructures(SpatialAccelerationCache, InternalAcceleration, AsyncInternalAcceleration, true);
				}

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/PBDRigidsSolver.cpp:920

Scope (from outer to inner):

file
namespace    Chaos
function     void FPBDRigidsSolver::RegisterObject

Source code excerpt:

		if (FPBDRigidParticle* Particle = Proxy->GetParticle_External())
		{
			if (AccelerationStructureSplitStaticAndDynamic == 1)
			{
				// It needs to be {0, 1}. Things will crash otherwise. I don't know why.
				// Probably similarly to the geometry collection physics proxy.
				Particle->SetSpatialIdx(FSpatialAccelerationIdx{ 0, 1 });
			}
			else

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/PhysicsProxy/GeometryCollectionPhysicsProxy.cpp:67

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:


namespace Chaos{
	extern int32 AccelerationStructureSplitStaticAndDynamic;
	extern int32 AccelerationStructureIsolateQueryOnlyObjects;
}

float CollisionParticlesPerObjectFractionDefault = 1.0f;
FAutoConsoleVariableRef CVarCollisionParticlesPerObjectFractionDefault(
	TEXT("p.CollisionParticlesPerObjectFractionDefault"), 

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/PhysicsProxy/GeometryCollectionPhysicsProxy.cpp:802

Scope (from outer to inner):

file
function     void FGeometryCollectionPhysicsProxy::CreateGTParticles

Source code excerpt:

			P->SetSpatialIdx(Chaos::FSpatialAccelerationIdx{ 0,1 });

			if (Chaos::AccelerationStructureSplitStaticAndDynamic == 1)
			{
				P->SetSpatialIdx(Chaos::FSpatialAccelerationIdx{ 0,1 });
			}
			else
			{
				P->SetSpatialIdx(Chaos::FSpatialAccelerationIdx{ 0,0 });

#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Public/Chaos/ParticleHandle.h:90

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:



extern CHAOS_API int32 AccelerationStructureSplitStaticAndDynamic;
template <typename T, int d, typename FConcrete>
void KinematicGeometryParticleDefaultConstruct(FConcrete& Concrete, const FKinematicGeometryParticleParameters& Params)
{
	Concrete.SetV(TVector<T, d>(0));
	Concrete.SetW(TVector<T, d>(0));
	if (AccelerationStructureSplitStaticAndDynamic == 1)
	{
		Concrete.SetSpatialIdx(FSpatialAccelerationIdx{ 0,1 });
	}
	else
	{
		Concrete.SetSpatialIdx(FSpatialAccelerationIdx{ 0,0 });

#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Private/ChaosEngineInterface.cpp:33

Scope (from outer to inner):

file
namespace    Chaos

Source code excerpt:

namespace Chaos
{
	extern CHAOS_API int32 AccelerationStructureSplitStaticAndDynamic;
	extern CHAOS_API int32 AccelerationStructureIsolateQueryOnlyObjects;
	extern CHAOS_API int32 SyncKinematicOnGameThread;
}

bool bEnableChaosJointConstraints = true;
FAutoConsoleVariableRef CVarEnableChaosJointConstraints(TEXT("p.ChaosSolverEnableJointConstraints"), bEnableChaosJointConstraints, TEXT("Enable Joint Constraints defined within the Physics Asset Editor"));

#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Private/ChaosEngineInterface.cpp:2083

Scope (from outer to inner):

file
function     void FChaosEngineInterface::CreateActor

Source code excerpt:

	{
		FSpatialAccelerationIdx SpatialIndex{0, ESpatialAccelerationCollectionBucketInnerIdx::Default };
		if (AccelerationStructureSplitStaticAndDynamic == 1)
		{
			if (AccelerationStructureIsolateQueryOnlyObjects == 1)
			{
				if (InParams.bStatic && InParams.bQueryOnly)
				{
					SpatialIndex = FSpatialAccelerationIdx{0, ESpatialAccelerationCollectionBucketInnerIdx::DefaultQueryOnly};