#version 400
#extension GL_EXT_texture_array : enable
layout(quads, fractional_even_spacing, cw) in;
in terrainVertex
{
vec2 position;
} In[];
out worldVertex
{
vec4 worldPosition;
vec3 worldNormal;
vec4 position;
vec3 normal;
vec2 texCoords;
} Out;
uniform sampler2DArray heightMap;
// The number of triangles created per height-map texel
uniform int maxTrianglesPerTexel = 10;
// Distance between each tessellation point at max tess level
uniform float horizontalScale = 10.0;
// Transformation matrices
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 worldNormalMatrix;
uniform mat3 normalMatrix;
uniform mat4 mvp;
const float maxTessLevel = 64.0;
void main()
{
// Calculate extent of this patch in texture coords [0,1]
vec2 patchExtent = maxTessLevel / (textureSize(heightMap, 0).xy * maxTrianglesPerTexel); // -- modified
// Calculate the texture coordinates
Out.texCoords = In[0].position.xy + gl_TessCoord.xy * patchExtent;
// Calculate the model-space position
vec4 position;
position.xz = Out.texCoords * horizontalScale;
position.y = texture(heightMap, vec3(Out.texCoords, 0)).r; // -- modified
position.w = 1.0;
// Transform the position to world coordinates and to eye space
Out.worldPosition = modelMatrix * position;
Out.position = modelViewMatrix * position;
// Calculate the normal
// This could be moved to a one-time pre-process step to create a normal map.
// This would be a good candidate for a compute shader.
// For deformable terrain, would need re-generating when terrain is modified
const ivec3 offset = ivec3(-1, 0, 1); // Texel offsets
float delta = 2.0 * horizontalScale / textureSize(heightMap, 0).x; // Horizontal displacement in world coords
float left = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.xy).r; // -- modified
float right = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.zy).r; // -- modified
float top = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.yz).r; // -- modified
float bottom = textureOffset(heightMap, vec3(Out.texCoords, 0), offset.yx).r; // -- modified
vec3 x = normalize(vec3(delta, right - left, 0.0));
vec3 z = normalize(vec3(0.0, top - bottom, delta));
vec3 n = cross(z, x);
Out.worldNormal = worldNormalMatrix * n;
Out.normal = normalMatrix * n;
// Transform to clip-space
gl_Position = mvp * position;
}