Spatial Shader: render_mode world_vertex_coords Doesn't seem to put NORMAL in world space?

Godot Version

4.4

Question

I am making a theoretically VERY SIMPLE shader for terrain and am trying to have the VERTEX and NORMAL be in world space and in the documentation I see that render_mode world_vertex_coords does exactly this. However I am still seeing the color change as I rotate the view indicating that its not working in world space.
Has anyone that used render_mode world_vertex_coords had this issue, or am I doing something wrong when setting the render mode?
Also, I would prefer to use this render mode flag rather than do matrix transformations just for simplicity.

Thanks!

Here’s the code:

shader_type spatial;

render_mode world_vertex_coords; // Put VERTEX and NORMAL into WORLD SPACE

uniform sampler2D CliffGradient;
uniform sampler2D SurfaceGradient;

void fragment() {
	// Get the world position height of the fragment
	float height = VERTEX.y;
	
	// Create the UV Sampler and sample the gradient textures 
	// to get the color for the surface and cliff
	vec2 uv_coords = vec2(height, 0.0);
	vec4 cliff_color = texture(CliffGradient, uv_coords);
	vec4 surface_color = texture(SurfaceGradient, uv_coords);
	
	// Get the upwards alignment using NORMAL dot UP
	float upwards_alignment = dot(NORMAL, vec3(0.0, 1.0, 0.0));
	
	// Remap the output of the dot product to be in a 0-1 range
	upwards_alignment = (upwards_alignment + 1.0) / 2.0;
	
	// Mix the surface color and the cliff color using the alignment
	vec4 mixed_color = mix(cliff_color, surface_color, upwards_alignment);
	ALBEDO = mixed_color.xyz;
}

I might be very wrong with all of this, but from my understanding is fragment() always in view space, which means world_vertex_coords should only matter in vertex(). What you probably want to do then is, put all your code in vertex(), only the last line into fragment() and make mixed_color a varying to transfer the color.

shader_type spatial;

render_mode world_vertex_coords; // Put VERTEX and NORMAL into WORLD SPACE

uniform sampler2D CliffGradient;
uniform sampler2D SurfaceGradient;
varying vec4 mixed_color;

void vertex() {
	// Get the world position height of the fragment
	float height = VERTEX.y;
	
	// Create the UV Sampler and sample the gradient textures 
	// to get the color for the surface and cliff
	vec2 uv_coords = vec2(height, 0.0);
	vec4 cliff_color = texture(CliffGradient, uv_coords);
	vec4 surface_color = texture(SurfaceGradient, uv_coords);
	
	// Get the upwards alignment using NORMAL dot UP
	float upwards_alignment = dot(NORMAL, vec3(0.0, 1.0, 0.0));
	
	// Remap the output of the dot product to be in a 0-1 range
	upwards_alignment = (upwards_alignment + 1.0) / 2.0;
	
	// Mix the surface color and the cliff color using the alignment
	mixed_color = mix(cliff_color, surface_color, upwards_alignment);
}

void fragment() {
	ALBEDO = mixed_color.xyz;
}

Cool yea, this was definitely it- Wish it was more clear in the documentation though :sweat_smile:

I did need to normalize NORMAL because it gets scaled by the object’s scale which seems odd…

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.