#version 450 layout(location = 0) in vec3 frag_color; layout(location = 1) in vec3 frag_normal; layout(location = 2) in float frag_debug_tint; layout(location = 0) out vec4 out_color; // Direction the light travels, pointing downward and across both horizontal axes so that no cubic face orientation receives exactly the same amount of light as another. A light aligned with an axis would leave two of the three visible faces of a cube indistinguishable. const vec3 LIGHT_DIRECTION = vec3(-0.4, -1.0, -0.3); // Fraction of the albedo retained by a fully unlit face, standing in for bounced light until a global-illumination term exists. Without it, faces turned away from the light collapse to black and their silhouettes disappear against one another. const float AMBIENT = 0.25; // Colour applied to debug raster passes, chosen to contrast with terrain and to remain legible when overlaid on filled geometry. const vec3 DEBUG_COLOR = vec3(1.0, 0.0, 1.0); void main() { // The interpolated normal is renormalised: the six face normals are unit length and constant across a quad, but interpolation across a triangle is not guaranteed to preserve that. vec3 normal = normalize(frag_normal); // Lambertian term. The light vector is negated because LIGHT_DIRECTION points along the light's travel, whereas the dot product requires the direction from the surface toward the light. The clamp discards the negative half, where the face points away from the light. float diffuse = max(dot(normal, normalize(-LIGHT_DIRECTION)), 0.0); vec3 lit = frag_color * (AMBIENT + (1.0 - AMBIENT) * diffuse); // The debug tint is applied after shading so debug passes draw flat and stay legible over the shaded geometry beneath them. out_color = vec4(mix(lit, DEBUG_COLOR, frag_debug_tint), 1.0); }