test(engine-math): pin intersectsChunkRelative camera-relative semantics (#741) - #781
Conversation
Audit issue #741 claimed intersectsChunkRelative miscalculates the chunk bounding-sphere center (world_y = -cam_y) and proposed anchoring world_y to 0. The report conflated world space with camera-relative space: the renderer builds the terrain view-projection from Camera.getViewMatrixOriginCentered (rotation only) and draws chunks via model matrices that subtract camera_pos, so the culling frustum lives in camera-relative space. In that space center.y = (CHUNK_SIZE_Y * 0.5) - cam_y is exactly the chunk's vertical center, and the sphere of radius 144 fully contains every chunk corner for any camera height. The proposed 'fix' would detach the sphere from the camera and cull terrain whenever the camera is high above the world (it also breaks the existing y=80 test). No production change. Add regression tests that lock in the correct behavior and fail under the proposed change: - forward view sees the chunk ahead for cam_y in {0, 80, 128, 200, 256} - camera looking down at a chunk from high above (y=600, 200) still sees it - property test: intersectsChunkRelative reports visible whenever an independent circumscribed sphere (radius sqrt(8^2+128^2+8^2) ~= 128.5) centered at the camera-relative chunk center does, across forward/down/ up/angled frustums, multiple camera heights, and chunk/cam offsets.
📋 SummaryThis PR addresses issue #741, which claimed The implementation fully satisfies the issue's acceptance criteria: it verifies correct culling across camera heights, confirms the sphere contains the full chunk column, and all tests pass. 📌 Review Metadata
🔴 Critical Issues (Must Fix - Blocks Merge)None identified.
|
| Principle | Score | Notes |
|---|---|---|
| Single Responsibility | 9 | Tests are focused solely on frustum/chunk intersection semantics. |
| Open/Closed | 8 | Extends test coverage without modifying production behavior. |
| Liskov Substitution | N/A | No inheritance hierarchies involved. |
| Interface Segregation | N/A | No interfaces introduced. |
| Dependency Reversal | 8 | Uses existing public Frustum/Mat4/Vec3 APIs. |
| Average | 8.3 |
🎯 Final Assessment
Overall Confidence Score: 95%
Confidence Breakdown:
- Code Quality: 95% — Clean, well-commented tests with clear intent and correct math.
- Completeness: 95% — Covers acceptance criteria and refutes the audit claim with a property test.
- Risk Level: 5% — Test-only change; no production behavior altered.
- Test Coverage: 100% — Adds three targeted regression tests; all pass.
Merge Readiness:
- All critical issues resolved
- SOLID average score >= 6.0
- Overall confidence >= 60%
- No security concerns
- Tests present and passing (if applicable)
Verdict:
MERGE — Test-only regression coverage is correct, well-reasoned, and all tests pass.
{
"reviewed_sha": "4b7113196f089854bc1a2c80e3a6299a689d888f",
"critical_issues": 0,
"high_priority_issues": 0,
"medium_priority_issues": 0,
"overall_confidence_score": 95,
"recommendation": "MERGE"
}
Summary
Closes #741.
Investigation result: the reported bug does not exist. The audit concluded that
intersectsChunkRelative(libs/zig-math/frustum.zig:118) miscalculates the bounding-sphere center (world_y = -cam_y) and proposed anchoringworld_y = 0. That analysis conflated world space with camera-relative space.Why the current code is correct
The renderer uses camera-relative (floating-origin) rendering:
Camera.getViewMatrixOriginCentered—Mat4.lookAt(Vec3.zero, forward, up), rotation only (modules/engine-graphics/src/camera.zig:203, consumed atmodules/engine-graphics/src/render_graph.zig:464).chunk_world − camera_pos(modules/world-runtime/src/world_renderer.zig:334,:456,:660).So the frustum handed to
intersectsChunkRelativelives in camera-relative space (apex at origin). In that space the chunk spansy ∈ [−cam_y, 256 − cam_y], and its vertical center is(CHUNK_SIZE_Y * 0.5) − cam_y = 128 − cam_y— exactly what the function computes (-cam_y + 128).The audit's
cam_y = 80example: the sphere coversy ∈ [−96, 192]in camera-relative space, which isy ∈ [−16, 272]in world space — fully containing the chunk'sy ∈ [0, 256]. The camera-y offset cancels between the sphere center and the chunk corners, so the sphere contains every chunk corner for any camera height. Theradius = 144is a deliberate conservative bound (true circumscribed radius is√(8² + 128² + 8²) ≈ 128.5).Why the proposed fix is harmful
Setting
world_y = 0would anchor the sphere's center at camera-relativey = 128regardless of camera height. When the camera is high above terrain, the chunk's true camera-relative center is far below (e.g.−472atcam_y = 600), but the "fixed" sphere would sit ~cam_yunits above the view axis and cull terrain that is actually in front of the camera. It also makescam_yan unused parameter (compile error) and breaks the existingFrustum forward view at y=80 sees all nearby chunkstest.Changes
No production change. Added regression tests in
src/math_tests.zig(the root-module test file that is actually collected byzig build test; note the inline tests inlibs/zig-math/frustum.zigandmodules/engine-math/src/frustum_tests.zigare not collected by the build):Frustum forward view sees chunk ahead across camera heights— the chunk straight ahead is visible forcam_y ∈ {0, 80, 128, 200, 256}(issue acceptance criterion Roadmapv3 #1).Frustum looking down at chunk from high camera still sees it— a camera aty = 600(andy = 200) aimed straight at a chunk still sees it. This directly refutes the "missing terrain when camera is high" claim and fails if the sphere is detached from the camera (verified: fails under the proposedworld_y = 0change).Frustum intersectsChunkRelative matches independent circumscribed sphere— for a battery of forward/down/up/angled frustums, multiple camera heights, and chunk/camera offsets, the function reports visible whenever an independently-derived circumscribed sphere (radius≈ 128.5) at the camera-relative chunk center does. This verifies the sphere contains the full chunk (all 256 Y levels) and would fail if the center drifted out of camera-relative space.Verification
`zig build test` — 275/275 pass (was 272; +3 new tests).
Confirmed the new tests are effective guards by temporarily applying the proposed buggy change (
world_y = 0): the suite then fails with 2 failures — the pre-existingy=80test plus the newlooking down at chunk from high cameratest. Reverted afterward; final tree is pristine production code + tests only.Acceptance criteria
intersectsChunkRelativecorrectly culls chunks when camera is at various heights (y=0, 80, 200, 256)