#version 450 core layout(quads, fractional_even_spacing, cw) in; layout(binding = 0) uniform sampler2D heightTexture; layout(std140, binding = 4) uniform GeoUniforms { mat4 PV; mat4 M; float minTessellation; float maxTessellation; float displacementScale; int gridDensity; }; in TC_OUT { vec3 position; vec2 texCoord; float tessLevel; } te_in[]; out TE_OUT { vec3 position; vec2 texCoord; vec3 normal; } te_out; float getHeight(vec2 uv) { return texture(heightTexture, uv).r * displacementScale; } float getNeighbor(float tessFactor) { return (float(gridDensity) * tessFactor + 1.0f); } vec3 calculateSmoothNormal(vec3 pos, vec2 coord) { // Currently hardcoded to match patch density //float step = 1.0f / (float(gridDensity) * tessLevel + 1.0f); float stepU = 1.0f / (float(gridDensity) * gl_TessLevelInner[0]); float stepV = 1.0f / (float(gridDensity) * gl_TessLevelInner[1]); // Find surrounding heights float hLeft = getHeight(coord + vec2(-stepU, 0.0f)); float hRight = getHeight(coord + vec2(stepU, 0.0f)); float hUp = getHeight(coord + vec2(0.0f, stepV)); float hDown = getHeight(coord + vec2(0.0f, -stepV)); // Calculate tangents vec3 tangentX = normalize(vec3(stepU, hRight - hLeft, 0.0)); vec3 tangentY = normalize(vec3(0.0, hUp - hDown, stepV)); 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 }