#version 430 core // Per-vertex attributes layout(location = 0) in vec3 aPosition; layout(location = 1) in vec3 aNormal; layout(location = 2) in vec2 aTexCoord; // Per-instance model matrix, split across four vec4 attribute slots. // A mat4 consumes 4 consecutive attribute locations, so locations 3-6 are // all occupied by this single logical matrix. The C# side must call // VertexAttribPointer four times (one per row) and VertexAttribDivisor(loc, 1) // on each of the four slots. layout(location = 3) in vec4 aInstanceRow0; layout(location = 4) in vec4 aInstanceRow1; layout(location = 5) in vec4 aInstanceRow2; layout(location = 6) in vec4 aInstanceRow3; uniform mat4 uViewProjection; uniform vec3 uLightDirection; // world-space light direction (points FROM sun, matching ACME) uniform float uAmbientIntensity; out vec2 vTex; out vec3 vWorldNormal; out float vLightingFactor; void main() { // Reconstruct the per-instance model matrix from its four row vectors. mat4 model = mat4(aInstanceRow0, aInstanceRow1, aInstanceRow2, aInstanceRow3); vec4 worldPos = model * vec4(aPosition, 1.0); gl_Position = uViewProjection * worldPos; // Transform normal into world space. vWorldNormal = normalize(mat3(model) * aNormal); vTex = aTexCoord; // Lambert + ambient matching ACME StaticObject.vert: // LightingFactor = max(dot(Normal, -uLightDirection), 0.0) + uAmbientIntensity; vLightingFactor = max(dot(vWorldNormal, -uLightDirection), 0.0) + uAmbientIntensity; }