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

Allow using nearest-neighbor filtering when sampling DEPTH_TEXTURE #6025

Closed
ClemensOlivae opened this issue Dec 30, 2022 · 4 comments
Closed

Comments

@ClemensOlivae
Copy link

Describe the project you are working on

I've been looking at many ocean/water shaders made by the community and all of them run into the same problem, caused by the DEPTH_TEXTURE. An exemple of it can be seen here.
godot_depth

Describe the problem or limitation you are having in your project

I'll try to explain it here:

You're coding a water shader with refraction.
When you sample the SCREEN_TEXTURE at (SCREEN_UV + an offset), you get a distorted SCREEN_TEXTURE that you can use for your refraction.
But there is one issue : since SCREEN_TEXTURE is a render of the whole screen, you also sample objects that are above the water level. This makes your shader unreadable/unrealistic.

So you must avoid rendering the objects that are above water.
The classic way to do it, as seen here (https://alextardif.com/Water.html) and many other tutorials, is to sample the DEPTH_TEXTURE where the refracted pixel should be, at (SCREEN_UV + an offset). Then you convert the depth at this coordinate to a world position. If the position is above water, you turn off refraction to avoid rendering it. The link above explains it with code, not in Godot but the language is similar.

However in Godot since DEPTH_TEXTURE is antialiased, you get at the edges of objects a value that is part the depth of the object, and part the depth of the object behind it. It messes with the result you're trying to achieve.

There are solutions to mitigate this problem, like checking multiple pixels around the target refracted pixel, but none of them work perfectly.
I've downloaded and tested most of the water shaders available on Godot shaders, Github etc, and if some of them almost get it right, they all get broken in edge cases, or show some kind of flickering pixels.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The solution to this is to either entirely disable the DEPTH_TEXTURE antialiasing, or to enable sampling it unaliased. This way it would work similarly to other engines.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Something like textureDepth(vec2 UV, bool antialiased), or disabling antialiasing.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No, the only way to bypass this issue right now would require using a viewport used as a buffer with the whole scene copied, which would be very detrimental to performance.

Is there a reason why this should be core and not an add-on in the asset library?

I put this in proposals but it may be considered an issue and relevant to the engine's core.

@Calinou
Copy link
Member

Calinou commented Dec 30, 2022

There is no antialiasing being performed on the depth texture if MSAA is disabled (or if using FXAA/TAA only). If MSAA is enabled, it's likely a different story though.

That said, aren't you referring to bilinear filtering here instead? In Godot 4, sampling state (filter/repeat) is set on the sampler, rather than on image files. Uniforms can have their filter mode set via property hints, but there's way to define those for SCREEN_TEXTURE or DEPTH_TEXTURE yet. I assume this would have to be done on a per-shader basis using a top-level hint, or even a project setting to adjust this globally. See also #4697.

@ClemensOlivae
Copy link
Author

Yes that must be bilinear filtering, sorry. I have seen the term antialiasing used by people describing the same issue but this makes more sense.
I agree with you, even adjusting it as a project setting with SCREEN_TEXTURE would be good (and simpler).

@Calinou Calinou changed the title Remove or make the antialiasing of the DEPTH_DEPTURE toggable Allow using nearest-neighbor filtering when sampling DEPTH_TEXTURE Dec 30, 2022
@reduz
Copy link
Member

reduz commented Jan 1, 2023

This is already the case in Godot 4, by the way. You can chose the sampler type.

@ClemensOlivae
Copy link
Author

Thanks, that's a great feature.
Closing the proposal and leaving this here in case someone encounters the same issues:

Using the bias argument of the texture function : sample the base depth and the refracted depth with something like this:
float depth= texture(DEPTH_TEXTURE, ref_uv or SCREEN_UV, -10.0).r;
Check the world position of the refracted pixel to know if it's above water (method shown in the OP).
Sample around the target refracted pixel to improve the detection(costly but necessary).
And don't forget to use bias on the SCREEN_TEXTURE too!
albedo = texture(SCREEN_TEXTURE, ref ? ref_uv : SCREEN_UV, -10.0).rgb

The result I get is near-perfect and way way better than before :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants