From 7765b4161199f7d5768c80cb37a60e432808adc3 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sun, 8 Feb 2026 20:33:40 -0800 Subject: [PATCH] Disable WMO floor cache and add camera collision with WMO/M2 Disabled persistent WMO floor grid cache - it stored one height per 2-unit cell causing fall-through at stairs where floor height changes within a cell. Per-frame dedup cache is sufficient for performance. Added camera raycast collision against WMO walls (when inside) and M2 objects to zoom in when camera would clip through geometry instead of phasing through walls. --- src/rendering/camera_controller.cpp | 26 ++++++++++++++++++++++++-- src/rendering/wmo_renderer.cpp | 18 ++---------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/rendering/camera_controller.cpp b/src/rendering/camera_controller.cpp index 2c6c5b18..56301d5a 100644 --- a/src/rendering/camera_controller.cpp +++ b/src/rendering/camera_controller.cpp @@ -641,8 +641,30 @@ void CameraController::update(float deltaTime) { // Find max safe distance using raycast + sphere radius collisionDistance = currentDistance; - // Camera collision: terrain-only floor clamping (skip expensive WMO raycasts). - // The camera may clip through WMO walls but won't go underground. + // WMO raycast collision: zoom in when camera would clip through walls + if (wmoRenderer && cachedInsideWMO && currentDistance > MIN_DISTANCE) { + glm::vec3 camRayOrigin = pivot; + glm::vec3 camRayDir = camDir; + float wmoHitDist = wmoRenderer->raycastBoundingBoxes(camRayOrigin, camRayDir, currentDistance); + if (wmoHitDist < currentDistance) { + // Hit WMO geometry — pull camera in to avoid clipping + constexpr float CAM_RADIUS = 0.3f; + collisionDistance = std::max(MIN_DISTANCE, wmoHitDist - CAM_RADIUS); + } + } + + // M2 raycast collision: zoom in when camera would clip through doodads + if (m2Renderer && currentDistance > MIN_DISTANCE) { + glm::vec3 camRayOrigin = pivot; + glm::vec3 camRayDir = camDir; + float m2HitDist = m2Renderer->raycastBoundingBoxes(camRayOrigin, camRayDir, currentDistance); + if (m2HitDist < collisionDistance) { + constexpr float CAM_RADIUS = 0.3f; + collisionDistance = std::max(MIN_DISTANCE, m2HitDist - CAM_RADIUS); + } + } + + // Camera collision: terrain-only floor clamping auto getTerrainFloorAt = [&](float x, float y) -> std::optional { if (terrainManager) { return terrainManager->getHeightAt(x, y); diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index 50684cd7..72fc2a76 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -1743,22 +1743,8 @@ std::optional WMORenderer::getFloorHeight(float glX, float glY, float glZ auto frameCached = frameFloorCache_.get(glX, glY, currentFrameId, outNormalZ); if (frameCached) return *frameCached; - // Check persistent grid cache first (computed lazily, never expires) - uint64_t gridKey = floorGridKey(glX, glY); - auto gridIt = precomputedFloorGrid.find(gridKey); - if (gridIt != precomputedFloorGrid.end()) { - float cachedHeight = gridIt->second; - // Only trust cache if it's basically at foot level. - // Reject cache if it's too high above us (prevents stair landing from overriding approach floor) - constexpr float CACHE_ABOVE = 0.25f; // tight above threshold (prevents stair landing cache hit) - constexpr float CACHE_BELOW = 4.0f; // keep generous below - if (cachedHeight <= glZ + CACHE_ABOVE && cachedHeight >= glZ - CACHE_BELOW) { - // Persistent cache doesn't store normal — report as flat - if (outNormalZ) *outNormalZ = 0.8f; // conservative "walkable-ish" - frameFloorCache_.put(glX, glY, cachedHeight, 1.0f, currentFrameId); - return cachedHeight; - } - } + // Persistent grid cache disabled - causes fall-through at stairs where + // one 2-unit cell contains multiple floor heights. Per-frame cache is sufficient. QueryTimer timer(&queryTimeMs, &queryCallCount); std::optional bestFloor;