Help understanding noise texture 2D used with the "as normal map" option

Godot Version

4.4.1-stable

Question

How do I use a NoiseTexture2D with 'as_normal_map' set, to set my normals in the fragment shader?

I’m currently using a noise texture 2d as a height map for some terrain I’m generating. It looks great.

I wanted to tackle normals for my terrain - I found this video online https://www.youtube.com/watch?v=-dMbacvrDrs that outlined the approach of duplicating your noise texture - with the duplicated one having the use as normal option enabled. I did this and followed through the video. I’m getting some convincing results, but it doesn’t quite feel right, and I have loads of questions:

Here’s the relevant code bits:

uniform sampler2D terrain_noise_normal_map_texture;

vec3 unpack_normalmap(vec4 rgba) {
	vec3 n = rgba.xyz * 2.0 - vec3(1.0);
	n.y *= -1.0;
	return n;
}

void fragment() {
	vec3 terrain_normal = normalize(unpack_normalmap(texture(terrain_noise_normal_map_texture, UV)));
	NORMAL = vec4(terrain_normal, 0.0).xyz; // This used to get multiplied by VIEW_MATRIX
}

Questions:

  1. Why the need to unpack the normal map? why isn’t it in a godot native format?
  2. How can I figure out the angle of the normal along the y-axis (positive-y being “height” for me) ? I had thought sampling the normal’s .y value would give me a 0->1.0 range of how far up the axis the normal is pointing, but this doesn’t look right
  3. The original video I linked above contained a multiplication like so: NORMAL = (VIEW_MATRIX * vec4(terrain_normal, 0.0)).xyz;, however this seemed to cause the normals to change as my camera tilted up/down. Removing that multiplication removed this effect

one you should enable the as normal in the noise texture, two your noise texture size should match the vertex count to make the noise pixel one-to-one with the vertexes. Three in your vertex function you should set the normal there, and this should carry over into the fragment shader. (which you probably don’t need anymore)

1 Like

Hey thanks for the reply.

I’m following through the advice - I’m setting the NORMAL in the vertex shader as you suggested:

NORMAL = texture(terrain_noise_normal_map_texture, UV).rgb;

and I’ve removed all references to NORMAL in my fragment shader. This results in no normals existing (no shadows being cast, surface looks flat) - any ideas?

okay, I thought about it some more, and I guess noise as normal maps won’t work out like i thought. Basically the noise textures don’t work the way i thought and will require you to sample 3 points to determine the normal. here is an old tutorial.

also if you are bump mapping then you can apply to the NORMAL_MAP in the fragment shader. see reference

	NORMAL_MAP = texture(texture_normal, base_uv).xyz ;

ah I think you just need to move your normal stuff in to the a vertex shader.

uniform sampler2D ter_noise;
uniform sampler2D ter_normal;
void vertex() {
	vec3 noise_tex = texture(ter_noise, UV).xyz;
	vec3 normal_tex = (texture(ter_normal, UV).xzy * 2.0 - vec3(1.0)) * vec3(1.0,1.0,-1.0);

	NORMAL = normalize(normal_tex);
	VERTEX += noise_tex.y ;
}



The more i play around with this the less it seems accurate.