Open BenjaminNavarro opened 2 years ago
From a quick look, you will need to change your depth calculation. In Vulkan you do not scale to the -1 to 1 range, so this:
float depth = texture(DEPTH_TEXTURE, SCREEN_UV).r;
depth = depth * 2.0 - 1.0;
depth = PROJECTION_MATRIX[3][2] / (depth + PROJECTION_MATRIX[2][2]);
depth = depth + VERTEX.z;
becomes this:
float depth = texture(DEPTH_TEXTURE, SCREEN_UV).r;
depth = PROJECTION_MATRIX[3][2] / (depth + PROJECTION_MATRIX[2][2]);
depth = depth + VERTEX.z;
For me information see: https://docs.godotengine.org/en/latest/tutorials/shaders/advanced_postprocessing.html#depth-texture
Thanks @clayjohn, I didn't know about this difference between OpenGL and Vulkan. I made the change you suggested, it improved the situation but the result is still quite different from the GLES3 version. Here are the two versions again for comparison:
GLES3:
Vulkan:
We can even see in the inspector pane how the two shaders look different even though their settings are the same. Would it be another thing handled differently between OpenGL and Vulkan? Or something more on the Godot side of things?
I attach the updated 4.0 project LowPolyWaterShader_4_0_v2.zip
The different water color looks like a sRGB/linear color conversion issue.
I have a simpler case with similar results.
On Godot v3.4 with GLES3 it looks like this:
shader_type canvas_item;
uniform vec4 color : hint_color;
void fragment() {
COLOR = color;
}
On Godot 4.0-alpha13 with Vulkan it looks like this:
shader_type canvas_item;
uniform vec4 color : source_color;
void fragment() {
COLOR = color;
}
Definitely looks like a sRGB/linear color conversion issue, probably from the uniform
, because with the following shader code the color looks correct even on Godot 4.0-alpha13.
shader_type canvas_item;
void fragment() {
COLOR = vec4(0., .7, 1., 1.);
}
Here are some slow, medium, and fast linear/srgb conversions for you. Accuracy is inversely correlated to speed. See if these will fix your color issues.
vec4 toLinearFast(vec4 col) {
return vec4(col.rgb*col.rgb, col.a);
}
vec4 toSRGBFast(vec4 col) {
return vec4(sqrt(col.rgb), col.a);
}
vec4 toLinearMed(vec4 col) {
return vec4(pow(col.rgb, vec3(2.2)), col.a);
}
vec4 toSRGBMed(vec4 col) {
return vec4(pow(col.rgb, vec3(.4545)), col.a);
}
vec4 toLinearSlow(vec4 col) {
bvec4 cutoff = lessThan(col, vec4(0.04045));
vec4 higher = vec4(pow((col.rgb + vec3(0.055))/vec3(1.055), vec3(2.4)), col.a);
vec4 lower = vec4(col.rgb/vec3(12.92), col.a);
return mix(higher, lower, cutoff);
}
vec4 toSRGBSlow(vec4 col) {
bvec4 cutoff = lessThan(col, vec4(0.0031308));
vec4 higher = vec4(vec3(1.055)*pow(col.rgb, vec3(1.0/2.4)) - vec3(0.055), col.a);
vec4 lower = vec4(col.rgb * vec3(12.92), col.a);
return mix(higher, lower, cutoff);
}
Ok so it seems that converting the color uniform parameter to sRGB gives the proper color. It makes the color consistent between setting it from the inspector and hardcoding it in the shader as well as giving the same color as with 3.x.
So doing this conversion internally would solve the color issue and @bruce965 problem but on my side there is more to it. The water tint changes a little but it still looks very different.
After some testing I realized that in 4.0 the water color is unaffected by the DirectionalLight
, toggling it on and off only changes the other objects color (white vs gray) while doing the same thing with 3.x has a clear impact on both the water and the objects.
Also, with 4.0, bumping the ground energy in the ProceduralSkyMaterial
to ~50 gives the water a very similar look as with 3.x, but now the other objects are way too bright. But doing the same in 3.x doesn't change the water color, it only gives it brighter reflections.
Finally, I replaced the water mesh+shader by a simple MeshInstance3D
with a StandardMaterial3D
with the same color and roughly the same transparency and now the "water" plane looks and behave as expected.
So there seems to be something wrong regarding the lighting of objects with custom shaders as materials...
Just for info, I just tested with the current master branch (dc4b616596) and the issue is still there
Ok so I found a fix but I don't know if it's an expected change in behavior between GLES3 and Vulkan or a bug.
In my fragment shader I had the following line:
NORMAL = normalize(cross(dFdx(VERTEX), dFdy(VERTEX)));
But if I negate the result of the normalize
function I get the lighting to work properly and a very similar look between GLES3 and Vulkan:
NORMAL = -normalize(cross(dFdx(VERTEX), dFdy(VERTEX)));
So either there is a problem in the output sign of one of the function involved or normals have opposite signs between the 2 renderers.
Would you guys have any idea of which is more likely ?
Godot version
4.0 dev (e44a2f1680)
System information
Linux, RTX3080, NVIDIA drivers
Issue description
While porting my game prototype from 3.4 to 4.0 I noticed that the water shader I was using looks different.
The shader originaly comes from this video, but I made some small modifications to it (see attached projects).
Here is what the sample project on 3.4 gives:
And the same with 4.0:
I tried to match the environments as much as possible. All the shader parameters are the same in both versions.
To me there are two things wrong here:
Here is the shader code (4.0 version but only the color hint is different):
Steps to reproduce
See attached projects for reproduction
Minimal reproduction project
LowPolyWaterShader_3_4.zip
LowPolyWaterShader_4_0.zip