render3d: the reflection draws an actor when its mirror image is in view; reflection CPU in R3D_PROF

The water reflection keeps the main camera's frustum planes, and ac_visible tested the actor itself
against them: the town's people, far above the lake with their images far below the frame, all drew
again. The image (2L - y) is what is tested now - town, 69 skinned reflection draws -> 38, the frame
byte-identical; PC camp reflection scene CPU 793 -> about 760 us. R3D_PROF splits the reflection's
CPU into setup, terrain, scene and sky.

Tried and not kept, with the numbers (PC, camp, Vulkan GPU timestamps):
- the ground's cost is its scanned material taps: without them the terrain pass is 555 us of 1568,
  without the photograph 1029; the sun, the noise fields and the grain are 20-100 us each. Moving the
  cheap tier in from 200 m to 60 m changes nothing, so it is the far tier's single taps over the
  mountains. Skipping the normal-map taps past 900 m (where the detail normal is fully faded) saved
  22 us and moved a few pixels - reverted.
- grass: cutting its radius to 300 m barely moves it, so the cost is the near blades' pixels; moving
  their three noise fields to the vertices changed nothing (747 us) - reverted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-15 18:25:05 +03:00
parent 5b9403c343
commit fd750f3588
2 changed files with 11 additions and 1 deletions

View file

@ -152,7 +152,13 @@ function ac_visible(a: Actor, shadow: bool) -> bool {
}
if not shadow and a.radius != 0 {
let r = f_mul(a.radius, a.scale)
if not cam_sphere_visible(a.x, f_add(a.y, r), a.z, f_mul(r, fl(1.5))) { return false }
var cy = f_add(a.y, r)
# In the water reflection what reaches the picture is the actor's mirror image, 2L - y. The pass
# keeps the main camera's frustum planes, so the image is what has to be tested against them: the
# actor itself was, and the town's people - far above the lake, their images far below the frame -
# all drew again into the reflection.
if ter_reflect { cy = f_sub(f_mul(F_TWO, water_level), cy) }
if not cam_sphere_visible(a.x, cy, a.z, f_mul(r, fl(1.5))) { return false }
}
return true
}

View file

@ -78,9 +78,13 @@ function water_reflection_pass() -> void {
let sb = sc_skip_blade
sc_skip_blade = true # blades are invisible at this scale in a reflection
ter_reflect = true
prof_cpu_mark("reflection setup")
terrain_draw()
prof_cpu_mark("reflection terrain")
scene_draw()
prof_cpu_mark("reflection scene")
r3d_draw_sky()
prof_cpu_mark("reflection sky")
ter_reflect = false
sc_skip_blade = sb
sc_freeze = false