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
|
|
@ -36,7 +36,7 @@ property Layer {
|
|||
last_cam: floats,
|
||||
rough: float = 0.0,
|
||||
blade: bool = false,
|
||||
grass: bool = false, # ground-cover grass the game may hand to the GPU blades (R3D_NOGRASS skips it)
|
||||
grass: bool = false, # ground cover the GPU blades replace: skipped while they draw (and under R3D_NOGRASS)
|
||||
flower: bool = false,
|
||||
card: bool = false,
|
||||
cheap: bool = false, # distant cover: no shadows, no wind, flat lighting
|
||||
|
|
@ -1135,7 +1135,7 @@ function scatter_draw_depth(render3d_st: mut Render3dState) -> void {
|
|||
for i in 0 .. len(render3d_st.sc_layers) {
|
||||
let l = render3d_st.sc_layers[i]
|
||||
if not l.foliage or l.blade or l.flower { continue }
|
||||
if render3d_st.sc_skip_grass and l.grass { continue }
|
||||
if l.grass and sc_grass_replaced(render3d_st) { continue }
|
||||
if render3d_st.r3d_no_trees and l.imp != null { continue }
|
||||
layer_update(render3d_st, l)
|
||||
if l.n_lods > 1 and l.g_on {
|
||||
|
|
@ -1151,13 +1151,15 @@ function scatter_draw_depth(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
gpu_cull(render3d_st, true)
|
||||
}
|
||||
# a layer the game flagged `grass` is ground cover the GPU blades stand in for: off while they draw
|
||||
function sc_grass_replaced(render3d_st: Render3dState) -> bool { return render3d_st.sc_skip_grass or ((render3d_st.grass_on or render3d_st.grass_force) and not render3d_st.grass_env_off and render3d_st.grass_prog != 0) }
|
||||
function scatter_draw(render3d_st: mut Render3dState) -> void {
|
||||
for i in 0 .. len(render3d_st.sc_layers) {
|
||||
let l = render3d_st.sc_layers[i]
|
||||
if render3d_st.sc_skip_blade and l.blade { continue }
|
||||
if render3d_st.sc_skip_flower and l.flower { continue }
|
||||
if render3d_st.sc_skip_card and l.card { continue }
|
||||
if render3d_st.sc_skip_grass and l.grass { continue }
|
||||
if l.grass and sc_grass_replaced(render3d_st) { continue }
|
||||
if render3d_st.r3d_no_trees and l.imp != null and not l.card { continue }
|
||||
layer_update(render3d_st, l)
|
||||
layer_draw_near(render3d_st, l, false, null, false)
|
||||
|
|
@ -1175,7 +1177,7 @@ function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats)
|
|||
let l = render3d_st.sc_layers[i]
|
||||
if render3d_st.sc_skip_blade and l.blade { continue }
|
||||
if render3d_st.sc_skip_card and l.card { continue }
|
||||
if render3d_st.sc_skip_grass and l.grass { continue }
|
||||
if l.grass and sc_grass_replaced(render3d_st) { continue }
|
||||
if render3d_st.r3d_no_trees and l.imp != null and not l.card { continue }
|
||||
layer_update(render3d_st, l)
|
||||
if l.imp != null {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue