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

depth texture gets distorted at different angles or distance from the camera #77798

Closed
Ivanfs8 opened this issue Jun 3, 2023 · 3 comments
Closed
Labels

Comments

@Ivanfs8
Copy link

Ivanfs8 commented Jun 3, 2023

Godot version

4.0.3

System information

Windows 10

Issue description

Sorry in advance if this is a misunderstanding, but I haven't found a solution anywhere.
I tried to use the depth texture for edge detection in a water shader. It doesn't stay consistent, wherever I put the camera it will get distorted or curved, specially when doing a close up. Made sure to use the correct linear depth function, it's the same one on all shaders I could find. In fact, I'm using the one from the proximity fade node in the visual shader.

shader_type spatial;
render_mode shadows_disabled;

uniform sampler2D DEPTH_TEXTURE: hint_depth_texture;

uniform vec3 water_color: source_color;
uniform vec3 edge_color: source_color = vec3(1.0);
uniform float edge_dis = 1.0;

void fragment() {
	float depth = texture(DEPTH_TEXTURE, SCREEN_UV,0.0).r;
	
	vec4 view = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth, 1.0);
	view.xyz /= view.w;
	float prox = clamp(1.0 - smoothstep(view.z + edge_dis, view.z, VERTEX.z), 0.0, 1.0);
	
	float blend = clamp(prox / edge_dis, 0.0, 1.0);
	
	ALBEDO = mix(edge_color, water_color, blend);
}

From a distance seems fine:
image

However, on close up it starts to distort:
image

To be honest I didn't really mind it, until I tested a beach:
image
image

That second angle is pretty common in a playable scene I have, it's painfully obvious so I can't use it.

I'm not really sure if this is just a side effect of the function or a bug, but at this point I tried every single water shader I could find and all have the same issue.

StayAtHomeDev uses another method: https://www.youtube.com/watch?v=7L6ZUYj1hs8

shader_type spatial;
render_mode shadows_disabled;

uniform sampler2D DEPTH_TEXTURE: hint_depth_texture;

uniform vec3 water_color: source_color;
uniform vec3 edge_color: source_color = vec3(1.0);
uniform float edge_dis = 1.0;

uniform float near = 1.0;
uniform float far = 100.0;

float edge(float depth){
	depth = 2.0 * depth - 1.0;
	return near * far / (far + depth * (near - far));
}

void fragment() {
	float depth_tex = texture(DEPTH_TEXTURE, SCREEN_UV,0.0).r;
	
	float z_depth = edge(depth_tex);
	float z_pos = edge(FRAGCOORD.z);
	float z_dif = z_depth - z_pos;
	
	float blend = step(edge_dis, z_dif);
	ALBEDO = mix(edge_color, water_color, blend);
}

But produces the same issue:
image

This this is the regular linear depth (-view.z+VERTEX.z):
image
image
Same thing. Also tried float depth = texture(DEPTH_TEXTURE, FRAGCOORD.xy / VIEWPORT_SIZE).r; with the same results

Is this an issue with the depth texture or am I misunderstanding how to use it?

Steps to reproduce

  1. Add a plane with one of the shaders in a 3D scene
  2. Add another plane, rotate it slightly and intersect it with the first plane
  3. Move the camera at different angles and distances

Minimal reproduction project

min_water.zip

@Lielay9
Copy link
Contributor

Lielay9 commented Jun 3, 2023

What the shaders are currently measuring and the reason the value differs:

Water

The thing you'd ideally want to measure, distance to the nearest shore, is not unfortunately possible to calculate in Godot* (*for static objects and surface the data could be baked to the water mesh). To do that you'd need distance fields such as those in Unreal Engine.

If you want something that looks okay-ish you could measure the distance of the depthtexture to the surface:

shader_type spatial;

uniform sampler2D depth_texture: hint_depth_texture;
uniform vec3 water_color: source_color;
uniform vec3 edge_color: source_color = vec3(1.0);
uniform float edge_dis = 0.1;

void fragment() {
	float depth = texture(depth_texture, SCREEN_UV).x;
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	float depth_texture_y = world.y / world.w;
	float vertex_y = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).y;
	float blend = clamp((vertex_y - depth_texture_y) / edge_dis, 0.0, 1.0);
	ALBEDO = mix(edge_color, water_color, blend);
}
Water

This obviously doesn't work behind objects, no ripples etc. but if you were happy with the results of the shaders you were using (bar the perspective skew) then this might be passable.

@Lielay9
Copy link
Contributor

Lielay9 commented Jun 3, 2023

In short, not a bug, can be closed. If you feel like Godot could use better foam (distance fields), you can give thumbs up to this proposal: godotengine/godot-proposals#5984.

@Ivanfs8
Copy link
Author

Ivanfs8 commented Jun 3, 2023

In short, not a bug, can be closed. If you feel like Godot could use better foam (distance fields), you can give thumbs up to this proposal: godotengine/godot-proposals#5984.

Yeah today I tried the same effect with Unreal and had the same distortion, so it's not an issue. Was actually gonna see if SDF were supported because people in Unreal forums came to the same conclusion. I'll try your solution and see what I can do.

Thank you very much! this was driving me crazy

@Ivanfs8 Ivanfs8 closed this as completed Jun 3, 2023
crealol2 added a commit to pnutball/GalacticKatamari that referenced this issue Feb 14, 2024
The distortion on the water's edge has been eliminated.

Credit to Lielay9 for some of the shader code (godotengine/godot#77798 (comment))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants