bSubstepping
bSubstepping
#Overview
name: bSubstepping
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 11
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of bSubstepping is to control whether the physics simulation should be subdivided into smaller time steps (substeps) during each frame. This setting is part of the physics engine in Unreal Engine 5 and is used to improve the accuracy and stability of physics simulations, especially in scenarios with fast-moving objects or complex interactions.
The bSubstepping variable is primarily used in the physics engine subsystem of Unreal Engine 5. It is referenced in the PhysicsSettings, BodyInstance, and ChaosScene modules, which are core components of the physics simulation system.
The value of this variable is set in the UPhysicsSettings class, which is likely configurable through the project settings in the Unreal Engine editor.
Several other variables interact with bSubstepping, including:
- MaxSubstepDeltaTime
- MaxSubsteps
- MinPhysicsDeltaTime
- MaxPhysicsDeltaTime
Developers must be aware of the following when using this variable:
- It is marked as experimental, and certain functionality might not work correctly when enabled.
- Enabling substepping can affect performance, as it may increase the number of physics calculations per frame.
- When substepping is enabled, it alters how the physics delta time is calculated and applied.
Best practices when using this variable include:
- Test thoroughly when enabling substepping, as it may introduce unexpected behavior in physics simulations.
- Adjust related variables (MaxSubstepDeltaTime, MaxSubsteps) to find the right balance between simulation accuracy and performance.
- Monitor performance impacts when enabling substepping, especially in complex scenes or on target platforms with limited resources.
- Consider using bSubstepping only when dealing with fast-moving objects or complex physics interactions that require higher accuracy.
- Be aware that enabling substepping may affect other physics-related settings and behaviors, so ensure to test all physics-dependent systems in your game when modifying this setting.
#Setting Variables
#References In INI files
Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:338, section: [/Script/Engine.PhysicsSettings]
- INI Section:
/Script/Engine.PhysicsSettings
- Raw value:
False
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/PhysicsEngine/PhysicsSettings.h:205
Scope (from outer to inner):
file
class class UPhysicsSettings : public UPhysicsSettingsCore
Source code excerpt:
/** Whether to substep the physics simulation. This feature is still experimental. Certain functionality might not work correctly*/
UPROPERTY(config, EditAnywhere, Category = Framerate)
bool bSubstepping;
/** Whether to substep the async physics simulation. This feature is still experimental. Certain functionality might not work correctly*/
UPROPERTY(config, EditAnywhere, Category = Framerate)
bool bSubsteppingAsync;
/** Whether to tick physics simulation on an async thread. This feature is still experimental. Certain functionality might not work correctly*/
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/PhysicsEngine/BodyInstance.cpp:4468
Scope (from outer to inner):
file
function void FBodyInstance::UpdateInterpolateWhenSubStepping
Source code excerpt:
void FBodyInstance::UpdateInterpolateWhenSubStepping()
{
if(UPhysicsSettings::Get()->bSubstepping)
{
// We interpolate based around our current collision enabled flag
ECollisionEnabled::Type UseCollisionEnabled = ECollisionEnabled::NoCollision;
if(OwnerComponent.IsValid() && OwnerComponent.Get()->GetBodyInstance() != this)
{
UseCollisionEnabled = OwnerComponent->GetCollisionEnabled();
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysLevel.cpp:147
Scope (from outer to inner):
file
function void UWorld::SetupPhysicsTickFunctions
Source code excerpt:
static const auto CVar_MaxPhysicsDeltaTime = IConsoleManager::Get().FindTConsoleVariableDataFloat(TEXT("p.MaxPhysicsDeltaTime"));
PhysScene->SetUpForFrame(&DefaultGravity, DeltaSeconds, UPhysicsSettings::Get()->MinPhysicsDeltaTime, UPhysicsSettings::Get()->MaxPhysicsDeltaTime,
UPhysicsSettings::Get()->MaxSubstepDeltaTime, UPhysicsSettings::Get()->MaxSubsteps, UPhysicsSettings::Get()->bSubstepping);
}
void UWorld::StartPhysicsSim()
{
FPhysScene* PhysScene = GetPhysicsScene();
if (PhysScene == NULL)
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp:20
Scope (from outer to inner):
file
function UPhysicsSettings::UPhysicsSettings
Source code excerpt:
, MinPhysicsDeltaTime(UE_SMALL_NUMBER)
, MaxPhysicsDeltaTime(1.f / 30.f)
, bSubstepping(false)
, bTickPhysicsAsync(false)
, AsyncFixedTimeStepSize(1.f / 30.f)
, MaxSubstepDeltaTime(1.f / 60.f)
, MaxSubsteps(6)
, SyncSceneSmoothingFactor(0.0f)
, InitialAverageFrameRate(1.f / 60.f)
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/PhysicsEngine/PhysicsSettings.cpp:89
Scope (from outer to inner):
file
function bool UPhysicsSettings::CanEditChange
Source code excerpt:
if(Name == TEXT("MaxPhysicsDeltaTime") || Name == TEXT("SyncSceneSmoothingFactor") || Name == TEXT("AsyncSceneSmoothingFactor") || Name == TEXT("InitialAverageFrameRate"))
{
bIsEditable = !bSubstepping;
}
}
return bIsEditable;
}
#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/PhysicsSolverBase.cpp:425
Scope (from outer to inner):
file
namespace Chaos
function FGraphEventRef FPhysicsSolverBase::AdvanceAndDispatch_External
Source code excerpt:
FGraphEventRef FPhysicsSolverBase::AdvanceAndDispatch_External(FReal InDt)
{
const bool bSubstepping = MMaxSubSteps > 1;
SetSolverSubstep_External(bSubstepping);
const FReal DtWithPause = bPaused_External ? 0.0f : InDt;
FReal InternalDt = DtWithPause;
int32 NumSteps = 1;
if(IsUsingFixedDt())
{
#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/PhysicsSolverBase.cpp:449
Scope (from outer to inner):
file
namespace Chaos
function FGraphEventRef FPhysicsSolverBase::AdvanceAndDispatch_External
Source code excerpt:
}
}
else if (bSubstepping && InDt > 0)
{
NumSteps = FMath::CeilToInt32(DtWithPause / MMaxDeltaTime);
if (NumSteps > MMaxSubSteps)
{
// Hitting this case means we're losing time, given the constraints of MaxSteps and MaxDt we can't
// fully handle the Dt requested, the simulation will appear to the viewer to run slower than realtime
#Loc: <Workspace>/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/Framework/PhysicsSolverBase.cpp:551
Scope (from outer to inner):
file
namespace Chaos
function FGraphEventRef FPhysicsSolverBase::AdvanceAndDispatch_External
Source code excerpt:
// This break is mainly here to satisfy unit testing. The call to StepInternalTime_External will decrement the
// delay in the marshaling manager and throw of tests that are explicitly testing for propagation delays
if (IsUsingAsyncResults() == false && !bSubstepping)
{
break;
}
}
if (AsyncBlockMode == EAsyncBlockMode::DoNoBlock)
{
#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Private/ChaosScene.cpp:332
Scope (from outer to inner):
file
function void FChaosScene::SetUpForFrame
Source code excerpt:
}
void FChaosScene::SetUpForFrame(const FVector* NewGrav,float InDeltaSeconds /*= 0.0f*/,float InMinPhysicsDeltaTime /*= 0.0f*/,float InMaxPhysicsDeltaTime /*= 0.0f*/,float InMaxSubstepDeltaTime /*= 0.0f*/,int32 InMaxSubsteps,bool bSubstepping)
{
using namespace Chaos;
SetGravity(*NewGrav);
InDeltaSeconds *= MNetworkDeltaTimeScale;
if(bSubstepping)
{
MDeltaTime = FMath::Min(InDeltaSeconds, InMaxSubsteps * InMaxSubstepDeltaTime);
}
else
{
MDeltaTime = InMaxPhysicsDeltaTime > 0.f ? FMath::Min(InDeltaSeconds, InMaxPhysicsDeltaTime) : InDeltaSeconds;
#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Private/ChaosScene.cpp:350
Scope (from outer to inner):
file
function void FChaosScene::SetUpForFrame
Source code excerpt:
if(FPhysicsSolver* Solver = GetSolver())
{
if(bSubstepping)
{
Solver->SetMaxDeltaTime_External(InMaxSubstepDeltaTime);
Solver->SetMaxSubSteps_External(InMaxSubsteps);
}
else
{
#Loc: <Workspace>/Engine/Source/Runtime/PhysicsCore/Public/Chaos/ChaosScene.h:138
Scope: file
Source code excerpt:
PHYSICSCORE_API void StartFrame();
PHYSICSCORE_API void SetUpForFrame(const FVector* NewGrav,float InDeltaSeconds,float InMinPhysicsDeltaTime,float InMaxPhysicsDeltaTime,float InMaxSubstepDeltaTime,int32 InMaxSubsteps,bool bSubstepping);
PHYSICSCORE_API void EndFrame();
DECLARE_MULTICAST_DELEGATE_OneParam(FOnPhysScenePostTick,FChaosScene*);
FOnPhysScenePostTick OnPhysScenePostTick;
PHYSICSCORE_API void KillSafeAsyncTasks();