Optimize WMO rendering and collision performance

- Add texture-sorted batch merging with glMultiDrawElements to reduce draw calls
- Pre-compute merged batches at load time instead of per-frame
- Add persistent floor height cache with disk save/load (cache/wmo_floor_cache.bin)
- Reduce collision focus radius and sweep steps for faster collision checks
- Add floor cache size to performance HUD
- Reduce WMO group distance culling to 80 units
This commit is contained in:
Kelsi 2026-02-05 17:20:30 -08:00
parent f69556b83e
commit 01de332d4c
7 changed files with 229 additions and 40 deletions

View file

@ -106,8 +106,8 @@ private:
static constexpr float PIVOT_HEIGHT = 1.8f; // Pivot at head height
static constexpr float CAM_SPHERE_RADIUS = 0.32f; // Keep camera farther from geometry to avoid clipping-through surfaces
static constexpr float CAM_EPSILON = 0.22f; // Extra wall offset to avoid near-plane clipping artifacts
static constexpr float COLLISION_FOCUS_RADIUS_THIRD_PERSON = 42.0f;
static constexpr float COLLISION_FOCUS_RADIUS_FREE_FLY = 34.0f;
static constexpr float COLLISION_FOCUS_RADIUS_THIRD_PERSON = 20.0f; // Reduced for performance
static constexpr float COLLISION_FOCUS_RADIUS_FREE_FLY = 20.0f;
static constexpr float MIN_PITCH = -88.0f; // Look almost straight down
static constexpr float MAX_PITCH = 35.0f; // Limited upward look
glm::vec3* followTarget = nullptr;

View file

@ -222,6 +222,11 @@ public:
double getQueryTimeMs() const { return queryTimeMs; }
uint32_t getQueryCallCount() const { return queryCallCount; }
// Floor cache persistence
bool saveFloorCache(const std::string& filepath) const;
bool loadFloorCache(const std::string& filepath);
size_t getFloorCacheSize() const { return precomputedFloorGrid.size(); }
private:
/**
* WMO group GPU resources
@ -243,6 +248,16 @@ private:
};
std::vector<Batch> batches;
// Pre-merged batches for efficient rendering (computed at load time)
struct MergedBatch {
GLuint texId;
bool hasTexture;
bool alphaTest;
std::vector<GLsizei> counts;
std::vector<const void*> offsets;
};
std::vector<MergedBatch> mergedBatches;
// Collision geometry (positions only, for floor raycasting)
std::vector<glm::vec3> collisionVertices;
std::vector<uint16_t> collisionIndices;
@ -472,6 +487,22 @@ private:
// Collision query profiling (per frame).
mutable double queryTimeMs = 0.0;
mutable uint32_t queryCallCount = 0;
// Floor height cache - persistent precomputed grid
static constexpr float FLOOR_GRID_CELL_SIZE = 2.0f; // 2 unit grid cells
mutable std::unordered_map<uint64_t, float> precomputedFloorGrid; // key -> floor height
mutable bool floorGridDirty = true; // Rebuild when instances change
mutable uint32_t currentFrameId = 0;
uint64_t floorGridKey(float x, float y) const {
int32_t ix = static_cast<int32_t>(std::floor(x / FLOOR_GRID_CELL_SIZE));
int32_t iy = static_cast<int32_t>(std::floor(y / FLOOR_GRID_CELL_SIZE));
return (static_cast<uint64_t>(static_cast<uint32_t>(ix)) << 32) |
static_cast<uint64_t>(static_cast<uint32_t>(iy));
}
// Compute floor height for a single cell (expensive, done at load time)
std::optional<float> computeFloorHeightSlow(float x, float y, float refZ) const;
};
} // namespace rendering