Use mesh bounds center for transparent/transmissive sorting #22041
+71
−44
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.
Transparent and transmissive phases previously used the instance translation from GlobalTransform as the sort position. This breaks down when mesh geometry is authored in "world-like" coordinates and the instance transform is identity or near-identity (common in building/CAD-style content). In such cases multiple transparent instances end up with the same translation and produce incorrect draw order.
This change introduces sorting based on the world-space center of the mesh bounds instead of the raw translation. The local bounds center is stored per mesh/instance and transformed by the instance’s world transform when building sort keys. This adds a small amount of per-mesh/instance data but produces much more correct transparent and transmissive rendering in real-world scenes.
Objective
Currently, transparent and transmissive render phases in Bevy sort instances using the translation from GlobalTransform. This works only if the mesh origin is a good proxy for the geometry position. In many real-world cases (especially CAD/architecture-like content), the mesh data is authored in "world-like" coordinates and the instance
Transformis identity. In such setups, sorting by translation produces incorrect draw order for transparent/transmissive objects.I propose switching the sorting key from
GlobalTransform.translationto the world-space center of the mesh bounds for each instance.Solution
Instead of using
GlobalTransform.translationas the sort position for transparent/transmissive phases, use the world-space center of the mesh bounds:RenderMeshInstanceSharedascenter: Vec3derived from the meshAabb).This way:
The main trade-offs:
RenderMeshInstanceShared(typically +12 or +16 bytes depending on alignment),Alternative approach and its drawbacks
In theory, this could be fixed by baking meshes so that:
Transformis adjusted to move it back into place.However, this has several drawbacks:
In practice, this is not a scalable or convenient solution.
Secondary issue: unstable ordering when depth is equal
There is another related problem with the current sorting: when two transparent/transmissive instances end up with the same view-space depth (for example, their centers project onto the same depth plane), the resulting draw order becomes unstable. This leads to visible flickering, because the internal order of
RenderEntityitems is not guaranteed to bestable between frames.
In practice this happens quite easily, especially when multiple transparent instances share the same or very similar sort depth, and
their relative order in the extracted render list can change frame to frame.
To address this, I suggest extending the sort key with a deterministic tie-breaker, for example the entity's main index. Conceptually, the sort key would become:
This ensures that instances with the same depth keep a consistent draw order across frames, removing flickering while preserving the intended depth-based sorting behavior.
Testing
cargo run -p ci -- test cargo run -p ci -- doc cargo run -p ci -- compileRun this "example"
Showcase
In my tests with building models (windows, glass, etc.), switching from translation-based sorting to bounds-center-based sorting noticeably improves the visual result. Transparent surfaces that were previously fighting or blending incorrectly now render in a much more expected order.
Current:
https://youtu.be/WjDjPAoKK6w
Sort by aabb center:
https://youtu.be/-Sl4GOXp_vQ
Sort by aabb center + tie breaker:
https://youtu.be/0aQhkSKxECo