Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AlphaMode Blend - Z ordering errors #11608

Closed
IDEDARY opened this issue Jan 29, 2024 · 13 comments
Closed

AlphaMode Blend - Z ordering errors #11608

IDEDARY opened this issue Jan 29, 2024 · 13 comments
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior

Comments

@IDEDARY
Copy link
Contributor

IDEDARY commented Jan 29, 2024

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

bug.mp4

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.

@IDEDARY IDEDARY added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Jan 29, 2024
@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen and removed S-Needs-Triage This issue needs to be labelled labels Jan 29, 2024
@IDEDARY
Copy link
Contributor Author

IDEDARY commented Feb 1, 2024

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.
image

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.

@floppyhammer
Copy link
Contributor

I cannot reproduce it with the 3d/texture example. Could you provide a reproduction project?

@CptPotato
Copy link
Contributor

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:

/// Adjust rendered depth.
///
/// A material with a positive depth bias will render closer to the
/// camera while negative values cause the material to render behind
/// other objects. This is independent of the viewport.
///
/// `depth_bias` affects render ordering and depth write operations
/// using the `wgpu::DepthBiasState::Constant` field.
///
/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting
pub depth_bias: f32,

Related: #5656, #2223

@IDEDARY
Copy link
Contributor Author

IDEDARY commented Feb 8, 2024

I cannot reproduce it with the 3d/texture example. 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:

/// Adjust rendered depth.
///
/// A material with a positive depth bias will render closer to the
/// camera while negative values cause the material to render behind
/// other objects. This is independent of the viewport.
///
/// `depth_bias` affects render ordering and depth write operations
/// using the `wgpu::DepthBiasState::Constant` field.
///
/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting
pub depth_bias: f32,

Related: #5656, #2223

Ok, that seems like it might be able to do something. I will try it later

@floppyhammer
Copy link
Contributor

floppyhammer commented Feb 19, 2024

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.

@floppyhammer
Copy link
Contributor

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. image

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?

@IDEDARY
Copy link
Contributor Author

IDEDARY commented Mar 14, 2024

Update: The PR mentioned here was closed as it did not solve the issue completely.
I also made reproducible: bare bones reproducible

@torsteingrindvik
Copy link
Contributor

torsteingrindvik commented May 21, 2024

This still exists in 0.13.2:

bug-transparency.mp4

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

@superdump
Copy link
Contributor

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.

@alice-i-cecile
Copy link
Member

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.

@zhuliang198754
Copy link

Excuse me, is this issue scheduled to be fixed? @alice-i-cecile

@IDEDARY
Copy link
Contributor Author

IDEDARY commented Aug 16, 2024

@superdump Note that in the original video/reproducible I posted, there are no intersections. Nomeshes collide with each other, they are just stacked closely next to each other. It should be possible to fix that with order dependent draw calls.

@IDEDARY
Copy link
Contributor Author

IDEDARY commented Oct 17, 2024

This issue has now been fixed by @IceSentry with his #14876 Order Independent PR.

Image

To enable OIT, just modify your camera like this: (more info in the OIT example) Image

@alice-i-cecile I'm closing this as completed :)

@IDEDARY IDEDARY closed this as completed Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants