Quick answer: The Chaos solver uses an iterative constraint resolution approach. With the default solver iteration count, stacked objects may not fully converge to a stable state each frame, causing small residual forces that manifest as visible jitter.
Here is how to fix Unreal chaos physics jittering stacking. You drop a few crates on top of each other in your Unreal Engine 5 level and they never settle. The stack vibrates, objects slide apart, and occasionally a box launches itself into the sky. Chaos physics is powerful, but its default configuration is tuned for general-purpose gameplay — not stable stacking. Here is how to fix it.
The Symptom
You have a set of rigid body actors — crates, barrels, furniture, anything with Simulate Physics enabled — and when they come to rest on top of each other, they never truly rest. The stack jitters visibly, with objects oscillating by fractions of a centimeter each frame. Sometimes the jitter is subtle enough that you only notice it in a close-up camera shot. Other times it is violent enough that objects slowly work themselves free and tumble off the pile.
The problem is most visible when you stack three or more objects vertically. Two objects touching the ground may appear stable, but add a third on top and the entire column begins to vibrate. The jitter is especially pronounced with convex mesh colliders rather than simple box or sphere primitives, and it gets worse as you add more objects to the pile.
If you pause the game and step frame by frame, you can see the objects shifting position slightly on each physics tick. The velocity readout on the objects never reaches zero — there is always a small residual linear or angular velocity that the solver cannot eliminate. This is the hallmark of an under-iterated constraint solver.
What Causes This
1. Insufficient solver iterations. The Chaos physics solver resolves constraints iteratively. Each iteration makes progress toward a physically correct solution, but with the default iteration counts (typically 4 position iterations and 1 velocity iteration), the solver cannot fully resolve the competing contact constraints in a tall stack. The bottom object is being pushed down by every object above it, while simultaneously being pushed up by the ground. With only a few iterations to sort this out, the solver leaves small errors that oscillate from frame to frame.
2. Missing stabilization and damping. Real-world objects lose energy through friction, deformation, and air resistance. The default Chaos configuration uses minimal linear and angular damping, so objects that should settle quickly keep bouncing around with tiny residual velocities. Additionally, the default sleep thresholds may be too low — objects that are barely moving never cross the threshold to be put to sleep, so they keep being simulated and keep jittering.
3. Collision margin too small or too large. Chaos uses a collision margin (a thin shell around each convex shape) to detect contacts before objects actually penetrate each other. If this margin is too small, the solver only discovers contacts once penetration has already occurred, forcing it to apply large corrective impulses that overshoot. If the margin is too large, objects appear to float above surfaces. Getting the margin right is critical for smooth contact resolution.
4. Inconsistent mass ratios. Stacking a 1 kg box on top of a 1000 kg platform is fine, but stacking a 1000 kg block on top of a 1 kg box creates an extreme mass ratio that the iterative solver struggles with. The solver applies corrections proportional to inverse mass, so the light object gets enormous corrections while the heavy object barely moves, leading to instability.
The Fix
Step 1: Increase solver iteration counts. This is the single most impactful change. You can set iterations per-body in C++ or globally in your project physics settings. For stacking scenarios, 8 to 12 position iterations and 4 to 8 velocity iterations provide a good balance between stability and performance.
// StackableActor.cpp - Configure solver iterations on a per-body basis
#include "StackableActor.h"
#include "Components/StaticMeshComponent.h"
void AStackableActor::BeginPlay()
{
Super::BeginPlay();
UStaticMeshComponent* Mesh = FindComponentByClass<UStaticMeshComponent>();
if (Mesh && Mesh->IsSimulatingPhysics())
{
FBodyInstance* Body = Mesh->GetBodyInstance();
if (Body)
{
// Increase position iterations for stable stacking
Body->SetPhySolverPositionIterationCount(12);
// Increase velocity iterations to reduce residual bounce
Body->SetPhySolverVelocityIterationCount(8);
}
}
}
If you want to apply this globally instead of per-actor, open Project Settings > Physics > Chaos Physics and increase the Solver Iteration Count values there. Be aware that higher iteration counts cost more CPU time, so only increase them as much as you need.
Step 2: Enable stabilization through damping and sleep thresholds. Adding linear and angular damping helps objects bleed off residual energy and settle into stable positions. Raising the sleep threshold ensures that objects with tiny velocities get put to sleep sooner rather than jittering indefinitely.
// StackableActor.cpp - Apply damping and sleep settings
void AStackableActor::ConfigureStabilization()
{
UStaticMeshComponent* Mesh = FindComponentByClass<UStaticMeshComponent>();
if (!Mesh) return;
FBodyInstance* Body = Mesh->GetBodyInstance();
if (!Body) return;
// Apply damping to bleed off residual jitter energy
Body->LinearDamping = 0.1f;
Body->AngularDamping = 0.5f;
Body->UpdateDampingProperties();
// Raise sleep thresholds so near-stationary objects sleep sooner
Body->SleepFamily = ESleepFamily::Sensitive;
Body->SetUseCCD(false); // CCD not needed for slow stacking
// Custom sleep threshold - put to sleep earlier
Body->CustomSleepThresholdMultiplier = 2.0f;
Body->bEnableGravity = true;
Mesh->SetAngularDamping(0.5f);
Mesh->SetLinearDamping(0.1f);
}
The SleepFamily::Sensitive setting uses a lower velocity threshold before putting the body to sleep. The custom sleep threshold multiplier scales that further. For stacking scenarios, you want objects to fall asleep as soon as they are reasonably stationary, rather than continuing to simulate micro-movements.
Step 3: Adjust collision margin and contact offset. The collision margin controls how early the solver begins generating contact points. For medium-scale objects (roughly 50 to 200 cm), a collision margin of 2.0 to 5.0 units works well. You can also adjust the contact offset in the physics settings to give the solver a larger pre-contact window.
// StackableActor.cpp - Adjust collision margin on convex shapes
#include "PhysicsEngine/BodySetup.h"
void AStackableActor::AdjustCollisionMargin()
{
UStaticMeshComponent* Mesh = FindComponentByClass<UStaticMeshComponent>();
if (!Mesh || !Mesh->GetStaticMesh()) return;
UBodySetup* BodySetup = Mesh->GetStaticMesh()->GetBodySetup();
if (!BodySetup) return;
// Increase collision margin for more stable contact generation
for (FKConvexElem& Convex : BodySetup->AggGeom.ConvexElems)
{
// Set margin to 3.0 units for medium-scale objects
Convex.SetCollisionMargin(3.0f);
}
// Rebuild physics state with updated margins
Mesh->RecreatePhysicsState();
}
If you are using simple collision shapes (box, sphere, capsule) rather than convex meshes, the margin matters less because the solver can compute exact contact points analytically. But for any convex decomposition or complex mesh collider, getting the margin right is essential.
One additional tip: keep mass ratios between stacked objects within a 10:1 range. If you need a visually light object to support a heavy one, override the mass to bring the ratio closer to 1:1, or use constraints instead of relying purely on contact physics.
Related Issues
If your objects are not jittering but instead falling through each other entirely, that is a tunneling problem rather than a solver convergence issue — enable Continuous Collision Detection (CCD) on fast-moving bodies. For objects that jitter only at specific frame rates, check whether your physics substep settings are consistent. Unreal defaults to a fixed physics tick rate, but if you have modified the MaxSubstepDeltaTime or MaxSubsteps values, inconsistent step sizes can amplify solver instability.
If stacking is stable but objects slide sideways off each other, the issue is likely insufficient friction rather than solver iterations. Check the physical material assigned to your meshes and increase both static and dynamic friction values. Chaos uses a friction combine mode (average, min, multiply, max) that can produce unexpectedly low friction if one surface has a low value.
More iterations, more damping, wider margins. That is the stacking stability triangle.