feat(app): render landblock with height-ramp shader + orbit camera

Adds a 2-stage GLSL shader (vertex + fragment), a Shader helper that
compiles/links and exposes SetMatrix4 for uniforms, and an OrbitCamera
with yaw/pitch/distance and a 192-unit-centered target for a single
landblock. TerrainRenderer now takes a Shader and issues an actual
DrawElements call with uView + uProjection uniforms. GameWindow owns
the Shader and Camera, routes mouse drag to camera yaw/pitch, and
scroll wheel to camera distance.

The fragment shader maps world Z to a green-brown-white ramp so
lowlands read green, midlands brown, and peaks white — no textures
yet, but enough to visually confirm the terrain shape.

Shaders are copied to the output dir via a <None Update> item group.

Smoke verified against real dats: process stays alive with no GL
errors, no shader compile/link failures, and no exception trail.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-10 16:44:08 +02:00
parent 8356fe65a0
commit 87c45c70ac
7 changed files with 154 additions and 7 deletions

View file

@ -0,0 +1,14 @@
#version 430 core
in float vHeight;
out vec4 fragColor;
void main() {
float t = clamp(vHeight / 200.0, 0.0, 1.0);
vec3 low = vec3(0.10, 0.35, 0.15); // green lowland
vec3 mid = vec3(0.55, 0.45, 0.25); // brown mid
vec3 high = vec3(0.90, 0.90, 0.95); // snowy peak
vec3 color = t < 0.5
? mix(low, mid, t * 2.0)
: mix(mid, high, (t - 0.5) * 2.0);
fragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,14 @@
#version 430 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTex;
uniform mat4 uView;
uniform mat4 uProjection;
out float vHeight;
void main() {
vHeight = aPos.z;
gl_Position = uProjection * uView * vec4(aPos, 1.0);
}