render3d: the GPU blades grow by a painted density (a layer of the ground densities, grass_density_layer) where a map has one - a 5x5-tile window round the camera in a storage buffer the cull samples - and by today's rules where not; grass_rule_at is the rules on the CPU for the migration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 21:14:22 +03:00
parent e6f4685bd0
commit 9186abbbe3
10 changed files with 219 additions and 21 deletions

View file

@ -37,7 +37,7 @@ function gg_init__t(render3d_st: mut Render3dState) -> void {
if not gpu_has_compute(render3d_st) or render3d_st.grass_prog == 0 { return }
if r3d_env_has(render3d_st, "R3D_GRASS_GPU") and r3d_env(render3d_st, "R3D_GRASS_GPU") == "0" { return }
render3d_st.gg_reset = gpu_compute(render3d_st, "grass_reset", 1)
render3d_st.gg_cull = gpu_compute_tex(render3d_st, "grass_cull", 3, 7)
render3d_st.gg_cull = gpu_compute_tex(render3d_st, "grass_cull", 4, 7)
render3d_st.gg_prog = r3d_program(render3d_st, "grass_inst.vert", "model.frag", "#define FOLIAGE\n#define BLADE\n#define GBLADE\n#define GINST\n")
if render3d_st.gg_reset == 0 or render3d_st.gg_cull == 0 or render3d_st.gg_prog == 0 { return }
render3d_st.gg_tiles_buf = new []int
@ -57,6 +57,7 @@ function gg_init__t(render3d_st: mut Render3dState) -> void {
render3d_st.gg_cmds = gpu_buffer_new(render3d_st)
gpu_buffer_upload(render3d_st, render3d_st.gg_cmds, GG_BANDS * 20, data_of(rec), GPU_DYNAMIC)
gpu_buffer_gpu_owned(render3d_st, render3d_st.gg_cmds)
gb_init(render3d_st)
render3d_st.gg_on = true
print("r3d: grass: blades are culled on the GPU")
}
@ -132,13 +133,14 @@ function gg_cull_frame(render3d_st: mut Render3dState) -> void {
# the tile list alternates buffers by frame, so the frame still on the GPU keeps its own
let tb = render3d_st.gg_tiles_buf[render3d_st.r3d_test_frame % 2]
gpu_buffer_upload(render3d_st, tb, render3d_st.gg_n * 16, data_of(render3d_st.gg_tv), GPU_DYNAMIC)
gb_frame(render3d_st)
let pr = gg_params(render3d_st)
let bufs = render3d_st.gg_bufs
bufs[0] = tb; bufs[1] = render3d_st.gg_out; bufs[2] = render3d_st.gg_cmds
bufs[0] = tb; bufs[1] = render3d_st.gg_out; bufs[2] = render3d_st.gg_cmds; bufs[3] = render3d_st.gb_buf
let texs = render3d_st.gg_texs
texs[0] = render3d_st.ter_height_tex; texs[1] = render3d_st.ter_ortho_tex; texs[2] = render3d_st.ter_normal_tex
gg_page_texs(render3d_st, texs)
gpu_dispatch_tex(render3d_st, render3d_st.gg_cull, data_of(pr), 288, bufs, texs, (render3d_st.gg_max + 63) / 64, render3d_st.gg_n)
gpu_dispatch_tex(render3d_st, render3d_st.gg_cull, data_of(pr), 304, bufs, texs, (render3d_st.gg_max + 63) / 64, render3d_st.gg_n)
}
# the page pool's four, after the three whole-map ones (the stand-ins while paging is off)
@ -148,10 +150,10 @@ function gg_page_texs(render3d_st: mut Render3dState, texs: words) -> void {
if render3d_st.tp_on { texs[3] = render3d_st.tp_page_tex; texs[4] = render3d_st.tp_h_tex; texs[5] = render3d_st.tp_n_tex; texs[6] = render3d_st.tp_o_tex }
}
# grass_cull.comp's Params, std140: 18 vec4s, into the block made once with the device
# grass_cull.comp's Params, std140: 19 vec4s, into the block made once with the device
function gg_params(render3d_st: mut Render3dState) -> words {
let pr = render3d_st.gg_pr
for i in 0 .. 72 { pr[i] = 0 }
for i in 0 .. 76 { pr[i] = 0 }
if render3d_st.cam_planes != null { for i in 0 .. 16 { pr[i] = float_bits(render3d_st.cam_planes[i]) } }
pr[16] = float_bits(render3d_st.cam_pos[0]); pr[17] = float_bits(render3d_st.cam_pos[1]); pr[18] = float_bits(render3d_st.cam_pos[2]); pr[19] = float_bits(grass_reach(render3d_st))
var ph = render3d_st.post_h
@ -171,6 +173,7 @@ function gg_params(render3d_st: mut Render3dState) -> words {
# the page pool (terrain_pages.ludic): on in lev.w, and its dims as the terrain's shaders take them
if render3d_st.tp_on { pr[31] = float_bits(1.0) }
pr[48] = float_bits(float(render3d_st.tt_n)); pr[49] = float_bits(float(TT_TEX)); pr[50] = float_bits(float(render3d_st.tt_oside)); pr[51] = float_bits(float(TERRAIN_RES))
gb_params(render3d_st, pr)
return pr
}