Ticket 014 V6/V7/V12/V13 — invalidate WSRC cascades on camera travel OR meaningful lighting change. V13 runs the V12 hysteresis checks per cascade, so a sun rotation or camera shift only rebakes the affected cascade(s). Typical pattern: camera moves 10 m → near cascade (1.875 m cell, ~0.47 m threshold) rebakes every few frames, mid cascade (7.5 m cell, ~1.9 m threshold) rebakes occasionally, far c
(&mut self)
| 6976 | /// cascade (31 m cell, ~7.8 m threshold) stays cached for |
| 6977 | /// much longer. |
| 6978 | fn maybe_invalidate_wsrc(&mut self) { |
| 6979 | let cam = self.current_camera_world_pos(); |
| 6980 | let ld = self.lighting_uniforms.light_dir; |
| 6981 | let lc = self.lighting_uniforms.light_color; |
| 6982 | let amb = self.lighting_uniforms.ambient; |
| 6983 | let cur_sun_color = [lc[0] * ld[3], lc[1] * ld[3], lc[2] * ld[3]]; |
| 6984 | let cur_sky_color = [amb[0] * amb[3], amb[1] * amb[3], amb[2] * amb[3]]; |
| 6985 | |
| 6986 | fn luma(c: [f32; 3]) -> f32 { |
| 6987 | c[0] * 0.2126 + c[1] * 0.7152 + c[2] * 0.0722 |
| 6988 | } |
| 6989 | fn rel_diff(a: f32, b: f32) -> f32 { |
| 6990 | (a - b).abs() / a.max(b).max(1e-4) |
| 6991 | } |
| 6992 | |
| 6993 | for c in 0..WSRC_CASCADE_COUNT as usize { |
| 6994 | if !self.wsrc_built[c] { |
| 6995 | continue; |
| 6996 | } |
| 6997 | // Camera travel — per-cascade threshold scales with the |
| 6998 | // cascade's extent, so each cascade has its own |
| 6999 | // "moved enough" metric. |
| 7000 | let extent = WSRC_CASCADE_EXTENTS[c]; |
| 7001 | let origin = self.wsrc_origin[c]; |
| 7002 | let dx = cam[0] - origin[0]; |
| 7003 | let dy = cam[1] - origin[1]; |
| 7004 | let dz = cam[2] - origin[2]; |
| 7005 | let dist_sq = dx * dx + dy * dy + dz * dz; |
| 7006 | let threshold = extent * WSRC_REBAKE_THRESHOLD; |
| 7007 | if dist_sq > threshold * threshold { |
| 7008 | self.wsrc_built[c] = false; |
| 7009 | continue; |
| 7010 | } |
| 7011 | |
| 7012 | // V12 hysteresis — angular sun + 5% relative luma. |
| 7013 | let last = self.wsrc_last_sun_dir[c]; |
| 7014 | let sun_dot = ld[0] * last[0] + ld[1] * last[1] + ld[2] * last[2]; |
| 7015 | if sun_dot < 0.99985 { |
| 7016 | self.wsrc_built[c] = false; |
| 7017 | continue; |
| 7018 | } |
| 7019 | if rel_diff(luma(cur_sun_color), luma(self.wsrc_last_sun_color[c])) > 0.05 { |
| 7020 | self.wsrc_built[c] = false; |
| 7021 | continue; |
| 7022 | } |
| 7023 | if rel_diff(luma(cur_sky_color), luma(self.wsrc_last_sky_color[c])) > 0.05 { |
| 7024 | self.wsrc_built[c] = false; |
| 7025 | } |
| 7026 | } |
| 7027 | } |
| 7028 | |
| 7029 | /// Ticket 014 V6 — bake the world-space radiance cache. One |
| 7030 | /// dispatch covers all `WSRC_GRID_RES³` probes × 64 octel texels. |
no test coverage detected