Persistent Simulation Islands#809
Merged
Merged
Conversation
Jondolf
added a commit
that referenced
this pull request
Sep 30, 2025
# Objective In past versions of Avian, adding/removing `Sleeping` manually was supported as a way to sleep or wake up a rigid body. However, after #809, this does not work properly, and you should instead use the `SleepBody` and `WakeBody` commands. Additionally, `SleepBody` does not currently split the island, which can cause bodies that are not in contact to also be forced asleep. ## Solution Split islands when using `SleepBody`, and add hooks to automatically sleep/wake bodies when `Sleeping` is manually added/removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
Closes #578.
Sleeping and waking are crucial for reducing CPU overhead for large game worlds. Up until now, Avian has used basic per-body sleeping that only allows sleeping for dynamic bodies that are not in contact with each other and not connected via joints. This means that object piles and joints are never allowed to sleep.
The standard solution to this problem is simulation islands. Bodies that are touching or connected by a joint belong to the same island, and can only sleep if the whole island can sleep. Conversely, if any dynamic body in an island is woken up, the whole island is woken up.
Solution
Implement persistent simulation islands for sleeping and waking. Islands are persisted across time steps, merged when constraints are added between different islands, and split heuristically in a deferred manner.
The below video displays the combined bounds of each body in each island as a red bounding box. When islands are marked as sleeping, the outline becomes darker.
simulation_islands.mp4
Implementation
The island implementation is primarily based on Erin Catto's Simulation Islands article and Box2D.
PhysicsIsland, stored in thePhysicsIslandsresource.IslandNodestored in eachBodyIslandNodecomponent,ContactEdge, andJointEdge.PhysicsIsland::constraints_removedis incremented.split_candidate, and split using DFS. Splitting is expensive, but it can safely be deferred and done heuristically like this.Sleeping and Waking Changes
For a body to fall asleep, its whole island must be able to sleep. A body and its island are woken up when any of the following happens:
Transform,LinearVelocity, orAngularVelocityof a sleeping body is modified.Forces, without usingnon_waking.Gravityresource orGravityScalecomponent is modified.A body and all bodies connected to it can also be forced to sleep or wake up using the
SleepBodyorWakeBodycommands, or by using theSleepIslandsorWakeIslandscommands.The
SleepingPluginhas been replaced by theIslandSleepingPlugin. It uses anAwakeIslandBitVecto track which islands should be kept awake, and updates sleep timers and splitting candidates.Additionally, I renamed some components for clarity and consistency:
TimeSleeping->SleepTimerSleepingThreshold->SleepThresholdDeactivationTime->TimeToSleep(also a component and not a resource now)Alternatives
In this PR, I have implemented persistent simulation islands. This implies caching state. For a "stateless" solution, islands could also be built from scratch each frame with a depth-first search or union-find algorithm.
Based on Erin's results, persistent islands can be roughly an order of magnitude faster than building islands from scratch with DFS. A decent alternative could be Jolt's parallel union find algorithm, but it appears to require expensive sorting for determinism.
Still, in the future, we could look into a stateless alternative alongside the persistent one, for cases where that may be desirable, such as rollback or scrubbing through time.
Note on Parallelism
While simulation islands can also be used for solver parallelism, we only use them for sleeping and waking, similar to Box2D. Graph coloring (#771) is used for the multi-threaded constraint solver.
Migration Guide
Stacks of bodies as well as bodies connected by joints now form "simulation islands" that are allowed to enter a low-cost sleeping state when all bodies in a given island are resting. This can significantly reduce CPU overhead for large game worlds with lots of dynamic bodies. Previously, bodies were only allowed to sleep when they were not interacting with other dynamic bodies.
The following components have been renamed:
TimeSleeping->SleepTimerSleepingThreshold->SleepThresholdDeactivationTime->TimeToSleep(also a component and not a resource now)Additionally, the
SleepingPluginhas been replaced by theIslandSleepingPlugin.