Editor 2022.3.38f1, Unity Physics 1.3.2. Also tested in Unity 6.0.21f1
I made a domino game and all tiles are using the same components. This happens when they are pushed one-by-one, and the performance runs like the image below. Only one line is pushing down from the start to the end, but the performance starts dropping so quick.
However, with 1.5k tiles, even pushing down multiple lines of dominos, this issue didn’t appear at all.
Additionally, after the line finished which means no tiles are changing, the performance issue will be gone. However, if one of the tile’s status changed (either be pushed or destroyed), the performance issue will appear immediately.
Also, this issue will not appear if I create new tiles away from this matrix and push those new tiles.
Would you mind posting a profiler screenshot with the jobs panel expanded and doing the same for Unity Physics as underlying simulation engine in addition to Havok?
The issue might be related to the parallel solver.
If you use single threaded you should get more smooth time consumption increases that grow with the number of dominoes regardless of the structure of your domino lines. This is just in comparison and to confirm my hypothesis.
To be honest, Unity Physics isn’t ideal for my user case.
All the tiles created (Dynamic PhysicsBody, Box shape) standing on the ground will shake forever. As I feel, it means the performance issue starts immediately.
Performance capture with 6.5k tiles.
+++++++++++++++++++++++++++++++++++++++++++++++
However, it seems like this performance issue wont appear if dealing with 1.5k tiles. Even the tiles are still shaking forever with Unity Physics.
The shaking is likely caused by an issue we just found with box colliders. When you flip them around, the shaking should stop.
This seems to happen only with small boxes also. What size are they?
Would you be able to share some reproduction steps? Or file a bug through the Unity bug reporting system and attach a small project that reproduces this issue?
The tile’s size is 0.05 * 0.3 * 0.15.
Prafab components are:
Transform (posi = 0, rota = 0)
MeshFilter (box)
MeshRenderer
PhysicsBody (Dynamic, Mass 0.01, LinearDamping 0.1, AD 0.05)
PhysicsShape (Box, size 0.05, 0.3, 0.15)
In a baker, GetEntity(entity, Trans.Dynamic)
In an ISystem, call the method
void TestJob()
{
var inputBuffer = SystemAPI.GetSingletonBuffer<ItemPlacementInput>();
var xTotal = 513; // Total number of positions in the x direction
var zTotal = 128; // Total number of positions in the z direction
var gap = 0.2f; // Gap between each position
// Create an array to hold the positions
var positions = new Vector3[(int)xTotal * (int)zTotal];
int index = 0; // Index for the positions array
for (int x = 0; x < xTotal; x++)
{
for (int z = 0; z < zTotal; z++)
{
// Calculate the position with gap
float xPos = x * gap; // Position in x direction
float zPos = z * gap; // Position in z direction
// Store the position in the array
positions[index] = new Vector3(xPos, 0, zPos);
var trans = LocalTransform.FromPosition(positions[index]);
// Add tile data to the InputBuffer
inputBuffer.Add(new ItemPlacementInput
{
ItemType = ItemType.Normal,
LocalTransform = trans
});
index++; // Move to the next index in the positions array
}
}
}
The ItemPlacementSystem.cs can be found in my initial post.
Push down a tile by changing the entity’s position. Probably don’t need to do anything if it’s on UnityPhysics.
You will see the Default World Unity.Physics.Systems.BuildPhysicsWorld performance issue.
If you change the number to 512/2 * 128/2, the issue wont appear.
Regarding jittering of the dominoes:
Yeah I think that might be exactly the case which we are looking at right now in regards to collision behavior artifacts.
The box likely collapses to a quad internally because the convex bevel radius in your PhysicsShape is set to a value that is greater or equal half of the smallest dimension, so, 0.025. That can cause jitter in the contact generation.
You can see this also in the PhysicsDebugDisplay in the collider edges mode.
Make sure that the bevel radius is sufficiently small for this to be prevented.
Regarding the performance:
The issue is not in BuildPhysicsWorld. It’s that your simulation due to the sheer number of colliding elements becomes so slow that the physics runs again to try to catch up, which obviously won’t work.
You see that by the BuildPhysicsWorld system running again while the solver jobs are still running in your first screenshot.
Since the solver needs to complete and the new rigid body transformations need to be computed before the BuildPhysicsWorld can commence, it simply waits for these corresponding simulation jobs (generate contacts, solver, integration) to have completed.
The time displayed in the BuildPhysicsWorld system is therefore not time spent by it, but time waited. All systems in physics launch jobs to do their work. The heavy jobs spawned by the BuildPhysicsWorld system are for example CreateMotions, CreateBodies and BuildBranches. As you can see, these run fast in both cases, the one with the slowdown and the other without the slowdown.
What’s slower are the simulation jobs, launched by the NarrowphaseSystem (for finding and generating contacts) and the SolveAndIntegrateSystem (for computing contact forces) for example. These are the ParallelCreateContactsJob and the SolverJob among others.
In other words, your simulation is too heavy.
Consider disabling some of your dominoes if you need so many when they come to rest by making them static.
You can also change the RateManager in the FixedStepSimulationSystemGroup to prevent the physics from running multiple times per frame and thereby aggravating the performance issue.
I suggested the same for this very similar case. See the thread for details:
Hi Daniel, thank you so much for the detailed explanation, it brings me to do more testing about this
With UnityPhysics, I have changed the size of each matrix to 251 * 63 = 15k+ (due some math reason, not exactly 513/2 * 128/2). Then, I started to create the matrix one by one, each with 16k+ tiles.
The first two matrices don’t have much performance problem at all, thanks to DOTS. (And the jittering is good for testing at this point.)
When the third matrix is created (47k+ entities), the Time for PhysicsSystemGroup is jumping between 4 ms and 15 ms, 90% of the time from the PhysicsSimulationGroup and 90% from the PhysicsSolveAndIntegrate.
The fourth matrix (63k+ entities) brings a significant performance cost, and the total number of tiles is close to a 512*128 matrix.
** PhysicsSystemGroup 50ms
** PhysicsBuildWorldGroup 28ms
** PhysicsSimulationGroup 20ms
The result of four smaller matrices is the same as one big matrix.
With UnityPhysics, when I’m pushing down a line of dominos, the system time spent is the image bellow. It is slow overall since the entity number is so high, but not weird.
With Havok and a 513*128 matrix of entities, when pushing down a line, the weird thing appears. Not much cost on SimulationGroup, but the PhysicsBuildWorldGroup.
Also with HavokPhysics, use smaller matrix (251*63).
If I create four matrices of entities (63k+) and each matrix is away from the other around 3 units. There isnt anything weird happen.
If four matrices are created next to anther, such as around 0.2 unit at the z-aix, the sharp increasement will appear just like with a big matrix.
With UnityPhysics, it behaves just like you explained previously. However, I think it is a different story with the Havok Physics.
At this stage, I personally prefer Havok for the domino simulation game development because it acts better when a domino tower is involved.
To understand where the time is really spent, you need to unfortunately look at the Jobs. The aggregate performance per system doesn’t tell you whether the system is waiting for jobs scheduled by another system to finish, which as we saw in your profile screenshot is the case.
Note also that the build phase in the pipeline is identical in both engines, regardless whether you use Havok or Unity Physics as engines.
The difference you are seeing in the aggregate time in the build phase between both engines therefore confirms that this comes from waiting for jobs from another system / phase altogether and not from work related to the build phase itself.
In order to see which systems launch which jobs and to figure out where the long running jobs are coming from you can click on the three dots in the top right of the profiler’s timeline and enable “show flow events”. These flow events show you the scheduling moments and the systems of origin for all jobs in the timeline.
I gave some examples in my other response of which system launches which jobs, like the SolveAndIntegrateSystem from the Unity Physics engine launching the solver jobs for example.
In Havok you’ll see a different setup.
From the profiler screenshots you provide, it is clear that the performance degradation comes from a so-called spiral of death in which due to too slow physics updates, the catch up mechanism that is running by default in entities keeps making things worse by continuously trying to catch up by running additional physics updates in the same frame.
You can see this in the “fast” profile already. Here we see at least two BuildPhysicsWorld system updates. There should be only one.
In the “slow” profile it’s even worse and you see 4 or 5.
In (this response)[Slow Physics: How do I examine this Performance Readout?] in another thread about physics performance, I explain how to replace this catch up system with one that is guaranteed to always only perform one physics step per frame.
Once you have this in place, you will see the true performance of your simulation and can then make adjustments to speed it up if required.
public class WorldInitialization
{
[RuntimeInitializeOnLoadMethod]
static void InitialRateManager()
{
var fixedGroup = World.DefaultGameObjectInjectionWorld.GetExistingSystemManaged<FixedStepSimulationSystemGroup>();
fixedGroup.RateManager = new RateUtils.FixedRateSimpleManager(1f / 60f);
Debug.Log(fixedGroup.RateManager.Timestep);
}
}
the multiple-BuildPhysicsWorld issue is gone, because the fixedGroup will be focused to execute only one time each frame.
EDIT at Jul 2025:
HOWEVER, with this “new RateUtils.FixedRateSimpleManager(1f / 60f)”, it means the fixedGroup will update exactly at the rate of (1/60).
For example, if an entity is falling from the sky, it will take longer at 30 fps than 60 fps.
Without the “FixedRateSimpleManager”, it should take the same time at different fps. The reason for “taking the same time at different fps”, as I understand, is that the fixedGroup is executed more times on a single frame at lower fps and will skip the execution on some frames at higher fps.