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

Transparent png images are not rendered correctly #3050

Closed
xiaopengli89 opened this issue Oct 29, 2021 · 9 comments
Closed

Transparent png images are not rendered correctly #3050

xiaopengli89 opened this issue Oct 29, 2021 · 9 comments
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior
Milestone

Comments

@xiaopengli89
Copy link

Bevy version

pipelined-rendering#c5af1335

Operating system & version

macOS 12.0.1

What you did

I wrote a simple demo based on the new renderer,there is a white quad and a png image quad in the demo.

What you expected to happen

The transparent part of the png image is always transparent.

What actually happened

In some cases, the transparent part of the png will show clear color.

Additional information

default.mov
@xiaopengli89 xiaopengli89 added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Oct 29, 2021
@xiaopengli89
Copy link
Author

I think the cause of the problem lies in the calculation of the distance of the two quads. The distance is calculated based on the transform. The shape and size of the mesh are not considered. As a result, the distance of the image quad may be smaller than the white quad, which causes the image quad to be rendered first.

@NiklasEi NiklasEi added A-Rendering Drawing game state to the screen and removed S-Needs-Triage This issue needs to be labelled labels Oct 29, 2021
@NiklasEi NiklasEi added this to the Bevy 0.6 milestone Oct 29, 2021
@NiklasEi
Copy link
Member

@alice-i-cecile I added this to 0.6, I hope you agree

@alice-i-cecile
Copy link
Member

Yep; this is the sort of rendering bug that would be nasty to let slip through, and the fix doesn't seem terribly involved.

@superdump
Copy link
Contributor

As a note, transparency should work properly on pipelined-rendering in the PBR pipeline after #3072. Is this 3D or 2D? Looks 3D given the perspective. I haven't done anything with sprites and transparency though. The bevymark_pipelined example uses a round icon image that is a PNG with transparency and that seems to work fine.

@xiaopengli89 can you share the code you're using to reproduce the issue? That way we can test it. If it is indeed an artifact of essentially z-fighting then having the exact positioning of things may help. Also the size of the sprite / texture depending on whether this is using sprites or just quad meshes.

@CptPotato
Copy link
Contributor

I think there's two problems. As @xiaopengli89 mentioned, ordering is one of them. I.e. in the scene above, having the camera look at an angle can produces cases where the white quad is drawn after the transparent sprite.

Solving this isn't trivial, I think. There has to be some representative point or value for each entity to sort transparent objects for correct blending order (back to front). But this doesn't work in all cases or is sometimes impossible, especially if complex entities are close to each other or intersect.

The specific case in the video could be solved a few different ways:

  • have the camera look straight at the sprites (soring by depth will result in the correct order)
  • sort the sprites based on a different value that will produce the correct order for this specific use case (for example simply use the z-coordinate / forward axis)
  • separate opaque and transparent entities and render them accordingly (one layer of transparency should always look correct when rendered after an opaque pass)
    • (I'm assuming that the white quad is supposed to be fully opaque)
  • use a hard alpha threshold (1-bit alpha), effectively turning transparent geometry into opaque
  • (weight blended transparency was talked about before but I'm cetrain it would not work very well in this specific case)

The other issue (the front sprite showing the clear color) happens because of the following I think:

  1. the sprites aren't sorted correctly (because of the difficulties mentioned above)
  2. the front sprite is drawn first and writes to the depth buffer
  3. the white quad is drawn second, but fails the depth check where the sprite was drawn and thus shows the clear color in the transparent regions
  4. when the distance between the sprites is great enough and the ordering is correct again the problem is gone

Usually transparent entities only perform a depth comparison but not write to the depth buffer to avoid these issues. (1-bit alpha is an exception because these entities can be part of the opaque pass).

I'm not up to speed on the new renderer, but as @superdump hinted the second issue might already be solved by now.

@superdump
Copy link
Contributor

superdump commented Nov 6, 2021

Take a look at #3072 As a quick summary, it supports opaque, alpha masked (with a cutoff value), and transparent alpha modes according to the glTF spec. There are depth prepasses for opaque and alpha mask modes where the alpha mask prepass samples the material to get the alpha value and discards the fragment if it is below the cutoff. There are opaque and alpha mask main passes that use the equals depth buffer comparison function, and set alpha to 1.0 explicitly, replacing the colour in the target texture. There is a transparent pass that uses the greater depth buffer comparison function, keeps alpha as is and uses the alpha blending over operator. Opaque and alpha mask are sorted front to back, transparent back to front using the view space z position of the mesh’s transform. As such, if this is all using PBR, and the white plane were marked opaque and the textured quad were marked as alpha mask and has some fragments in front of the white quad then it should work. If the fragment positions are exactly equal (as in exactly) then I think the alpha masked values would overwrite the opaque values simply because the opaque pass is run first.

@xiaopengli89
Copy link
Author

I will try again with #3072 .

@xiaopengli89
Copy link
Author

I tried the latest version of pipelined-rendering branch, everything works well except when I set both white quad and png to Blend mode.

I think it's related to #2223.

2021-11-18.8.32.55.mov

@cart
Copy link
Member

cart commented Dec 18, 2021

Yeah I think I'll close this out because that specific issue is already captured in #2223. Thanks for investigating!

@cart cart closed this as completed Dec 18, 2021
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

No branches or pull requests

6 participants