-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
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
Fix PanoramaSky artifacts on Android/GLES2 #44489
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making a pull request! This certainly is a troubling bug.
As you'll see my comments, I'm a little skeptical that these are the proper fixes. I will take a closer look tonight and try running this on an android device. In the meantime, do you mind uploading an image of a radiance cubemap generated from this PR. you can capture it in RenderDoc and save to a png fairly easily.
A better fix would be to check for the existence of the |
@ForestKatsch GLSL extension checking is handled within each shader with preprocessor directives as below: godot/drivers/gles2/shaders/cubemap_filter.glsl Lines 30 to 45 in 68013d2
|
This is definitely not a long-term proper fix. Without support for fragment shader texture LOD sampling, I don't know if there can be a proper fix for this bug. But an incorrect result is arguably an improvement over the black artifacts. I don't have a native Android device, only an Oculus Quest 2. I'll look into getting RenderDoc captures.
Without checking for the extension on the C++ side, I don't think there's a clean workaround for devices that don't support the |
@ForestKatsch Well, we can just do a different codepath for all android devices. While it won't be as smooth, we could just force android devices to read from the source panorama. You would do so by putting an |
Note that this would apply to iOS too (and WebGL I think). |
I don't know all of the tradeoffs between sampling from the source equirectangular panorama (with |
Here is a comparison between the two methods on a desktop with the GLES2 backend:
Comparing these two images with a diff tool, I don't see any difference between the two at all. |
@ForestKatsch The difference is quality. A huge difference in quality when using high frequency environment maps. Try the same comparison with the environment map from #33616. Although, thinking about it, GLES2 may not use an HDR panorama, so the impact may not be so severe. Please test with the environment map from #33616 and if it looks fine in both cases I am happy to remove the hack altogether. _Edit: _ to be clear, in your above example, you tested once with |
I think you're correct:
Yes. |
Well that settles it. Looks like our little hack isn't needed in GLES2. I'll test tonight when I get home from work before approving. In the meantime, you can remove the |
It's worth noting that this exact problem (no texture LOD support in GLES2) will cause issues elsewhere; notably, the wrong roughness will be used on planar or distant metallic surfaces (which should normally have a uniform roughness). This is visually very apparent. As this issue probably isn't easily solved (given the strict GLES2/GLES3 separation), isn't immediately apparent as a visual defect, and with Godot moving to Vulkan in the future, I don't plan on opening an issue for that. But it is a problem on any device that doesn't support texture LOD extensions. |
Yep. Could be useful to document in https://docs.godotengine.org/en/stable/tutorials/misc/gles2_gles3_differences.html which is becoming a catch all for GLES2 specific limitations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested out on my hardware and removing the cubemap hack works great. Since GLES2 always uses LDR, we don't need the extra smoothness that comes from resampling from lower radiance levels.
I also tested out without your changes to the texture2DLod, and I was correct before that those changes are unnecessary. So just remove those changes and this PR will be good to go!
Thanks for your hard work and your great sleuthing. It will be really nice to have this fixed.
Could you squash the commits into one? See PR workflow for instructions. |
The root cause of the issue is that OpenGL ES 2 does not support the `textureCubeLod` function. There are (optional) extensions to support this, but they don't appear to be exposed with the ES2 renderer (even though the hardware needed to support LOD features are certainly available.) The existing shim in `drivers/gles2/shaders/cubemap_filter.glsl` just creates a macro: ``` #define textureCubeLod(img, coord, lod) textureCube(img, coord) ``` But the third parameter of `textureCube` is actually a mip bias, not an absolute mip level. (And it doesn't seem to work regardless.) In this specific case, the `cubemap_filter` should only sample from the first level of the "source" panorama cubemap. In lieu of a method to force a lod level of zero, I've chosen to comment out the switchover from a 2D equirectangular panorama to the cubemap version of the same image, therefore always sampling roughness values from the 2D equirectangular panorama. This may cause additional artifacts or issues across the seam, but at least it prevents the glaringly obvious black areas. --- This same issue (no fragment texture LOD support) has rather large repercussions elsewhere too; it means materials with larger cubemap density (i.e. planar or distant objects) will be far rougher than expected. Since GLES 3 appears to properly support fragment `texture*Lod` functions, switching to the GLES 3 backend would solve this problem. --- Root cause discovered with help from @kaadmy.
Done! |
Thanks! |
The root cause of the issue is that OpenGL ES 2 does not support the
textureCubeLod
function.There are (optional) extensions to support this, but they don't appear to be exposed with the ES2 renderer (even though the hardware needed to support LOD features are certainly available.)
The existing shim in
drivers/gles2/shaders/cubemap_filter.glsl
just creates a macro:But the third parameter of
textureCube
is actually a mip bias, not an absolute mip level.(And it doesn't seem to work regardless.)
In this specific case, the
cubemap_filter
should only sample from the first level of the "source" panorama cubemap.In lieu of a method to force a lod level of zero, I've chosen to comment out the switchover from a 2D equirectangular panorama to the cubemap version of the same image, therefore always sampling roughness values from the 2D equirectangular panorama.
This may cause additional artifacts or issues across the seam, but at least it prevents the glaringly obvious black areas.
This same issue (no fragment texture LOD support) has rather large repercussions elsewhere too; it means materials with larger cubemap density (i.e. planar or distant objects) will be far rougher than expected.
Since GLES 3 appears to properly support fragment
texture*Lod
functions, switching to the GLES 3 backend would solve this problem.Root cause discovered with help from @kaadmy.
Bugsquad edit: Fix #43667