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:
parent
f815f3e3cf
commit
cc384efee0
34 changed files with 798 additions and 212 deletions
|
|
@ -234,7 +234,10 @@ function cmd_shaders() -> int {
|
|||
let depth_remap = "\n#undef main\nvoid main() {\n ludic_gl_main();\n gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n}\n"
|
||||
# invariant: the foliage's depth prepass and its lit pass (depth EQUAL) are different variants,
|
||||
# and without it the compiler may compute their positions a hair apart and fail the test
|
||||
var vsrc = "#version 460\n" + defines + shd_wind + "invariant gl_Position;\n#define main ludic_gl_main\n" + shd_file(parts[0]) + depth_remap
|
||||
# as programs.ludic: a blade's vertex stage gets the noise its colour field needs
|
||||
var vnoise = ""
|
||||
if Text.contains(defines, "#define GBLADE") { vnoise = shd_noise }
|
||||
var vsrc = "#version 460\n" + defines + shd_wind + vnoise + "invariant gl_Position;\n#define main ludic_gl_main\n" + shd_file(parts[0]) + depth_remap
|
||||
# A mesh shader stands in for the vertex stage (a variant whose first file is *.mesh): it writes an
|
||||
# array of positions, so it cannot be wrapped for the depth remap or take invariant gl_Position -
|
||||
# it remaps depth itself. Its SPIR-V keeps the .vert name, so the manifest and loader are unchanged.
|
||||
|
|
@ -304,7 +307,8 @@ function cmd_shaders() -> int {
|
|||
let cp = Text.split(cl, "|")
|
||||
if len(cp) < 2 { err(`shaders: bad compute line: {cl}\n`); return 1 }
|
||||
let glsl = `{tmp}/{cp[0]}.comp.glsl`
|
||||
if not write_file(glsl, "#version 460\n" + shd_file(cp[1])) { err(`shaders: cannot write {glsl}\n`); return 1 }
|
||||
# the noise functions come first, as in a fragment stage (grass_cull uses them; the rest ignore them)
|
||||
if not write_file(glsl, "#version 460\n" + shd_noise + shd_file(cp[1])) { err(`shaders: cannot write {glsl}\n`); return 1 }
|
||||
let spv = `{outdir}/{cp[0]}.comp.spv`
|
||||
let logf = `{tmp}/{cp[0]}.comp.log`
|
||||
if not shq(`{shd_q(shd_bin + "/glslangValidator")} -V -S comp {shd_q(glsl)} -o {shd_q(spv)} > {shd_q(logf)} 2>&1`) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue