Shader not working with Compatibility rendering method

Godot Version

4.2.2

Question

I’m trying to port this shader to Godot 4 for my shader collection. I’ve got it working just fine with Forward+, but the shadow color breaks in Compatibility. Is there some difference between the two I’m missing? I am aware that Forward+ uses Vulkan and Compatibility uses OpenGL. What do I need to change to accommodate OpenGL?

Here’s a comparison. The left side was rendered with Compatibility. It should look the same as the gem on the right, which was rendered with Forward+.

Comparison

Here’s the code. I’ve removed the vertex snapping since I know that’s not causing the issue.

shader_type spatial;
render_mode
#if defined(ALPHA_BLEND)
	depth_draw_always,
#else
	depth_draw_opaque,
#endif
	diffuse_lambert_wrap,
	vertex_lighting,
	specular_disabled,
	shadows_disabled;

#if defined(ALPHA_BLEND)
uniform vec4 albedo_color : source_color = vec4(1.0);
#else
uniform vec3 albedo_color : source_color = vec3(1.0);
#endif

uniform float color_depth : hint_range(16, 64, 16) = 16;
uniform float glossiness : hint_range(0, 1, 0.05) = 0.4;
uniform float shadow_intensity : hint_range(0, 1, 0.05) = 0.65;

vec3 glimmer(vec3 input)
{
	float grayscale = max(vec3(input).r, max(vec3(input).g, vec3(input).b));
	float lower = floor(grayscale * color_depth) / color_depth;
	float lower_difference = abs(grayscale - lower);
	float upper = ceil(grayscale * color_depth) / color_depth;
	float upper_difference = abs(upper - grayscale);
	float level = lower_difference <= upper_difference ? lower : upper;
	float adjustment = level / grayscale;
	return input * adjustment;
}

void fragment()
{
	vec3 light_dir = vec3(0.500000, 0.250000, 1.000000);
	float light_dot = dot(light_dir, NORMAL);
	vec3 brightness = glimmer(vec3(pow(light_dot, 10.0)));
	brightness = clamp(brightness * vec3(glossiness), vec3(0.00000), vec3(1.00000));
	vec3 shadow_dir = vec3(-light_dir.x, -light_dir.y, light_dir.z);
	float dark_dot = dot(NORMAL, shadow_dir);
	vec3 darkness = glimmer(vec3(dark_dot));

	ALBEDO =
		albedo_color.rgb +
		brightness +
		clamp(darkness, vec3(0.00000), vec3(1.00000)) * vec3(-shadow_intensity);

#if defined(ALPHA_BLEND)
	ALPHA = albedo_color.a;
#endif
}

maybe try it on godot 4.1.4? i had problem too with shader breaking on 4.2+ gl_compatibility, that it should be fine on godot 4.1.4 compatibility/mobile/forward+

Getting the same issue with that version.

then there’s no fixes… or it is, you might want to try the latest 4.3 dev6 if it actually fix this
the whole shader gl_compatibility vs not’s difference on build is really frustrating. you expect it to show the same shader effect, but it may differ on gl_compatibility

Tried that too, same issue. It just might be that this effect can’t work properly on Compatibility, but I’m still not sure. I feel like there’s something I could change with the code, but I honestly don’t know what that would be.

for me and in my opinion, the code should stay the same, and different renderer should display the same effect. it’s just feel not right to make different shader just for different renderer

There is definitely a difference with the same code, what caught my eye though was the ALBEDO input with the -shadow_intensity, and clamping the whole thing instead of just the darkness seemed to make it match:

	ALBEDO =
		clamp(albedo_color.rgb +
		brightness +
		darkness * vec3(-shadow_intensity), .0, 1.);

not sure why though?

2 Likes

Probably is the same problem from this post, take a look an try the solution here if works: How to minimize the visual difference between rendering backends? - Help - Godot Forum (godotengine.org)

1 Like

Well, this solved it, so I’m marking this as the solution. Thank you!

I did open an issue on the Godot GitHub repo, maybe one of the maintainers will have a better idea why this is the case.

2 Likes