-
-
Notifications
You must be signed in to change notification settings - Fork 21.2k
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
Material with opaque prepass enabled, even little alpha, appears invisible if no other object is behind. #36669
Comments
Note: The rationale behind the opaque prepass is that only the opaque parts of your object will be rendered. Because you have effectively made your entire object transparent, the whole thing is discarded. godot/drivers/gles3/rasterizer_scene_gles3.cpp Line 4131 in f4e3701
I am not sure why the cutoff is 0.99, it seems the cutoff could and should just be the alpha scissor threshold. But it is what it is. That being said, this is easy to work around. There is no benefit to making your material 98% opaque and alpha scissored. You should either treat it like an opaque material, or treat it like a transparent material. |
@clayjohn |
@unSkind You example scene works fine if you just don't reduce the transparency of the albedo color. The reason it is disappearing is because you are making the entire object transparent. Opaque pre-pass only captures the opaque part of the object. |
@clayjohn |
I have created a small test project that illustrates several of the conditions required for this bug. It seems to confirm that when a part of the material has an Given that 4.0 will have rewritten this entirely it seems unlikely that this particular issue will be fixed before the 4.0 release. In the meantime there is a slightly hacky workaround using the shader language. You can click on any SpacialMaterial and click
|
Maybe someone should open a pull request on the |
OK so, this isn't what I normally do, so excuse my noobiness or if this is wasting anyone's time, I don't normally do C++ coding and I've never contributed to Godot before.. I think I found a way of implementing @AsherGlick 's hack like @Calinou suggested. I just did a tiny test right now and it appears to work. In the 3.2 branch, in file /scene/resources/material.cpp @ line 883, I added a little bit of code that tweaks the shader code that's generated. This is what that section of the code looks like normally:
And this is what I tweaked it to:
The extra line achieves what Asher's hack does. Instead of an if/then I just compacted it to cast the if condition result into a float. I don't know if that's messy or not but.. and I don't know if it would break something else, like distance fade mode or something.. but hopefully that helps. It however doesn't fix the real issue which is that if the 'depth_draw_alpha_prepass' render mode is enabled with scissor mode, the scissor value is ignored because it's fixed at 0.99. But it would fix at least my use case issue with Godot, of spatial materials with depth prepass and alpha scissor enabled together not working when there's a sky background behind them, ya know, without having to convert every SpatialMaterial of every piece of foliage in my scene to a shader and manually modify the code. Because that's been messing up my trees something fierce. What do you think? |
I think I've figured out why this issue is particularly problematic for trees. For trees, you often have lots of quads overlapping each other, so you need some kind of alpha clipping/alpha scissor to render them, and you need opaque pre-pass to render shadows of the leaves. There's no other way around it, you would have triangle sorting issues otherwise. Because the threshold is so high, when you zoom out from a surface with an alpha transparent texture of leaves on it, the effects of mipmapping kicks in. The lower mipmaps are averaging pixel values, including alpha, so the lower mipmaps are blurry and hence there's no alpha values that are greater than 0.99 anymore, even though there are plenty of values which are greater than 0.5 and which should be rendered. The threshold really needs to be controllable with the alpha scissor threshold to fix this. Here's a video example of this issue Ignore the terrible incomplete scene in the background and the floating bushes, I haven't finished the level yet :P The scissor value is really defining here what should or shouldn't be opaque, so the threshold should be set to the scissor value. It does need that flexibility too, to be a slider value, because for some materials a higher or lower threshold will be required to compensate for the effects of mipmapping. |
@RonanZe @mindinsomnia Does this still occur if using my workaround and setting the threshold lower? I feel like I ran into something very similar to this as well in my own work but it was also fixed with that little hack without realizing that mipmaps were the cause. |
@AsherGlick With your workaround the problem is fixed. Your workaround effectively produces the behaviour that Godot should be doing anyway with the scissor value so it fixes the problem easily and branch textures look fine from a distance. |
See also #40364 which may resolve this issue in other ways. |
I have been fighting with this issue as well and I'm just wondering if any workaround shouldn't discard the fragments? I assume that's what's happening in the background when you are using ALPHA_SCISSOR? At least that's what it sounds like in the manual. I get visually the same result doing this, but a big performance improvement.
|
Will this still be fixed for the 3.2.4 release? Because in some situations, you can't just convert the material and fix the shader, like with materials in imported models. Event import scripts can't do that, because there seems to be no way of converting a Spatialmaterial into a shader in code. (/scene/resources/material.cpp @ line 883)
to this:
|
@Avogine Feel free to open a pull request for this (against the Make sure to include/link to a minimal reproduction project in the PR so we can confirm this effectively fixes the issue. |
@Calinou Thanks, I will do that.😄 |
@Avogine Thanks for tracking that down. I'd like to explain what the root of the bug here is so that someone can take a stab at fixing it. By default, transparent materials do not write anything to the depth buffer when drawn. However, if "opaque_prepass" is enabled they will be drawn during the depth prepass using any portion of the object with an alpha of 1.0 (fully opaque). For some reason, right now, transparent materials with depth prepass are not being drawn in areas where the depth is not written to (i.e. there is no solid object behind). This behaviour is inconsistent and changes depending on whether a gizmo in the scene is selected. My guess is there is a some OpenGL state not being set correctly (perhaps a glDepthMask or glDepthFunc call) resulting in this inconsistent behaviour (to me it almost looks like the transparent materials are accidentally using GL_GREATER for the glDepthFunc, running the test scene through RenderDoc could confirm). Regardless of whether the prepass is used, transparent materials should draw normally. The opaque prepass should just be necessary for inclusion in screen space effects that rely on depth. #45372 would help alleviate this issue as it allows transparent materials to write to depth even if their alpha is less than 1.0, but it doesn't fully resolve this issue. |
Thanks for the explanation.😄 |
This may be fixed by #50721 or may be moot, as you no longer have to use alpha scissoring for foliage anymore. You can use real alpha. As of this PR, my trees use |
Closing per the above comment. |
Godot version:
3.2 stable
EDIT: tested with 3.2.1 RC1 and the problem is present too
OS/device including version:
Windows 10 1903
Issue description:
Material with opaque prepass enabled, even little alpha, appears invisible if no other object is behind. Tested on 3.1, the issue is not present.
I tried to create leaves for trees and, if no other object is behind I see them invisible.
in 3.1 the issue is not present (same project)
Steps to reproduce:
create a quad with material with alpha texture, enable opaque prepass, enable alpha scissor (additionaly decrease the alpha channel of albedo color to 255 -> 252) and see the object become completely transparent.
Minimal reproduction project:
IssueOpaquePrepass.zip
The text was updated successfully, but these errors were encountered: