17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-31 03:09:58 +01:00

feat(terrain): grass follows the seasons and fades out over gfx.grass.fadedistance

This commit is contained in:
2026-10-20 02:20:03 +02:00
parent ceb439b218
commit 07ac7406a0
13 changed files with 129 additions and 28 deletions

View File

@@ -18,7 +18,8 @@ uniform vec4 grass_part;
uniform vec4 grass_chunk;
// the camera relative to the corner of the chunk (y as it is)
uniform vec4 grass_camera;
// x: distance the grass starts to thin out at; y: reach of the grass
// x: distance the grass starts to thin out at, for speed; y: distance the fading starts at (gfx.grass.distance); z: where the
// grass ends (gfx.grass.fadedistance)
uniform vec4 grass_lod;
// x, y: direction of the wind (x, z of the world); z: its strength, 0..1; w: time, seconds
uniform vec4 grass_wind;
@@ -28,6 +29,10 @@ uniform vec4 grass_tip[4];
uniform vec4 grass_shape[4];
// share of the blades of each kind against the densest one of the chunk
uniform vec4 grass_share;
// the colour of each kind dried out (linear rgb), and how much it follows the seasons
uniform vec4 grass_dry[4];
// the time of the year: x: how dry the grass is, y: how fresh (spring), z: how grown (share of the height)
uniform vec4 grass_season;
layout(binding = 0) uniform sampler2D grass_heights; // heights of the grid points, R32F
layout(binding = 1) uniform sampler2D grass_density; // densities of the kinds, RGBA8
@@ -56,12 +61,19 @@ float random(inout uint state)
return float(state >> 8) * (1.0 / 16777216.0);
}
// the share of the blades drawn at specified distance; the same as lod_share() of opengl46grass.cpp
float lod_share(float distance)
// the share of the blades drawn at specified distance for speed: fewer further away, each standing for more of them
float lod_thinning(float distance)
{
return distance <= grass_lod.x ? 1.0 : pow(grass_lod.x / distance, 1.5);
}
// the share of the blades drawn: the above, and fewer and fewer over the fading distance, where the grass really gets
// sparser; the same as lod_share() of opengl46grass.cpp
float lod_share(float distance)
{
return lod_thinning(distance) * (1.0 - smoothstep(grass_lod.y, grass_lod.z, distance));
}
// height of the ground at a point of the chunk and its normal, the way the full grid is triangulated
float ground(vec2 point, out vec3 normal)
{
@@ -111,6 +123,7 @@ void main()
float leanamount = random(state);
float shade = random(state);
float phase = random(state);
float early = random(state);
// place: R2 spreads the first blades evenly at any count, a little jitter breaks its lattice
vec2 spot = fract(shift + float(blade) * vec2(0.7548776662466927, 0.5698402909980532));
@@ -148,7 +161,7 @@ void main()
float distance = length(root - grass_camera.xyz);
float share = lod_share(distance);
float rank = (float(blade) + 0.5) / grass_tile.w;
if (kind < 0 || hole > 0.5 || rank >= share || distance > grass_lod.y)
if (kind < 0 || hole > 0.5 || rank >= share || distance > grass_lod.z)
{
collapse();
return;
@@ -158,11 +171,13 @@ void main()
float height = shape.x * (1.0 + shape.y * heightrandom);
// the last of the blades drawn at the distance grow in, and the grass fades out at the end of its reach
height *= 1.0 - smoothstep(share * 0.8, share, rank);
height *= 1.0 - smoothstep(grass_lod.y * 0.75, grass_lod.y, distance);
// lower in winter, growing in spring
float seasonal = grass_dry[kind].a;
height *= mix(1.0, grass_season.z, seasonal);
// where the paint thins out the blades get shorter
height *= mix(0.5, 1.0, clamp(density[kind] * 1.5, 0.0, 1.0));
// the blades drawn further away stand for more of them, so they're wider
float width = shape.z * (0.8 + 0.4 * widthrandom) / sqrt(share);
float width = shape.z * (0.8 + 0.4 * widthrandom) / sqrt(lod_thinning(distance));
// the face of the blade turns towards the camera further away, so the blades don't vanish edge on
vec2 facing = vec2(cos(turnrandom), sin(turnrandom));
@@ -192,7 +207,13 @@ void main()
// lit mostly as the ground under it, which keeps a field of blades from shimmering
vec3 normal = normalize(groundnormal * 0.8 + vec3(facing.x, 0.0, facing.y) * (side == 0.0 ? 0.0 : 0.25) + vec3(0.0, 0.3, 0.0));
vec3 albedo = mix(grass_base[kind].rgb, grass_tip[kind].rgb, t) * (0.85 + 0.3 * shade);
// the seasons: some blades dry out (and green up) earlier than others, so a field turns gradually; a dry blade takes the
// dry colour, darker at its root. in spring the green is fresher
float dry = clamp(grass_season.x * seasonal * (0.6 + 0.8 * early), 0.0, 1.0);
vec3 bottom = mix(grass_base[kind].rgb, grass_dry[kind].rgb * 0.45, dry);
vec3 top = mix(grass_tip[kind].rgb, grass_dry[kind].rgb, dry);
top *= mix(vec3(1.0), vec3(1.08, 1.22, 0.85), grass_season.y * seasonal * (1.0 - dry));
vec3 albedo = mix(bottom, top, t) * (0.85 + 0.3 * shade);
// the lower part of the blades is shaded by the others
albedo *= mix(0.7, 1.0, t);