render3d: the water reflection runs only when mirrored water can be on screen; an actor census
The reflection pass is a second copy of the terrain, the vegetation and the actors, and it ran on every frame of a map with water - looking straight down at a meadow included. The mirrored body is cut into rectangles where the ground lies below it (32 m over the height map in 8 x 8 blocks, the sea beyond it coarse), and the pass runs when one meets the view frustum and its water is not all dry where it shows, outside the frame or behind the ground. Three wrong turns on the way, each kept in a comment: bounding spheres (a 156 m cell reached into the view from behind the camera), sight lines that never asked whether the point was in the frame, and a walk of every rectangle every frame (0.1 s per 400 frames on the PC until the blocks). Built once in 6.6 ms. Mac, the five shot viewpoints: view c (the meadow) 225 reflection draws -> none; a, b, d, e unchanged; OpenGL frames byte-identical; self-tests 59/59 on OpenGL and Vulkan; MoltenVK validation adds nothing. PC camp (lake in view): 1882 draws either way, 3.8 s for 400 frames either way, three runs each, self-tests 59/59, validation 0. R3D_REFL_ALWAYS=1 runs the pass every frame; R3D_REFL_DBG=1 prints the test once. R3D_ACTOR_CENSUS=<frame> prints the lit pass's actors grouped by model: town is 17 models and 69 draws, and only four rigid models repeat (17 actors) - too little for instancing to be worth a shader variant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
44ecd55a86
commit
ef745a141d
3 changed files with 212 additions and 1 deletions
|
|
@ -236,9 +236,40 @@ function outline_clear() -> void { ac_oq_n = 0; ac_oq_closed = true }
|
|||
# highlighted tree left its rim on until something else was highlighted.
|
||||
function outline_frame() -> void { if ac_oq_closed { ac_oq_n = 0 } }
|
||||
|
||||
# R3D_ACTOR_CENSUS=<frame>: at that frame, the lit pass's actors grouped by model - skinned or rigid,
|
||||
# how many share it, the primitives each draws - so instancing is aimed at what repeats
|
||||
function actor_census() -> void {
|
||||
let keys = new []Model
|
||||
let cnt = new []int
|
||||
let prims = new []int
|
||||
let rigid = new []int
|
||||
for i in 0 .. len(ac_actors) {
|
||||
let a = ac_actors[i]
|
||||
if not ac_visible(a, false) { continue }
|
||||
var k = -1
|
||||
for j in 0 .. len(keys) { if keys[j] == a.model { k = j } }
|
||||
if k < 0 { push(keys, a.model); push(cnt, 0); push(prims, 0); var r = 1; if a.model.skin != null { r = 0 }; push(rigid, r); k = len(keys) - 1 }
|
||||
if a.skin != null { rigid[k] = 0 }
|
||||
cnt[k] += 1
|
||||
var shown = 0
|
||||
for p in 0 .. len(a.model.prims) { if a.hide == null or a.hide[p] == 0 { shown += 1 } }
|
||||
prims[k] += shown
|
||||
}
|
||||
var total = 0
|
||||
for j in 0 .. len(keys) {
|
||||
var kind = "skinned"
|
||||
if rigid[j] == 1 { kind = "rigid" }
|
||||
print(`actor census: model {j} ({kind}, {len(keys[j].prims)} prims, {keys[j].tris} tris): {cnt[j]} actors, {prims[j]} draws`)
|
||||
total += prims[j]
|
||||
}
|
||||
print(`actor census: {len(keys)} models, {total} lit draws`)
|
||||
}
|
||||
var ac_census_at: int = -2
|
||||
function actor_draw() -> void {
|
||||
if ac_actors == null { return }
|
||||
ac_frame += 1
|
||||
if ac_census_at == -2 { ac_census_at = -1; if Os.has_env("R3D_ACTOR_CENSUS") { ac_census_at = Text.to_int(Os.env("R3D_ACTOR_CENSUS")) } }
|
||||
if ac_census_at > 0 and ac_frame == ac_census_at { actor_census() }
|
||||
for i in 0 .. len(ac_actors) {
|
||||
let a = ac_actors[i]
|
||||
if not ac_visible(a, false) { continue }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue