p.ClothPhysics

p.ClothPhysics

#Overview

name: p.ClothPhysics

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

It is referenced in 10 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of p.ClothPhysics is to control whether physics cloth simulation is used in the game. It is a console variable that can be used to enable or disable cloth physics simulation at runtime.

This setting variable is primarily used by the cloth simulation system in Unreal Engine 5. It is utilized by the following subsystems and modules:

  1. The Skeletal Mesh Component system
  2. The Chaos Cloth Asset Engine plugin
  3. The general cloth simulation system

The value of this variable is set through the console command system. It is initialized with a default value of 1, which means cloth physics is enabled by default. The value can be changed at runtime using console commands.

The associated variable CVarEnableClothPhysics interacts directly with p.ClothPhysics. They share the same value and are used interchangeably in the code.

Developers must be aware of the following when using this variable:

  1. Setting it to 0 will disable cloth physics simulation entirely.
  2. It affects performance, as enabling cloth physics requires additional computation.
  3. It is marked with ECVF_Scalability, indicating it’s intended to be used for performance scaling.

Best practices when using this variable include:

  1. Use it for performance optimization, enabling or disabling cloth physics based on the target hardware capabilities.
  2. Consider exposing it as a user-configurable setting for players to adjust based on their system performance.
  3. Be aware that disabling cloth physics may affect the visual quality of clothing in the game.

Regarding the associated variable CVarEnableClothPhysics:

The purpose of CVarEnableClothPhysics is the same as p.ClothPhysics - to control whether cloth physics simulation is enabled.

It is used in various parts of the skeletal mesh component system to check if cloth simulation should be performed. This includes functions like CanSimulateClothing(), TickComponent(), and RecreateClothingActors().

The value of CVarEnableClothPhysics is set automatically based on the value of p.ClothPhysics.

Developers should be aware that this variable is often checked in performance-critical code paths, so changing its value can have significant performance implications.

Best practices for CVarEnableClothPhysics are the same as for p.ClothPhysics, as they are essentially two ways of accessing the same setting.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:48

Scope: file

Source code excerpt:

CSV_DECLARE_CATEGORY_MODULE_EXTERN(CORE_API, Basic);

TAutoConsoleVariable<int32> CVarEnableClothPhysics(TEXT("p.ClothPhysics"), 1, TEXT("If 1, physics cloth will be used for simulation."), ECVF_Scalability);

static TAutoConsoleVariable<int32> CVarEnableClothPhysicsUseTaskThread(TEXT("p.ClothPhysics.UseTaskThread"), 1, TEXT("If 1, run cloth on the task thread. If 0, run on game thread."));
static TAutoConsoleVariable<int32> CVarClothPhysicsTickWaitForParallelClothTask(TEXT("p.ClothPhysics.WaitForParallelClothTask"), 0, TEXT("If 1, always wait for cloth task completion in the Cloth Tick function. If 0, wait at end-of-frame updates instead if allowed by component settings"));

static TAutoConsoleVariable<bool> CVarClothTeleportOverride(TEXT("p.Cloth.TeleportOverride"), false, TEXT("Force console variable teleport override values over skeletal mesh properties.\n Default: false."));
static TAutoConsoleVariable<bool> CVarClothResetAfterTeleport(TEXT("p.Cloth.ResetAfterTeleport"), true, TEXT("Require p.Cloth.TeleportOverride. Reset the clothing after moving the clothing position (called teleport).\n Default: true."));

#Loc: <Workspace>/Engine/Plugins/ChaosClothAsset/Source/ChaosClothAssetEngine/Private/ChaosClothAsset/ClothComponent.cpp:55

Scope (from outer to inner):

file
function     bool UChaosClothComponent::IsSimulationSuspended

Source code excerpt:

bool UChaosClothComponent::IsSimulationSuspended() const
{
	static IConsoleVariable* const CVarClothPhysics = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ClothPhysics"));

	return bSuspendSimulation || !ClothSimulationProxy.IsValid() || (CVarClothPhysics && !CVarClothPhysics->GetBool());
}

bool UChaosClothComponent::IsSimulationEnabled() const
{
	static IConsoleVariable* const CVarClothPhysics = IConsoleManager::Get().FindConsoleVariable(TEXT("p.ClothPhysics"));
	// If the console variable doesn't exist, default to simulation enabled.
	return bEnableSimulation && ClothSimulationProxy.IsValid() && (!CVarClothPhysics || CVarClothPhysics->GetBool());
}

void UChaosClothComponent::ResetConfigProperties()
{

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp:594

Scope: file

Source code excerpt:

}

extern TAutoConsoleVariable<int32> CVarEnableClothPhysics;

bool USkeletalMeshComponent::CanSimulateClothing() const
{
	if(!GetSkeletalMeshAsset() || !bAllowClothActors || !CVarEnableClothPhysics.GetValueOnAnyThread())
	{
		return false;
	}

	return GetSkeletalMeshAsset()->HasActiveClothingAssets() && !IsNetMode(NM_DedicatedServer);
}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Components/SkeletalMeshComponent.cpp:1700

Scope (from outer to inner):

file
function     void USkeletalMeshComponent::TickComponent

Source code excerpt:

	// If we are suspended, we will not simulate clothing, but as clothing is simulated in local space
	// relative to a root bone we need to extract simulation positions as this bone could be animated.
	if((!CVarEnableClothPhysics.GetValueOnGameThread() || bClothingSimulationSuspended) && ClothingSimulation)
	{
		CSV_SCOPED_TIMING_STAT(Animation, Cloth);

		// First update the simulation context, since the simulation isn't ticking
		// and it is still required to get the correct simulation data and bounds.
		constexpr bool bIsInitialization = false;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:48

Scope: file

Source code excerpt:

CSV_DECLARE_CATEGORY_MODULE_EXTERN(CORE_API, Basic);

TAutoConsoleVariable<int32> CVarEnableClothPhysics(TEXT("p.ClothPhysics"), 1, TEXT("If 1, physics cloth will be used for simulation."), ECVF_Scalability);

static TAutoConsoleVariable<int32> CVarEnableClothPhysicsUseTaskThread(TEXT("p.ClothPhysics.UseTaskThread"), 1, TEXT("If 1, run cloth on the task thread. If 0, run on game thread."));
static TAutoConsoleVariable<int32> CVarClothPhysicsTickWaitForParallelClothTask(TEXT("p.ClothPhysics.WaitForParallelClothTask"), 0, TEXT("If 1, always wait for cloth task completion in the Cloth Tick function. If 0, wait at end-of-frame updates instead if allowed by component settings"));

static TAutoConsoleVariable<bool> CVarClothTeleportOverride(TEXT("p.Cloth.TeleportOverride"), false, TEXT("Force console variable teleport override values over skeletal mesh properties.\n Default: false."));
static TAutoConsoleVariable<bool> CVarClothResetAfterTeleport(TEXT("p.Cloth.ResetAfterTeleport"), true, TEXT("Require p.Cloth.TeleportOverride. Reset the clothing after moving the clothing position (called teleport).\n Default: true."));

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:2735

Scope (from outer to inner):

file
function     void USkeletalMeshComponent::RecreateClothingActors

Source code excerpt:

	}

	if(CVarEnableClothPhysics.GetValueOnGameThread() && (SkelMesh->GetMeshClothingAssets().Num() > 0))
	{
		UClass* SimFactoryClass = *ClothingSimulationFactory;
		if (SimFactoryClass)
		{
			UClothingSimulationFactory* SimFactory = SimFactoryClass->GetDefaultObject<UClothingSimulationFactory>();
			if(ClothingSimulation == nullptr)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:3720

Scope (from outer to inner):

file
function     bool USkeletalMeshComponent::RequiresPreEndOfFrameSync

Source code excerpt:

bool USkeletalMeshComponent::RequiresPreEndOfFrameSync() const
{
	if ((ClothingSimulation != nullptr) && (CVarEnableClothPhysics.GetValueOnGameThread() != 0))
	{
		// By default we await the cloth task in the ClothTickFunction, but...
		// If we have cloth and have no game-thread dependencies on the cloth output, 
		// then we will wait for the cloth task in SendAllEndOfFrameUpdates.
		if (!ShouldWaitForClothInTickFunction())
		{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:3782

Scope (from outer to inner):

file
function     void USkeletalMeshComponent::UpdateClothStateAndSimulate

Source code excerpt:


	// If disabled or no simulation
	if (CVarEnableClothPhysics.GetValueOnGameThread() == 0 || !ClothingSimulation || bDisableClothSimulation)
	{
		return;
	}

	// If we simulate a clothing actor at 0s it will fill simulated positions and normals with NaNs.
	// we can skip all the work it is still doing, and get the desired result (frozen sim) by not

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:3856

Scope (from outer to inner):

file
function     void USkeletalMeshComponent::TickClothing

Source code excerpt:

	bIsCompiling = (GetSkeletalMeshAsset() && GetSkeletalMeshAsset()->IsCompiling());
#endif
	if (GetSkeletalMeshAsset() == nullptr || !ClothingSimulation || CVarEnableClothPhysics.GetValueOnGameThread() == 0 || bIsCompiling)
	{
		return;
	}

	// Use the component update flag to gate simulation to respect the always tick options
	bool bShouldTick = ((VisibilityBasedAnimTickOption < EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered) || bRecentlyRendered);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SkeletalMeshComponentPhysics.cpp:3876

Scope (from outer to inner):

file
function     void USkeletalMeshComponent::GetUpdateClothSimulationData

Source code excerpt:

void USkeletalMeshComponent::GetUpdateClothSimulationData(TMap<int32, FClothSimulData>& OutClothSimData, USkeletalMeshComponent* OverrideLocalRootComponent)
{
	if(CVarEnableClothPhysics.GetValueOnAnyThread() == 0)
	{
		return;
	}

	SCOPE_CYCLE_COUNTER(STAT_ClothTotalTime);
	CSV_SCOPED_TIMING_STAT(Animation, Cloth);