AlphaMode Blend - Z ordering errors
Bevy version
Version 0.12.1 or Bevy main, latest commit: e94297f
`AdapterInfo { name: "NVIDIA GeForce RTX 3060 Laptop GPU", vendor: 4318, device: 9504, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "535.154.05", backend: Vulkan }`
What you did
I used AlphaMode:Blend on Standard Material slapped onto Quad mesh
https://github.com/bevyengine/bevy/assets/49441831/3eacad4a-682a-42f3-90ff-c13b81e9e6d5
What went wrong
The Z-ordering is most likely breaking under different camera angles. Most likely a math error somewhere in the blending pipeline.
You can see the semi-transparent texture blinking in certain moments.
The text's alpha is 100% and black background is 75%.
The issue only happens when AlphaMode is set to Blend
Additional information
The code for replicating this should be simple. I did not do anything to rendering, but I encountered it while developing UI library. The code is currently private and WIP, but I can provide it early if people are interested to fix this issue.
This issue is also present in billboard crate for text. It happens whenever 2 or more transparent meshes are on top of each other. Just transparent background and billboard text mesh is enough to break things.
I thought that stacking transparent images is edge-case, but it turned out that it is also triggered by 3D non-transparent text, which I assume also uses blend mode under the hood.
This just bumped the issues severity and I now consider it a blocker for Bevy's future world-space UI.
I cannot reproduce it with the 3d/texture example. Could you provide a reproduction project?
The Z-ordering is most likely breaking under different camera angles. Most likely a math error somewhere in the blending pipeline.
There is no way to correctly sort transparent objects correctly in all scenarios when drawing them separately. Bevy sorts transparent objects based on their distance to the camera, which is common practice.
From what I can tell this is working correctly in your example, even if the result looks odd. To get the expected behavior, either change the origin of the 3D models used or apply a depth bias in the material to force the desired sorting, see bevy_pbr::StandardMaterial:
https://github.com/bevyengine/bevy/blob/71be08af68e081cab466f3bbe3728c30db3a94f7/crates/bevy_pbr/src/pbr_material.rs#L374-L384
Related: #5656, #2223
I cannot reproduce it with the
3d/textureexample. Could you provide a reproduction project?
Of course, here it is https://github.com/IDEDARY/Bevycom/tree/bevy-issue-z-ordering
The Z-ordering is most likely breaking under different camera angles. Most likely a math error somewhere in the blending pipeline.
There is no way to correctly sort transparent objects correctly in all scenarios when drawing them separately. Bevy sorts transparent objects based on their distance to the camera, which is common practice.
From what I can tell this is working correctly in your example, even if the result looks odd. To get the expected behavior, either change the origin of the 3D models used or apply a depth bias in the material to force the desired sorting, see
bevy_pbr::StandardMaterial:https://github.com/bevyengine/bevy/blob/71be08af68e081cab466f3bbe3728c30db3a94f7/crates/bevy_pbr/src/pbr_material.rs#L374-L384
Related: #5656, #2223
Ok, that seems like it might be able to do something. I will try it later
It seems the calculated distance is wrong under some camera angles, which results in wrong sorted render order.
Correct case:
translation Vec3(9.0, -182.5, -170.0) distance -1005.19183
translation Vec3(9.0, -182.5, 30.0) distance -840.30206
translation Vec3(9.0, -182.5, 230.0) distance -675.4123
translation Vec3(-2.5, 202.5, -140.0) distance -846.68134
translation Vec3(-2.5, 202.5, 60.0) distance -681.79156
translation Vec3(-2.5, 202.5, 260.0) distance -516.90186
The correct render order is 1->4->2->5->3->6.
Wrong case:
translation Vec3(9.0, -182.5, -170.0) distance -990.4487
translation Vec3(9.0, -182.5, 30.0) distance -846.5717
translation Vec3(9.0, -182.5, 230.0) distance -702.69476
translation Vec3(-2.5, 202.5, -140.0) distance -829.6107
translation Vec3(-2.5, 202.5, 60.0) distance -685.73376
translation Vec3(-2.5, 202.5, 260.0) distance -541.8568
Now the order became 1->2->4->3->5->6.
This issue is also present in billboard crate for text. It happens whenever 2 or more transparent meshes are on top of each other. Just transparent background and billboard text mesh is enough to break things.
I thought that stacking transparent images is edge-case, but it turned out that it is also triggered by 3D non-transparent text, which I assume also uses blend mode under the hood.
This just bumped the issues severity and I now consider it a blocker for Bevy's future world-space UI.
@IDEDARY Could you help test the PR in this case?
Update: The PR mentioned here was closed as it did not solve the issue completely. I also made reproducible: bare bones reproducible
This still exists in 0.13.2:
https://github.com/bevyengine/bevy/assets/52322338/7c7d1030-3189-43b0-826c-9d42f2ab536d
These are basically just PBR bundles of cuboid meshes with standard materials set from colors, but with AlphaMode::Blend set.
@alice-i-cecile do you see any hope for this to get a fix for 0.14? Hoping to avoid waiting for 0.15 for using transparency.
EDIT: I also tried @IDEDARY 's repro above but changed to Bevy main branch just to make sure it isn't already fixed, and I see the bug there as well
The only way to fix this is order-independent transparency. Plain apps blending by ordering draws by their transform origins in view space only works up to a point. If you have intersecting triangles or situations like in the original video then what bevy currently supports out of the box will not be sufficient.
Agreed on the need for order-independent-transparency. @IceSentry had a really lovely implementation that I'd be happy to see upstreamed by him or someone else. No chance it makes it for 0.14 though.
