feat(render3d): the meadow's blades are culled on the GPU - under 1.5 ms of a MoltenVK frame for all the grass

- grass_cull.comp decides each candidate blade once a frame (place, ground, density, water,
  slope, frustum, colour field) and writes survivors into three bands by distance, one indirect
  draw each; grass_inst.vert only bends and places the vertices. OpenGL keeps grass.vert's
  per-vertex path; R3D_GRASS_GPU=0 compares
- compute programs take sampled textures after their buffers (gpu_compute_tex / gpu_dispatch_tex),
  and every dispatch now records a compute-to-draw memory barrier
- the blades as a sward: 4 m cells, bands with five, three and one-quad blades, spacing doubling
  every 18 m to 70 m, never narrower than a pixel; lit facing the sun and leaning to the sky,
  shadow looked up above the ground (it read the terrain as its caster), a colour ramp that
  leaves only the sheath dark, clumps, dry patches and a tussock shade worked out per blade
- scatter layers flagged grass are skipped while the blades draw (and under R3D_NOGRASS);
  R3D_BLADES, R3D_NOBLADES win over the game's setting; R3D_GRASS_S0/D0 for measuring

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-27 15:38:43 +03:00
parent f815f3e3cf
commit cc384efee0
34 changed files with 798 additions and 212 deletions

View file

@ -2,3 +2,5 @@
# spv/<name>.comp.spv. Binding 0 is the uniform block of parameters, 1.. storage buffers.
probe|probe.comp
scatter_cull|scatter_cull.comp
grass_reset|grass_reset.comp
grass_cull|grass_cull.comp

View file

@ -31,6 +31,7 @@ uniform vec4 u_tiles[256]; // per tile of the dispatch: corner x, corner z, in
uniform float u_s0;
uniform float u_d0;
uniform float u_radius;
uniform float u_px; // one pixel in radians (grass.vert)
uniform int u_dbg;
out vec3 v_wpos[];
out vec3 v_nrm[];
@ -40,7 +41,7 @@ out vec2 v_rot[];
out float v_hull[];
out float v_quake[]; // grass does not quake; written so model.frag can read it
const float CELL = 16.0;
const float CELL = 4.0; // grass.ludic GRASS_CELL: 4 m, so a near tile asks for what its blades need
float hash1(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); }
uint pcg(uint v) { uint s = v * 747796405u + 2891336453u; uint w = ((s >> ((s >> 28u) + 4u)) ^ s) * 277803737u; return (w >> 22u) ^ w; }
float bladeHash(ivec2 cell, int j, int k) {
@ -115,6 +116,7 @@ void main() {
float tall = mix(0.18, 0.42, h3) * mix(0.8, 1.2, hash1(cid * 0.1)) * (1.0 + 0.35 * smoothstep(1.0, 12.0, grow)) * life;
float bw = 0.028 * mix(1.0, 0.45 * grow, smoothstep(1.0, 4.0, grow));
if (far) { bw = max(bw, spacing * 0.35); tall = min(tall, spacing * 0.3); }
bw = max(bw, dist * u_px * 1.1);
float gust = sin(xz.x * 0.09 + u_time * 1.1) * 0.5 + sin(xz.y * 0.13 - u_time * 0.8 + xz.x * 0.05) * 0.5;
float ph = u_time * 1.7 + seed * 6.2831 + xz.x * 0.05 + xz.y * 0.07;
float sway = (sin(ph) * 0.6 + sin(ph * 2.3 + 1.0) * 0.4 + gust) * u_wind;

View file

@ -34,6 +34,7 @@ uniform vec4 u_tiles[256]; // per tile of the draw: corner x, corner z, indice
uniform float u_s0; // blade spacing at the camera (m)
uniform float u_d0; // distance at which the spacing has doubled (m)
uniform float u_radius; // no blades past this
uniform float u_px; // one pixel's height in radians: no blade is drawn narrower than a pixel
uniform int u_dbg; // R3D_GRASS_DBG: 1 lift blades 0.3 m, 2 light as ground everywhere, 3 both
out vec3 v_wpos;
out vec3 v_nrm;
@ -42,9 +43,10 @@ out float v_seed;
out vec2 v_rot;
out float v_hull;
out float v_quake; // only aspens quake; written so model.frag can read it
out vec3 v_tint; // the blade's colour field at its root (model.frag's regionTint and patchiness, once a blade)
const float CELL = 16.0;
float hash1(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); }
const float CELL = 4.0; // grass.ludic GRASS_CELL: 4 m, so a near tile asks for what its blades need
// hash1 and fbm come from noise.glsl, which a GBLADE vertex stage is given (programs.ludic)
// An integer hash (PCG) for the per-blade values. The sine hash advanced linearly with
// the blade index, so a cell's blades fell into diagonal rows, and the rows read as
// streaks across the meadow with an edge wherever they thinned out.
@ -68,7 +70,22 @@ float heightSmooth(sampler2D tex, vec2 uv) {
return (texture(tex, vec2(o0.x, o0.y)).r * s0.x + texture(tex, vec2(o1.x, o0.y)).r * s1.x) * s0.y
+ (texture(tex, vec2(o0.x, o1.y)).r * s0.x + texture(tex, vec2(o1.x, o1.y)).r * s1.x) * s1.y;
}
void cull() { gl_Position = vec4(0.0, 0.0, 2.0, 1.0); v_wpos = vec3(0.0); v_nrm = vec3(0.0, 1.0, 0.0); v_uv = vec2(0.0); v_seed = 0.0; v_rot = vec2(0.0, 1.0); v_hull = 1.0; v_quake = 0.0; }
void cull() { gl_Position = vec4(0.0, 0.0, 2.0, 1.0); v_wpos = vec3(0.0); v_nrm = vec3(0.0, 1.0, 0.0); v_uv = vec2(0.0); v_seed = 0.0; v_rot = vec2(0.0, 1.0); v_hull = 1.0; v_quake = 0.0; v_tint = vec3(1.0); }
// lighting.glsl's regionTint(wpos, 0.35) times model.frag's patchiness, at the root: three fbm
// fields a blade pixel used to pay for, when the whole blade stands on one spot
vec3 bladeField(vec2 xz, float y) {
float n = fbm(xz * 0.0018 + 4.0, 3) * 0.5 + 0.5;
float aspen = smoothstep(0.52, 0.7, n) * smoothstep(520.0, 250.0, y);
float dry = smoothstep(0.35, 0.15, fbm(xz * 0.004 + 9.0, 3) * 0.5 + 0.5);
vec3 t = mix(vec3(1.0), vec3(1.25, 1.3, 0.85), aspen * 0.35);
t = mix(t, vec3(1.15, 1.05, 0.7), dry * 0.35 * 0.6);
float patchy = fbm(xz * 0.045, 3) * 0.5 + 0.5;
t *= mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy);
// dry and green patches a few metres across, and the tussocks' own shade of the same green
float dryp = smoothstep(0.2, 0.8, gnoise(xz * 0.33 + 17.0) * 0.5 + 0.5);
t *= mix(vec3(0.92, 1.0, 0.95), vec3(1.30, 1.10, 0.62), dryp);
return t * (0.72 + 0.56 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
}
void main() {
#ifdef TILES
@ -158,6 +175,10 @@ void main() {
// that had been cut, which is the one thing an alpine meadow is not.
float hh = h3 * h3;
float tall = mix(0.09, 0.60, hh) * mix(0.8, 1.2, hash1(cid * 0.1)) * (1.0 + 0.35 * smoothstep(1.0, 12.0, grow)) * life;
// CLUMPS: grass grows in tussocks, taller and shorter patches a metre or so across, and that
// relief is the texture a meadow has from above - an even height reads as felt
float clump = gnoise(xz * 0.85 + 3.7) * 0.5 + 0.5;
tall *= mix(0.45, 1.40, clump * clump * (3.0 - 2.0 * clump));
// 2.8 cm was FIVE TIMES a blade of meadow grass, which is 3-6 mm. At 2 m from the
// camera that is a broad dark scimitar lying along the ground rather than a blade
// standing in a sward, and no amount of profile or colour work fixes a blade that is
@ -165,6 +186,9 @@ void main() {
// and too flat" note in this stage.
float bw = 0.010 * mix(1.0, 0.45 * grow, smoothstep(1.0, 4.0, grow));
if (far) { bw = max(bw, spacing * 0.35); tall = min(tall, spacing * 0.3); }
// a blade under a pixel is a vertex bill that shimmers: widen it to one and a bit, and let the
// thinning (spacing) keep the coverage
bw = max(bw, dist * u_px * 1.1);
vec3 p = vec3(a_pos.x * bw, a_pos.y * tall, a_pos.z * tall * (0.6 + 0.8 * h4));
vec3 n = vec3(0.0, 0.3, 1.0);
// The shared field (wind.glsl), so the gust that crosses this meadow is the same gust that
@ -217,6 +241,7 @@ void main() {
v_seed = seed;
v_rot = vec2(s, c_);
v_quake = 0.0;
v_tint = bladeField(xz, h);
v_hull = (dist > 2.0 || far || (u_dbg & 2) != 0) ? -1.0 : 1.0; // no back-face flip, no rounding past arm's reach
gl_Position = u_proj * u_view * vec4(w, 1.0);
}

View file

@ -0,0 +1,123 @@
// grass_cull.comp - the meadow's blades, decided once a frame on the GPU (Vulkan).
//
// grass.vert used to do all of this per VERTEX: every blade's hashes, its place, the ground under
// it (a four-tap bicubic height), the photograph's say on whether anything grows there, the water,
// the slope, the snow line and its colour field - ten times over for a five-row blade, and in full
// for every index a tile asked for and then threw away. Here each candidate is one invocation: a
// workgroup row per visible tile (grass.ludic walks them as before), a thread per candidate blade.
// A blade that survives is written once, as four vec4s, into its band's region, and the band's
// indirect draw count goes up by one; grass_inst.vert only bends and places the vertices.
// The rules are grass.vert's, kept in step with it: the same hashes give the same meadow.
layout(local_size_x = 64) in;
layout(set = 0, binding = 0) uniform Params {
vec4 planes[4]; // the side frustum planes: xyz in, w distance
vec4 cam; // xyz the camera, w no blades past this (u_radius)
vec4 dens; // x s0, y d0, z one pixel in radians, w the snow line
vec4 lake; // the carved lake: centre x/z, half extents (z = 0: none)
vec4 lev; // x the lake's level, y the sea's, z the photograph on (1), w unused
vec4 ts; // the height texture: origin x/z, half extent, unused
vec4 bands; // outer distance of bands 0 and 1 (x, y); band 2 is the rest
uvec4 base; // each band's first record in Out
uvec4 cap; // ... and how many it holds
} pr;
layout(set = 0, binding = 1) readonly buffer Tiles { vec4 tiles[]; }; // corner x/z, indices per cell, cells per side
layout(set = 0, binding = 2) buffer Out { vec4 outv[]; }; // 4 per blade
layout(set = 0, binding = 3) buffer Cmds { uint cmds[]; }; // VkDrawIndexedIndirectCommand per band
layout(set = 0, binding = 4) uniform sampler2D u_height; // height, normal (terrain's u_ts_height)
layout(set = 0, binding = 5) uniform sampler2D u_ortho; // the photograph
const float CELL = 4.0; // grass.ludic GRASS_CELL
uint pcg(uint v) { uint s = v * 747796405u + 2891336453u; uint w = ((s >> ((s >> 28u) + 4u)) ^ s) * 277803737u; return (w >> 22u) ^ w; }
float bladeHash(ivec2 cell, int j, int k) {
uint h = pcg(uint(cell.x + 32768) * 73856093u ^ uint(cell.y + 32768) * 19349663u ^ uint(j) * 83492791u ^ uint(k) * 2654435761u);
return float(h) * (1.0 / 4294967295.0);
}
float heightSmooth(vec2 uv) {
vec2 res = vec2(textureSize(u_height, 0));
vec2 t = uv * res - 0.5;
vec2 f = fract(t);
vec2 i = floor(t);
vec2 w0 = (1.0 - f) * (1.0 - f) * (1.0 - f) / 6.0;
vec2 w1 = (4.0 - 6.0 * f * f + 3.0 * f * f * f) / 6.0;
vec2 w3 = f * f * f / 6.0;
vec2 w2 = 1.0 - w0 - w1 - w3;
vec2 s0 = w0 + w1, s1 = w2 + w3;
vec2 o0 = (i - 1.0 + w1 / s0 + 0.5) / res;
vec2 o1 = (i + 1.0 + w3 / s1 + 0.5) / res;
return (textureLod(u_height, vec2(o0.x, o0.y), 0.0).r * s0.x + textureLod(u_height, vec2(o1.x, o0.y), 0.0).r * s1.x) * s0.y
+ (textureLod(u_height, vec2(o0.x, o1.y), 0.0).r * s0.x + textureLod(u_height, vec2(o1.x, o1.y), 0.0).r * s1.x) * s1.y;
}
// grass.vert's bladeField: the region, the patchiness, the dry patches and the tussocks' shade
vec3 bladeField(vec2 xz, float y) {
float n = fbm(xz * 0.0018 + 4.0, 3) * 0.5 + 0.5;
float aspen = smoothstep(0.52, 0.7, n) * smoothstep(520.0, 250.0, y);
float dry = smoothstep(0.35, 0.15, fbm(xz * 0.004 + 9.0, 3) * 0.5 + 0.5);
vec3 t = mix(vec3(1.0), vec3(1.25, 1.3, 0.85), aspen * 0.35);
t = mix(t, vec3(1.15, 1.05, 0.7), dry * 0.35 * 0.6);
float patchy = fbm(xz * 0.045, 3) * 0.5 + 0.5;
t *= mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy);
float dryp = smoothstep(0.2, 0.8, gnoise(xz * 0.33 + 17.0) * 0.5 + 0.5);
t *= mix(vec3(0.92, 1.0, 0.95), vec3(1.30, 1.10, 0.62), dryp);
return t * (0.72 + 0.56 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
}
void main() {
vec4 tile = tiles[gl_WorkGroupID.y];
int per_cell = int(tile.z + 0.5);
int cells = int(tile.w + 0.5);
int i = int(gl_GlobalInvocationID.x);
if (per_cell <= 0 || i >= per_cell * cells * cells) return;
int c = i / per_cell;
int j = i - c * per_cell;
vec2 cell = tile.xy + vec2(float(c % cells), float(c / cells)) * CELL;
vec2 cid = floor(cell / CELL + 0.5);
ivec2 ci = ivec2(cid);
vec2 hv = vec2(bladeHash(ci, j, 0), bladeHash(ci, j, 1));
vec2 xz = cell + hv * CELL;
float dist = length(xz - pr.cam.xz);
float radius = pr.cam.w;
if (dist >= radius) return;
float spacing = pr.dens.x * (1.0 + dist / pr.dens.y);
float count = CELL * CELL / (spacing * spacing) * (1.0 - smoothstep(radius * 0.7, radius, dist));
float keep = count / float(max(per_cell, 1));
float r = bladeHash(ci, j, 5);
if (r > keep) return;
float life = 1.0 - smoothstep(keep * 0.75, keep, r);
vec2 huv = (xz - pr.ts.xy) / (2.0 * pr.ts.z) + 0.5;
if (huv.x < 0.0 || huv.x > 1.0 || huv.y < 0.0 || huv.y > 1.0) return;
vec4 ht = textureLod(u_height, huv, 0.0);
// the frustum, on a sphere round the blade (it stands at most 0.9 m tall)
vec3 root = vec3(xz.x, ht.r, xz.y);
for (int k = 0; k < 4; k++) { if (dot(pr.planes[k].xyz, root) + pr.planes[k].w < -1.0) return; }
vec3 gn = normalize(ht.gba);
float h3 = bladeHash(ci, j, 2), h4 = bladeHash(ci, j, 3);
float wl = pr.lev.y;
if (pr.lake.z > 0.0) { vec2 q = (xz - pr.lake.xy) / pr.lake.zw; if (dot(q, q) < 1.0) wl = max(wl, pr.lev.x); }
float ok = (1.0 - smoothstep(0.30, 0.55, 1.0 - gn.y)) * smoothstep(0.0, 0.6, ht.r - wl - 0.15) * smoothstep(pr.dens.w - 80.0, pr.dens.w - 200.0, ht.r);
if (pr.lev.z > 0.5) {
vec3 oc = textureLod(u_ortho, huv, 1.5).rgb;
ok *= 0.40 + 0.60 * smoothstep(0.0, 0.025, oc.g - oc.b);
}
if (h4 > ok) return;
float h = heightSmooth(huv);
float seed = hv.x * 0.7 + hv.y * 0.3;
float ang = bladeHash(ci, j, 6) * 6.2831853;
float grow = spacing / pr.dens.x;
float hh = h3 * h3;
float tall = mix(0.09, 0.60, hh) * mix(0.8, 1.2, hash1(cid * 0.1)) * (1.0 + 0.35 * smoothstep(1.0, 12.0, grow)) * life;
float clump = gnoise(xz * 0.85 + 3.7) * 0.5 + 0.5;
tall *= mix(0.45, 1.40, clump * clump * (3.0 - 2.0 * clump));
float bw = 0.010 * mix(1.0, 0.45 * grow, smoothstep(1.0, 4.0, grow));
bw = max(bw, dist * pr.dens.z * 1.1);
uint b = dist < pr.bands.x ? 0u : (dist < pr.bands.y ? 1u : 2u);
uint slot = atomicAdd(cmds[b * 5u + 1u], 1u);
if (slot >= pr.cap[b]) { atomicAdd(cmds[b * 5u + 1u], 0xFFFFFFFFu); return; }
uint o = (pr.base[b] + slot) * 4u;
outv[o] = vec4(xz.x, h - 0.02, xz.y, seed);
outv[o + 1u] = vec4(sin(ang), cos(ang), tall, bw);
outv[o + 2u] = vec4(bladeField(xz, h), 0.6 + 0.8 * h4);
outv[o + 3u] = vec4(gn, dist);
}

View file

@ -0,0 +1,71 @@
// grass_inst.vert - a blade grass_cull.comp has already decided on (Vulkan). Everything about the
// blade - where it stands, its facing, height, width, colour field and the ground under it - is its
// instance record; this only bends, sways, pushes and stands the vertices, as grass.vert's second
// half does, so the two draw the same meadow.
layout(location = 0) in vec3 a_pos; // x: -0.5..0.5 across, y: 0..1 along the blade, z: bend
layout(location = 2) in vec2 a_uv;
layout(location = 3) in vec4 i_root; // xyz the root, w the seed
layout(location = 4) in vec4 i_shape; // sin and cos of the yaw, height, width
layout(location = 5) in vec4 i_tint; // the colour field, and how far the tip arches
layout(location = 6) in vec4 i_ground; // the ground's normal, and the distance it was decided at
uniform mat4 u_view;
uniform mat4 u_proj;
uniform float u_time;
uniform float u_wind;
uniform vec3 u_push; // x, z, radius: a body standing in the grass
uniform int u_dbg; // R3D_GRASS_DBG (2: light as ground everywhere)
out vec3 v_wpos;
out vec3 v_nrm;
out vec2 v_uv;
out float v_seed;
out vec2 v_rot;
out float v_hull;
out float v_quake;
out vec3 v_tint;
void main() {
vec2 xz = i_root.xz;
float seed = i_root.w;
float s = i_shape.x, c_ = i_shape.y, tall = i_shape.z, bw = i_shape.w;
vec3 gn = i_ground.xyz;
float dist = i_ground.w;
vec3 p = vec3(a_pos.x * bw, a_pos.y * tall, a_pos.z * tall * i_tint.w);
vec3 n = vec3(0.0, 0.3, 1.0);
float ph = u_time * 1.7 + seed * 6.2831 + xz.x * 0.05 + xz.y * 0.07;
float sway = windSway(xz, u_time, ph, 0.0) * u_wind;
float hgt = max(p.y, 0.0);
p.x += sway * hgt * hgt * 0.35;
p.z += sway * hgt * hgt * 0.15 * cos(ph * 0.7);
p = vec3(c_ * p.x + s * p.z, p.y, -s * p.x + c_ * p.z);
if (u_push.z > 0.0) {
vec2 away = xz - u_push.xy;
float pd = length(away);
float push = smoothstep(u_push.z, u_push.z * 0.2, pd);
if (push > 0.0) {
vec2 pdir = (pd > 1e-3) ? away / pd : vec2(1.0, 0.0);
float bh = max(p.y, 0.0);
p.x += pdir.x * push * bh * 1.05;
p.z += pdir.y * push * bh * 1.05;
p.y -= push * bh * 0.40;
}
}
n = normalize(vec3(c_ * n.x + s * n.z, n.y, -s * n.x + c_ * n.z));
vec3 k = cross(vec3(0.0, 1.0, 0.0), gn);
float sk = length(k), ck = gn.y;
if (sk > 1e-4) {
k /= sk;
p = p * ck + cross(k, p) * sk + k * dot(k, p) * (1.0 - ck);
n = normalize(n * ck + cross(k, n) * sk + k * dot(k, n) * (1.0 - ck));
}
n = normalize(mix(n, gn, smoothstep(2.0, 12.0, dist)));
vec3 w = i_root.xyz + p;
v_wpos = w;
v_nrm = n;
v_uv = a_uv;
v_seed = seed;
v_rot = vec2(s, c_);
v_quake = 0.0;
v_tint = i_tint.rgb;
v_hull = (dist > 2.0 || (u_dbg & 2) != 0) ? -1.0 : 1.0;
gl_Position = u_proj * u_view * vec4(w, 1.0);
}

View file

@ -0,0 +1,8 @@
// grass_reset.comp - zero each band's instance count before grass_cull.comp counts into it. On the
// GPU, in order, because the frame before may still be drawing from the same records.
layout(local_size_x = 1) in;
layout(set = 0, binding = 0) uniform Params { uvec4 n; } pr;
layout(set = 0, binding = 1) buffer Cmds { uint cmds[]; };
void main() {
for (uint b = 0u; b < pr.n.x; b++) { cmds[b * 5u + 1u] = 0u; }
}

View file

@ -15,6 +15,9 @@ uniform mat4 u_view;
uniform vec3 u_tint;
uniform float u_rough_scale;
uniform float u_emissive; // self-lit (a flame): albedo added back after shading
#ifdef GBLADE
in vec3 v_tint; // grass.vert's colour field (the mesh-shader and scatter blades work it out here)
#endif
#ifdef BLADE
uniform vec3 u_blade_base;
uniform vec3 u_blade_tip;
@ -49,6 +52,11 @@ void main() {
#endif
vec3 N = normalize(v_nrm);
if (!gl_FrontFacing && v_hull >= 0.0) N = -N;
#ifdef BLADE
// A blade is thin and two-sided: the sun lights whichever face it reaches (the other glows
// through, below). Faced away from the sun, half the meadow was lit by the sky alone.
if (dot(N, u_sun_dir) < 0.0) N = -N;
#endif
#ifdef CARD
// a baked card: albedo with coverage (premultiplied mips), normal in the card's own frame
vec4 ca = texture(u_diff, v_uv);
@ -80,7 +88,16 @@ void main() {
#ifdef BLADE
// a procedural blade: dark at the root, lighter at the tip; some blades gone to seed
float t = clamp(v_uv.y, 0.0, 1.0);
alb = mix(u_blade_base, u_blade_tip, t * t) * regionTint(v_wpos, 0.35);
// most of a blade is its own green, only the sheath darker: t*t held the lower two thirds at the
// root colour (0.14, darker than the ground), and a meadow of those reads as dark wire
#ifndef GBLADE
vec3 field = regionTint(v_wpos, 0.35);
float patchy = fbm(v_wpos.xz * 0.045, 3) * 0.5 + 0.5;
field *= mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy);
#else
vec3 field = v_tint;
#endif
alb = mix(u_blade_base, u_blade_tip, smoothstep(0.0, 0.55, t)) * field;
float dry = smoothstep(0.7, 0.8, fract(v_seed * 3.17));
alb = mix(alb, vec3(0.40, 0.36, 0.13) * (0.45 + 0.55 * t), dry * 0.75);
// A REAL BLADE, if the game gave us one. Each blade picks a column of the atlas from
@ -110,13 +127,13 @@ void main() {
vec3 g = photo * (1.0 / 0.3736);
alb *= mix(vec3(1.0), min(g, vec3(1.15)), 0.85);
}
float patchy = fbm(v_wpos.xz * 0.045, 3) * 0.5 + 0.5;
alb *= mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy);
// a far tuft is a patch of the meadow, darker than a lit blade tip and never straw
if (v_hull < 0.0) alb = mix(u_blade_base, u_blade_tip, 0.45) * regionTint(v_wpos, 0.35) * mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy) * 0.72;
if (v_hull < 0.0) alb = mix(u_blade_base, u_blade_tip, 0.45) * field * 0.72;
// a rounded cross-section reads softer than a flat card
vec3 side = normalize(cross(N, vec3(0.0, 1.0, 0.0)) + vec3(1e-4));
n = (v_hull < 0.0) ? N : normalize(N + side * (v_uv.x * 2.0 - 1.0) * 0.6);
// and a sward is lit as a mass leaning to the sky: a level normal took the light at a graze
n = normalize(n + vec3(0.0, 0.45, 0.0));
// A blade's own ambient occlusion. This was mix(0.2, 1.0, t*t): 80% occluded at the
// sheath and still 60% at half height, because t*t holds the curve down. Measured in a
// walking-distance shot the blades came out at 24-31 of 255 against a ground of 143 -
@ -227,6 +244,13 @@ void main() {
#else
float shadow = mix(1.0, sunShadow(v_wpos + N * 0.1 + vec3(0.0, 0.2, 0.0), N, viewDepth), 0.55);
#endif
#elif defined(BLADE)
// A blade stands within a shadow texel of the ground under it, and biased along its own
// (level) normal it read the terrain as its caster: the whole meadow in shadow, dark wire.
// Looked up a hand's width up, along the ground's up, trees and rocks still shade it.
// past arm's length a blade is a pixel or two wide: one tap is what a soft filter averages to
float shadow = (dist < 8.0) ? sunShadow(v_wpos + vec3(0.0, 0.25, 0.0), vec3(0.0, 1.0, 0.0), viewDepth)
: sunShadowCheap(v_wpos + vec3(0.0, 0.25, 0.0), vec3(0.0, 1.0, 0.0), viewDepth);
#else
float shadow = sunShadow(v_wpos, N, viewDepth);
#endif
@ -271,6 +295,9 @@ void main() {
float NoV = max(dot(n, vv), 0.0);
float sheen = pow(NoH, 26.0) * 0.55 + pow(1.0 - NoV, 4.0) * 0.05;
sheen *= smoothstep(0.10, 0.42, NoV);
#ifdef BLADE
sheen *= 0.2; // a sward seen from above is tips edge-on to the sun: the leaf's glint frosted them white
#endif
col += u_sun_color * sheen * shadow * cloudShadow(v_wpos) * 0.4 * (0.45 + 0.55 * arm.r);
}
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -843,7 +843,7 @@ T 74258189 u_shadow 6
T 74258189 u_tershadow 7
T 74258189 u_ts_height 8
P d48d6a48 grass.mesh model.frag #define FOLIAGE;#define BLADE;#define MESH;
B d48d6a48 vert 0 4384
B d48d6a48 vert 0 4388
U d48d6a48 vert u_view 0 mat4 1 0
U d48d6a48 vert u_proj 64 mat4 1 0
U d48d6a48 vert u_vp 128 mat4 1 0
@ -862,7 +862,8 @@ U d48d6a48 vert u_tiles 272 vec4 256 16
U d48d6a48 vert u_s0 4368 float 1 0
U d48d6a48 vert u_d0 4372 float 1 0
U d48d6a48 vert u_radius 4376 float 1 0
U d48d6a48 vert u_dbg 4380 int 1 0
U d48d6a48 vert u_px 4380 float 1 0
U d48d6a48 vert u_dbg 4384 int 1 0
B d48d6a48 frag 1 964
U d48d6a48 frag u_cascade_vp 0 mat4 5 64
U d48d6a48 frag u_cascade_split 320 float 5 16
@ -919,169 +920,171 @@ T d48d6a48 u_prefilter 9
T d48d6a48 u_shadow 10
T d48d6a48 u_tershadow 11
T d48d6a48 u_ts_height 12
P 7ed7de52 grass.vert model.frag #define FOLIAGE;#define BLADE;
B 7ed7de52 vert 0 320
U 7ed7de52 vert u_view 0 mat4 1 0
U 7ed7de52 vert u_proj 64 mat4 1 0
U 7ed7de52 vert u_vp 128 mat4 1 0
U 7ed7de52 vert u_cam_pos 192 vec3 1 0
U 7ed7de52 vert u_time 204 float 1 0
U 7ed7de52 vert u_ts_origin 208 vec2 1 0
U 7ed7de52 vert u_ts_half 216 float 1 0
U 7ed7de52 vert u_ortho_on 220 float 1 0
U 7ed7de52 vert u_lake_level 224 float 1 0
U 7ed7de52 vert u_sea_level 228 float 1 0
U 7ed7de52 vert u_lake 240 vec4 1 0
U 7ed7de52 vert u_snow_line 256 float 1 0
U 7ed7de52 vert u_wind 260 float 1 0
U 7ed7de52 vert u_push 272 vec3 1 0
U 7ed7de52 vert u_tile 288 vec2 1 0
U 7ed7de52 vert u_tile_cells 296 int 1 0
U 7ed7de52 vert u_per_cell 300 int 1 0
U 7ed7de52 vert u_s0 304 float 1 0
U 7ed7de52 vert u_d0 308 float 1 0
U 7ed7de52 vert u_radius 312 float 1 0
U 7ed7de52 vert u_dbg 316 int 1 0
I 7ed7de52 a_pos 0 vec3
I 7ed7de52 a_uv 2 vec2
B 7ed7de52 frag 1 964
U 7ed7de52 frag u_cascade_vp 0 mat4 5 64
U 7ed7de52 frag u_cascade_split 320 float 5 16
U 7ed7de52 frag u_cascade_range 400 float 5 16
U 7ed7de52 frag u_cascade_texel 480 float 5 16
U 7ed7de52 frag u_sun_dir 560 vec3 1 0
U 7ed7de52 frag u_sun_color 576 vec3 1 0
U 7ed7de52 frag u_cam_pos 592 vec3 1 0
U 7ed7de52 frag u_prefilter_levels 604 float 1 0
U 7ed7de52 frag u_fog_density 608 float 1 0
U 7ed7de52 frag u_fog_height_falloff 612 float 1 0
U 7ed7de52 frag u_fog_base 616 float 1 0
U 7ed7de52 frag u_clip_y 620 float 1 0
U 7ed7de52 frag u_spec_scale 624 float 1 0
U 7ed7de52 frag u_sky_rot 632 vec2 1 0
U 7ed7de52 frag u_ground_alb 640 vec3 1 0
U 7ed7de52 frag u_ground_alb_hi 656 vec3 1 0
U 7ed7de52 frag u_ground_hi_y 668 float 1 0
U 7ed7de52 frag u_ground_hi_w 672 float 1 0
U 7ed7de52 frag u_ibl_scale 688 vec3 1 0
U 7ed7de52 frag u_daylight 700 float 1 0
U 7ed7de52 frag u_fire_pos 704 vec3 1 0
U 7ed7de52 frag u_fire_color 720 vec3 1 0
U 7ed7de52 frag u_hand_pos 736 vec3 1 0
U 7ed7de52 frag u_hand_color 752 vec3 1 0
U 7ed7de52 frag u_hand_dir 768 vec3 1 0
U 7ed7de52 frag u_hand_cone 780 float 1 0
U 7ed7de52 frag u_hand_reach 784 float 1 0
U 7ed7de52 frag u_ts_origin 792 vec2 1 0
U 7ed7de52 frag u_ts_half 800 float 1 0
U 7ed7de52 frag u_ts_on 804 float 1 0
U 7ed7de52 frag u_force_cascade 808 int 1 0
U 7ed7de52 frag u_cloud_shadow 812 float 1 0
U 7ed7de52 frag u_time 816 float 1 0
U 7ed7de52 frag u_fog_inscatter 820 float 1 0
U 7ed7de52 frag u_fog_desat 824 float 1 0
U 7ed7de52 frag u_model_h 828 float 1 0
U 7ed7de52 frag u_view 832 mat4 1 0
U 7ed7de52 frag u_tint 896 vec3 1 0
U 7ed7de52 frag u_rough_scale 908 float 1 0
U 7ed7de52 frag u_emissive 912 float 1 0
U 7ed7de52 frag u_blade_base 928 vec3 1 0
U 7ed7de52 frag u_blade_tip 944 vec3 1 0
U 7ed7de52 frag u_blade_cols 956 float 1 0
U 7ed7de52 frag u_blade_tex_on 960 float 1 0
T 7ed7de52 u_arm 2
T 7ed7de52 u_blade_tex 3
T 7ed7de52 u_brdf 4
T 7ed7de52 u_diff 5
T 7ed7de52 u_irradiance 6
T 7ed7de52 u_nrm 7
T 7ed7de52 u_ortho 8
T 7ed7de52 u_prefilter 9
T 7ed7de52 u_shadow 10
T 7ed7de52 u_tershadow 11
T 7ed7de52 u_ts_height 12
P 7f096322 grass.vert model.frag #define FOLIAGE;#define BLADE;#define TILES;
B 7f096322 vert 0 4416
U 7f096322 vert u_view 0 mat4 1 0
U 7f096322 vert u_proj 64 mat4 1 0
U 7f096322 vert u_vp 128 mat4 1 0
U 7f096322 vert u_cam_pos 192 vec3 1 0
U 7f096322 vert u_time 204 float 1 0
U 7f096322 vert u_ts_origin 208 vec2 1 0
U 7f096322 vert u_ts_half 216 float 1 0
U 7f096322 vert u_ortho_on 220 float 1 0
U 7f096322 vert u_lake_level 224 float 1 0
U 7f096322 vert u_sea_level 228 float 1 0
U 7f096322 vert u_lake 240 vec4 1 0
U 7f096322 vert u_snow_line 256 float 1 0
U 7f096322 vert u_wind 260 float 1 0
U 7f096322 vert u_push 272 vec3 1 0
U 7f096322 vert u_tile 288 vec2 1 0
U 7f096322 vert u_tile_cells 296 int 1 0
U 7f096322 vert u_per_cell 300 int 1 0
U 7f096322 vert u_tiles 304 vec4 256 16
U 7f096322 vert u_s0 4400 float 1 0
U 7f096322 vert u_d0 4404 float 1 0
U 7f096322 vert u_radius 4408 float 1 0
U 7f096322 vert u_dbg 4412 int 1 0
I 7f096322 a_pos 0 vec3
I 7f096322 a_uv 2 vec2
B 7f096322 frag 1 964
U 7f096322 frag u_cascade_vp 0 mat4 5 64
U 7f096322 frag u_cascade_split 320 float 5 16
U 7f096322 frag u_cascade_range 400 float 5 16
U 7f096322 frag u_cascade_texel 480 float 5 16
U 7f096322 frag u_sun_dir 560 vec3 1 0
U 7f096322 frag u_sun_color 576 vec3 1 0
U 7f096322 frag u_cam_pos 592 vec3 1 0
U 7f096322 frag u_prefilter_levels 604 float 1 0
U 7f096322 frag u_fog_density 608 float 1 0
U 7f096322 frag u_fog_height_falloff 612 float 1 0
U 7f096322 frag u_fog_base 616 float 1 0
U 7f096322 frag u_clip_y 620 float 1 0
U 7f096322 frag u_spec_scale 624 float 1 0
U 7f096322 frag u_sky_rot 632 vec2 1 0
U 7f096322 frag u_ground_alb 640 vec3 1 0
U 7f096322 frag u_ground_alb_hi 656 vec3 1 0
U 7f096322 frag u_ground_hi_y 668 float 1 0
U 7f096322 frag u_ground_hi_w 672 float 1 0
U 7f096322 frag u_ibl_scale 688 vec3 1 0
U 7f096322 frag u_daylight 700 float 1 0
U 7f096322 frag u_fire_pos 704 vec3 1 0
U 7f096322 frag u_fire_color 720 vec3 1 0
U 7f096322 frag u_hand_pos 736 vec3 1 0
U 7f096322 frag u_hand_color 752 vec3 1 0
U 7f096322 frag u_hand_dir 768 vec3 1 0
U 7f096322 frag u_hand_cone 780 float 1 0
U 7f096322 frag u_hand_reach 784 float 1 0
U 7f096322 frag u_ts_origin 792 vec2 1 0
U 7f096322 frag u_ts_half 800 float 1 0
U 7f096322 frag u_ts_on 804 float 1 0
U 7f096322 frag u_force_cascade 808 int 1 0
U 7f096322 frag u_cloud_shadow 812 float 1 0
U 7f096322 frag u_time 816 float 1 0
U 7f096322 frag u_fog_inscatter 820 float 1 0
U 7f096322 frag u_fog_desat 824 float 1 0
U 7f096322 frag u_model_h 828 float 1 0
U 7f096322 frag u_view 832 mat4 1 0
U 7f096322 frag u_tint 896 vec3 1 0
U 7f096322 frag u_rough_scale 908 float 1 0
U 7f096322 frag u_emissive 912 float 1 0
U 7f096322 frag u_blade_base 928 vec3 1 0
U 7f096322 frag u_blade_tip 944 vec3 1 0
U 7f096322 frag u_blade_cols 956 float 1 0
U 7f096322 frag u_blade_tex_on 960 float 1 0
T 7f096322 u_arm 2
T 7f096322 u_blade_tex 3
T 7f096322 u_brdf 4
T 7f096322 u_diff 5
T 7f096322 u_irradiance 6
T 7f096322 u_nrm 7
T 7f096322 u_ortho 8
T 7f096322 u_prefilter 9
T 7f096322 u_shadow 10
T 7f096322 u_tershadow 11
T 7f096322 u_ts_height 12
P cb13f3c6 grass.vert model.frag #define FOLIAGE;#define BLADE;#define GBLADE;
B cb13f3c6 vert 0 324
U cb13f3c6 vert u_view 0 mat4 1 0
U cb13f3c6 vert u_proj 64 mat4 1 0
U cb13f3c6 vert u_vp 128 mat4 1 0
U cb13f3c6 vert u_cam_pos 192 vec3 1 0
U cb13f3c6 vert u_time 204 float 1 0
U cb13f3c6 vert u_ts_origin 208 vec2 1 0
U cb13f3c6 vert u_ts_half 216 float 1 0
U cb13f3c6 vert u_ortho_on 220 float 1 0
U cb13f3c6 vert u_lake_level 224 float 1 0
U cb13f3c6 vert u_sea_level 228 float 1 0
U cb13f3c6 vert u_lake 240 vec4 1 0
U cb13f3c6 vert u_snow_line 256 float 1 0
U cb13f3c6 vert u_wind 260 float 1 0
U cb13f3c6 vert u_push 272 vec3 1 0
U cb13f3c6 vert u_tile 288 vec2 1 0
U cb13f3c6 vert u_tile_cells 296 int 1 0
U cb13f3c6 vert u_per_cell 300 int 1 0
U cb13f3c6 vert u_s0 304 float 1 0
U cb13f3c6 vert u_d0 308 float 1 0
U cb13f3c6 vert u_radius 312 float 1 0
U cb13f3c6 vert u_px 316 float 1 0
U cb13f3c6 vert u_dbg 320 int 1 0
I cb13f3c6 a_pos 0 vec3
I cb13f3c6 a_uv 2 vec2
B cb13f3c6 frag 1 964
U cb13f3c6 frag u_cascade_vp 0 mat4 5 64
U cb13f3c6 frag u_cascade_split 320 float 5 16
U cb13f3c6 frag u_cascade_range 400 float 5 16
U cb13f3c6 frag u_cascade_texel 480 float 5 16
U cb13f3c6 frag u_sun_dir 560 vec3 1 0
U cb13f3c6 frag u_sun_color 576 vec3 1 0
U cb13f3c6 frag u_cam_pos 592 vec3 1 0
U cb13f3c6 frag u_prefilter_levels 604 float 1 0
U cb13f3c6 frag u_fog_density 608 float 1 0
U cb13f3c6 frag u_fog_height_falloff 612 float 1 0
U cb13f3c6 frag u_fog_base 616 float 1 0
U cb13f3c6 frag u_clip_y 620 float 1 0
U cb13f3c6 frag u_spec_scale 624 float 1 0
U cb13f3c6 frag u_sky_rot 632 vec2 1 0
U cb13f3c6 frag u_ground_alb 640 vec3 1 0
U cb13f3c6 frag u_ground_alb_hi 656 vec3 1 0
U cb13f3c6 frag u_ground_hi_y 668 float 1 0
U cb13f3c6 frag u_ground_hi_w 672 float 1 0
U cb13f3c6 frag u_ibl_scale 688 vec3 1 0
U cb13f3c6 frag u_daylight 700 float 1 0
U cb13f3c6 frag u_fire_pos 704 vec3 1 0
U cb13f3c6 frag u_fire_color 720 vec3 1 0
U cb13f3c6 frag u_hand_pos 736 vec3 1 0
U cb13f3c6 frag u_hand_color 752 vec3 1 0
U cb13f3c6 frag u_hand_dir 768 vec3 1 0
U cb13f3c6 frag u_hand_cone 780 float 1 0
U cb13f3c6 frag u_hand_reach 784 float 1 0
U cb13f3c6 frag u_ts_origin 792 vec2 1 0
U cb13f3c6 frag u_ts_half 800 float 1 0
U cb13f3c6 frag u_ts_on 804 float 1 0
U cb13f3c6 frag u_force_cascade 808 int 1 0
U cb13f3c6 frag u_cloud_shadow 812 float 1 0
U cb13f3c6 frag u_time 816 float 1 0
U cb13f3c6 frag u_fog_inscatter 820 float 1 0
U cb13f3c6 frag u_fog_desat 824 float 1 0
U cb13f3c6 frag u_model_h 828 float 1 0
U cb13f3c6 frag u_view 832 mat4 1 0
U cb13f3c6 frag u_tint 896 vec3 1 0
U cb13f3c6 frag u_rough_scale 908 float 1 0
U cb13f3c6 frag u_emissive 912 float 1 0
U cb13f3c6 frag u_blade_base 928 vec3 1 0
U cb13f3c6 frag u_blade_tip 944 vec3 1 0
U cb13f3c6 frag u_blade_cols 956 float 1 0
U cb13f3c6 frag u_blade_tex_on 960 float 1 0
T cb13f3c6 u_arm 2
T cb13f3c6 u_blade_tex 3
T cb13f3c6 u_brdf 4
T cb13f3c6 u_diff 5
T cb13f3c6 u_irradiance 6
T cb13f3c6 u_nrm 7
T cb13f3c6 u_ortho 8
T cb13f3c6 u_prefilter 9
T cb13f3c6 u_shadow 10
T cb13f3c6 u_tershadow 11
T cb13f3c6 u_ts_height 12
P b8cff226 grass.vert model.frag #define FOLIAGE;#define BLADE;#define GBLADE;#define TILES;
B b8cff226 vert 0 4420
U b8cff226 vert u_view 0 mat4 1 0
U b8cff226 vert u_proj 64 mat4 1 0
U b8cff226 vert u_vp 128 mat4 1 0
U b8cff226 vert u_cam_pos 192 vec3 1 0
U b8cff226 vert u_time 204 float 1 0
U b8cff226 vert u_ts_origin 208 vec2 1 0
U b8cff226 vert u_ts_half 216 float 1 0
U b8cff226 vert u_ortho_on 220 float 1 0
U b8cff226 vert u_lake_level 224 float 1 0
U b8cff226 vert u_sea_level 228 float 1 0
U b8cff226 vert u_lake 240 vec4 1 0
U b8cff226 vert u_snow_line 256 float 1 0
U b8cff226 vert u_wind 260 float 1 0
U b8cff226 vert u_push 272 vec3 1 0
U b8cff226 vert u_tile 288 vec2 1 0
U b8cff226 vert u_tile_cells 296 int 1 0
U b8cff226 vert u_per_cell 300 int 1 0
U b8cff226 vert u_tiles 304 vec4 256 16
U b8cff226 vert u_s0 4400 float 1 0
U b8cff226 vert u_d0 4404 float 1 0
U b8cff226 vert u_radius 4408 float 1 0
U b8cff226 vert u_px 4412 float 1 0
U b8cff226 vert u_dbg 4416 int 1 0
I b8cff226 a_pos 0 vec3
I b8cff226 a_uv 2 vec2
B b8cff226 frag 1 964
U b8cff226 frag u_cascade_vp 0 mat4 5 64
U b8cff226 frag u_cascade_split 320 float 5 16
U b8cff226 frag u_cascade_range 400 float 5 16
U b8cff226 frag u_cascade_texel 480 float 5 16
U b8cff226 frag u_sun_dir 560 vec3 1 0
U b8cff226 frag u_sun_color 576 vec3 1 0
U b8cff226 frag u_cam_pos 592 vec3 1 0
U b8cff226 frag u_prefilter_levels 604 float 1 0
U b8cff226 frag u_fog_density 608 float 1 0
U b8cff226 frag u_fog_height_falloff 612 float 1 0
U b8cff226 frag u_fog_base 616 float 1 0
U b8cff226 frag u_clip_y 620 float 1 0
U b8cff226 frag u_spec_scale 624 float 1 0
U b8cff226 frag u_sky_rot 632 vec2 1 0
U b8cff226 frag u_ground_alb 640 vec3 1 0
U b8cff226 frag u_ground_alb_hi 656 vec3 1 0
U b8cff226 frag u_ground_hi_y 668 float 1 0
U b8cff226 frag u_ground_hi_w 672 float 1 0
U b8cff226 frag u_ibl_scale 688 vec3 1 0
U b8cff226 frag u_daylight 700 float 1 0
U b8cff226 frag u_fire_pos 704 vec3 1 0
U b8cff226 frag u_fire_color 720 vec3 1 0
U b8cff226 frag u_hand_pos 736 vec3 1 0
U b8cff226 frag u_hand_color 752 vec3 1 0
U b8cff226 frag u_hand_dir 768 vec3 1 0
U b8cff226 frag u_hand_cone 780 float 1 0
U b8cff226 frag u_hand_reach 784 float 1 0
U b8cff226 frag u_ts_origin 792 vec2 1 0
U b8cff226 frag u_ts_half 800 float 1 0
U b8cff226 frag u_ts_on 804 float 1 0
U b8cff226 frag u_force_cascade 808 int 1 0
U b8cff226 frag u_cloud_shadow 812 float 1 0
U b8cff226 frag u_time 816 float 1 0
U b8cff226 frag u_fog_inscatter 820 float 1 0
U b8cff226 frag u_fog_desat 824 float 1 0
U b8cff226 frag u_model_h 828 float 1 0
U b8cff226 frag u_view 832 mat4 1 0
U b8cff226 frag u_tint 896 vec3 1 0
U b8cff226 frag u_rough_scale 908 float 1 0
U b8cff226 frag u_emissive 912 float 1 0
U b8cff226 frag u_blade_base 928 vec3 1 0
U b8cff226 frag u_blade_tip 944 vec3 1 0
U b8cff226 frag u_blade_cols 956 float 1 0
U b8cff226 frag u_blade_tex_on 960 float 1 0
T b8cff226 u_arm 2
T b8cff226 u_blade_tex 3
T b8cff226 u_brdf 4
T b8cff226 u_diff 5
T b8cff226 u_irradiance 6
T b8cff226 u_nrm 7
T b8cff226 u_ortho 8
T b8cff226 u_prefilter 9
T b8cff226 u_shadow 10
T b8cff226 u_tershadow 11
T b8cff226 u_ts_height 12
P 3733fc38 impostor.vert impostor.frag
B 3733fc38 vert 0 232
U 3733fc38 vert u_view 0 mat4 1 0
@ -3522,3 +3525,72 @@ T 46e2325c u_scene 7
T 46e2325c u_shadow 8
T 46e2325c u_tershadow 9
T 46e2325c u_ts_height 10
P b20fdcb5 grass_inst.vert model.frag #define FOLIAGE;#define BLADE;#define GBLADE;#define GINST;
B b20fdcb5 vert 0 160
U b20fdcb5 vert u_view 0 mat4 1 0
U b20fdcb5 vert u_proj 64 mat4 1 0
U b20fdcb5 vert u_time 128 float 1 0
U b20fdcb5 vert u_wind 132 float 1 0
U b20fdcb5 vert u_push 144 vec3 1 0
U b20fdcb5 vert u_dbg 156 int 1 0
I b20fdcb5 i_root 3 vec4
I b20fdcb5 i_shape 4 vec4
I b20fdcb5 i_ground 6 vec4
I b20fdcb5 a_pos 0 vec3
I b20fdcb5 i_tint 5 vec4
I b20fdcb5 a_uv 2 vec2
B b20fdcb5 frag 1 964
U b20fdcb5 frag u_cascade_vp 0 mat4 5 64
U b20fdcb5 frag u_cascade_split 320 float 5 16
U b20fdcb5 frag u_cascade_range 400 float 5 16
U b20fdcb5 frag u_cascade_texel 480 float 5 16
U b20fdcb5 frag u_sun_dir 560 vec3 1 0
U b20fdcb5 frag u_sun_color 576 vec3 1 0
U b20fdcb5 frag u_cam_pos 592 vec3 1 0
U b20fdcb5 frag u_prefilter_levels 604 float 1 0
U b20fdcb5 frag u_fog_density 608 float 1 0
U b20fdcb5 frag u_fog_height_falloff 612 float 1 0
U b20fdcb5 frag u_fog_base 616 float 1 0
U b20fdcb5 frag u_clip_y 620 float 1 0
U b20fdcb5 frag u_spec_scale 624 float 1 0
U b20fdcb5 frag u_sky_rot 632 vec2 1 0
U b20fdcb5 frag u_ground_alb 640 vec3 1 0
U b20fdcb5 frag u_ground_alb_hi 656 vec3 1 0
U b20fdcb5 frag u_ground_hi_y 668 float 1 0
U b20fdcb5 frag u_ground_hi_w 672 float 1 0
U b20fdcb5 frag u_ibl_scale 688 vec3 1 0
U b20fdcb5 frag u_daylight 700 float 1 0
U b20fdcb5 frag u_fire_pos 704 vec3 1 0
U b20fdcb5 frag u_fire_color 720 vec3 1 0
U b20fdcb5 frag u_hand_pos 736 vec3 1 0
U b20fdcb5 frag u_hand_color 752 vec3 1 0
U b20fdcb5 frag u_hand_dir 768 vec3 1 0
U b20fdcb5 frag u_hand_cone 780 float 1 0
U b20fdcb5 frag u_hand_reach 784 float 1 0
U b20fdcb5 frag u_ts_origin 792 vec2 1 0
U b20fdcb5 frag u_ts_half 800 float 1 0
U b20fdcb5 frag u_ts_on 804 float 1 0
U b20fdcb5 frag u_force_cascade 808 int 1 0
U b20fdcb5 frag u_cloud_shadow 812 float 1 0
U b20fdcb5 frag u_time 816 float 1 0
U b20fdcb5 frag u_fog_inscatter 820 float 1 0
U b20fdcb5 frag u_fog_desat 824 float 1 0
U b20fdcb5 frag u_model_h 828 float 1 0
U b20fdcb5 frag u_view 832 mat4 1 0
U b20fdcb5 frag u_tint 896 vec3 1 0
U b20fdcb5 frag u_rough_scale 908 float 1 0
U b20fdcb5 frag u_emissive 912 float 1 0
U b20fdcb5 frag u_blade_base 928 vec3 1 0
U b20fdcb5 frag u_blade_tip 944 vec3 1 0
U b20fdcb5 frag u_blade_cols 956 float 1 0
U b20fdcb5 frag u_blade_tex_on 960 float 1 0
T b20fdcb5 u_arm 2
T b20fdcb5 u_blade_tex 3
T b20fdcb5 u_brdf 4
T b20fdcb5 u_diff 5
T b20fdcb5 u_irradiance 6
T b20fdcb5 u_nrm 7
T b20fdcb5 u_prefilter 8
T b20fdcb5 u_shadow 9
T b20fdcb5 u_tershadow 10
T b20fdcb5 u_ts_height 11

View file

@ -20,8 +20,8 @@ fullscreen.vert|tonemap.frag|
fullscreen.vert|tonemap.frag|#define HDR10;
fullscreen.vert|volumetric.frag|
grass.mesh|model.frag|#define FOLIAGE;#define BLADE;#define MESH;
grass.vert|model.frag|#define FOLIAGE;#define BLADE;
grass.vert|model.frag|#define FOLIAGE;#define BLADE;#define TILES;
grass.vert|model.frag|#define FOLIAGE;#define BLADE;#define GBLADE;
grass.vert|model.frag|#define FOLIAGE;#define BLADE;#define GBLADE;#define TILES;
impostor.vert|impostor.frag|
impostor.vert|impostor.frag|#define SHADOW_PASS;
model.vert|bake.frag|
@ -59,3 +59,4 @@ terrain.vert|terrain.frag|#define SUN_INLINE;#define FAR_ONLY;
terrain.vert|terrain.frag|#define SUN_INLINE;#define NEAR_ONLY;
terrain.vert|tersun.frag|
water.vert|water.frag|
grass_inst.vert|model.frag|#define FOLIAGE;#define BLADE;#define GBLADE;#define GINST;