[Help] Creating Terrain Normals in Procedural Tessellated Terrain

Started by
-1 comments, last by JTomas 8 years, 1 month ago

Hi everyone, I am creating a procedural terrain generator with tessellation. I have already managed to create the plane of the terrain (32 instances of a quad) and they also get tessellated through the tessellation shader. Each vertex of my procedural terrain reads from a texture I send to the gpu to know the height at which the vertex must be. Until here everything was going ok but now I wish I could have normals in my terrain so as to see better the terrain. I am aware that a normal is a vector of 3 components perpendicular to the the surface of the terrain. What I have tried until now is to get the position of the next vertrex in the X axis and the next vertex in the Z axis, then I use the cross product of the substraction of these to with the original point and this is my normal. Bellow some code:

in TEES_CONTROL_SHADER_OUTPUT

{
vec2 texture_coords;
vec2 tessInnerLevel;
} tees_eval_shader_input[];
out TEES_EVAL_SHADER_OUTPUT
{
vec2 texture_coords;
float terrain_height;
vec3 normal;
} tees_eval_shader_output;
vec2 Get_TexCoords(float x, float z){
vec2 texcoords1 = mix(tees_eval_shader_input[0].texture_coords, tees_eval_shader_input[1].texture_coords, gl_TessCoord.x + x);
vec2 texcoords2 = mix(tees_eval_shader_input[2].texture_coords, tees_eval_shader_input[3].texture_coords, gl_TessCoord.x + x);
vec2 tc = mix(texcoords2, texcoords1, gl_TessCoord.y + z);
return tc;
}
vec4 Get_Position(float x, float z){
vec4 point1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x + x);
vec4 point2 = mix(gl_in[2].gl_Position, gl_in[3].gl_Position, gl_TessCoord.x + x);
vec4 point_ = mix(point2, point1, gl_TessCoord.y + z);
return point_;
}
vec4 GetPoint(float x, float z){
vec4 position = Get_Position(x, z);
float terrain = texture2D(heightmap, Get_TexCoords(x, z)).x;
terrain = (terrain + 1.0f) / 2.0f;
tees_eval_shader_output.terrain_height = terrain;
terrain *= 8;
position.y += terrain;
return position;
}
void main(void)
{
vec2 triangleSize = 1.0f / tees_eval_shader_input[0].tessInnerLevel;
vec4 position_x = GetPoint(triangleSize.x, 0);
vec4 position_z = GetPoint(0, triangleSize.y);
vec4 position = GetPoint(0, 0);
tees_eval_shader_output.normal = normalize(cross(position_z.xyz - position.xyz, position_x.xyz - position.xyz));
gl_Position = mvp * position;
tees_eval_shader_output.texture_coords = Get_TexCoords(0, 0);
}
Later these normals are sent to my fragment shader and are only used in this line:
vec3 light = vec3(0.5f, -1.0f, 0.5f);
output_color = output_color * dot(normalize(light), normalize(fragment_shader_input.normal));
The output_color is set above these lines of code but Im sure im not doing anything wrong there as it just sets the output_color to plain colors.
The result of this is the next image:
D6xPTSE.png
I am pretty sure this is not right, the fragment shader does make darker the zones that arent looking at the light but i have a strange pattern that appears. It is as if the edges of each tessellated quad got darked than the diagonal that crosses them. If anybody has seen this before or understands what it is that I am doing wrong please help me. I want to also mention that my terrain is actually 32*32 instances of a quad which is 1.0f*1.0f big. This is also my first time sharing my code with people in Internet, if you see any horrible codding or something a programmer should never do, please pardon me.
Jorge Tomas

This topic is closed to new replies.

Advertisement