#version 450 core layout(quads, fractional_even_spacing, cw) in; layout(binding = 0) uniform sampler2D heightTexture; layout(location = 0) uniform mat4 M; uniform float displacementScale = 0.025f; uniform float tessellationFactor; layout(std140, binding = 0) uniform SceneUniforms { mat4 PV; //camera projection * view matrix vec4 eye_w; //world-space eye position }; in TC_OUT { vec3 position; vec2 texCoord; } te_in[]; out TE_OUT { vec3 position; vec2 texCoord; vec3 normal; } te_out; float getHeight(vec2 uv) { return texture(heightTexture, uv).r * displacementScale; } vec3 calculateSmoothNormal(vec3 pos, vec2 coord) { float step = 1.0f / (16.0f * tessellationFactor + 1.0f); float hLeft = getHeight(coord + vec2(-step, 0.0f)); float hRight = getHeight(coord + vec2(step, 0.0f)); float hUp = getHeight(coord + vec2(0.0f, step)); float hDown = getHeight(coord + vec2(0.0f, -step)); vec3 tangentX = normalize(vec3(step, hRight - hLeft, 0.0)); vec3 tangentY = normalize(vec3(0.0, hUp - hDown, step)); return normalize(cross(tangentY, tangentX)); } void main() { // Interpolate texture coordinates vec2 texCoord = mix( mix(te_in[0].texCoord, te_in[1].texCoord, gl_TessCoord[0]), mix(te_in[3].texCoord, te_in[2].texCoord, gl_TessCoord[0]), gl_TessCoord[1] ); // Interpolate the original position vec3 position = mix( mix(te_in[0].position, te_in[1].position, gl_TessCoord[0]), mix(te_in[3].position, te_in[2].position, gl_TessCoord[0]), gl_TessCoord[1] ); position.z += texture(heightTexture, texCoord).r * displacementScale; te_out.position = (M*vec4(position, 1.0f)).xyz; // Position in world-space te_out.texCoord = texCoord; te_out.normal = calculateSmoothNormal(position, texCoord); gl_Position = PV*M*vec4(position, 1.0f); // Position in screen-space }