layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec3 aColor; uniform mat4 model; // rotation + translation only uniform mat4 view; uniform mat4 projection; uniform mat4 lightSpaceMatrix; uniform float boilTime; uniform float terrainSize; // > 0 only while drawing the terrain uniform float grassDepth; uniform float decalSize; // > 0 for things lying on the ground: they sink with it uniform float grass; // > 0 while drawing grass blades (terrain size); aNormal.y = height above the ground uniform sampler2D wearMap; // 0 = meadow, 1 = trampled path uniform sampler2D waterMap; // soil moisture, standing water, pee, mud (world/wetness.h) out vec3 WorldPos; out vec3 Normal; out vec3 ViewNormal; out vec3 Albedo; out vec4 LightSpacePos; out float ViewDepth; out float Wear; out vec4 Wet; // grass blades: the wet ground they stand in const float SHADOW_NORMAL_OFFSET = 0.06; // avoids self-shadowing acne const float DECAL_BIAS = 0.02; // decals are drawn this much towards the eye ... const float DECAL_BIAS_SLOPE = 0.004; // ... plus this per meter away, so the wobbling // ground never pokes through them void main() { vec3 world = vec3(model * vec4(aPos, 1.0)); // Trampled grass sinks a little Wear = 0.0; if (terrainSize > 0.0) { Wear = texture(wearMap, world.xz / terrainSize + 0.5).r; world.y -= Wear * grassDepth; } else if (decalSize > 0.0) { world.y -= texture(wearMap, world.xz / decalSize + 0.5).r * grassDepth; } vec3 normal = aNormal; Wet = vec4(0.0); if (grass > 0.0) { // Blades stand on the ground and sink with it; trampled ones (and in mud) lie flat; tips sway float h = aNormal.y; Wear = texture(wearMap, world.xz / grass + 0.5).r; Wet = texture(waterMap, world.xz / grass + 0.5); world.y -= Wear * grassDepth + h * smoothstep(0.08, 0.5, max(Wear, Wet.a)) * 0.9; world.xz += h * vec2(sin(boilTime * 1.7 + world.x * 0.35 + world.z * 0.2), cos(boilTime * 1.3 + world.z * 0.35)) * 0.1; normal = vec3(0.0, 1.0, 0.0); } world += wobble(world, boilTime); Normal = normalize(mat3(model) * normal); ViewNormal = mat3(view) * Normal; WorldPos = world; Albedo = aColor; LightSpacePos = lightSpaceMatrix * vec4(world + Normal * SHADOW_NORMAL_OFFSET, 1.0); vec4 viewPos = view * vec4(world, 1.0); ViewDepth = -viewPos.z; if (decalSize > 0.0) { // along the view ray: same spot on screen, just in front float d = max(length(viewPos.xyz), 1e-3); viewPos.xyz *= max(1.0 - (DECAL_BIAS + DECAL_BIAS_SLOPE * d) / d, 0.05); } gl_Position = projection * viewPos; }