Improve runtime stutter handling and ground clutter performance

- reduce per-tile ground clutter generation pressure and enforce tighter caps to avoid spikes

- remove expensive detail dedupe scans from the hot render path

- add progressive/lazy clutter updates around player movement to smooth frame pacing

- lower noisy runtime INFO logging to DEBUG/throttled paths

- keep terrain/game screen updates responsive while preserving existing behavior
This commit is contained in:
Kelsi 2026-02-21 01:26:16 -08:00
parent c04e97e375
commit 1003b25ff4
11 changed files with 714 additions and 116 deletions

View file

@ -65,6 +65,7 @@ struct M2ModelGPU {
bool collisionStatue = false;
bool isSmallFoliage = false; // Small foliage (bushes, grass, plants) - skip during taxi
bool isInvisibleTrap = false; // Invisible trap objects (don't render, no collision)
bool isGroundDetail = false; // Ground clutter/detail doodads (special fallback render path)
// Collision mesh with spatial grid (from M2 bounding geometry)
struct CollisionMesh {

View file

@ -19,6 +19,7 @@
#include <condition_variable>
#include <deque>
#include <glm/glm.hpp>
#include <array>
namespace wowee {
@ -191,6 +192,8 @@ public:
void setStreamingEnabled(bool enabled) { streamingEnabled = enabled; }
void setUpdateInterval(float seconds) { updateInterval = seconds; }
void setTaxiStreamingMode(bool enabled) { taxiStreamingMode_ = enabled; }
void setGroundClutterDensityScale(float scale) { groundClutterDensityScale_ = glm::clamp(scale, 0.0f, 1.5f); }
float getGroundClutterDensityScale() const { return groundClutterDensityScale_; }
void setWaterRenderer(WaterRenderer* renderer) { waterRenderer = renderer; }
void setM2Renderer(M2Renderer* renderer) { m2Renderer = renderer; }
void setWMORenderer(WMORenderer* renderer) { wmoRenderer = renderer; }
@ -264,6 +267,9 @@ private:
* Main thread: poll for completed tiles and upload to GPU
*/
void processReadyTiles();
void ensureGroundEffectTablesLoaded();
void generateGroundClutterPlacements(std::shared_ptr<PendingTile>& pending,
std::unordered_set<uint32_t>& preparedModelIds);
pipeline::AssetManager* assetManager = nullptr;
TerrainRenderer* terrainRenderer = nullptr;
@ -345,6 +351,16 @@ private:
static constexpr int MAX_M2_UPLOADS_PER_FRAME = 5; // Upload up to 5 models per frame
void processM2UploadQueue();
struct GroundEffectEntry {
std::array<uint32_t, 4> doodadIds{{0, 0, 0, 0}};
std::array<uint32_t, 4> weights{{0, 0, 0, 0}};
uint32_t density = 0;
};
bool groundEffectsLoaded_ = false;
std::unordered_map<uint32_t, GroundEffectEntry> groundEffectById_; // effectId -> config
std::unordered_map<uint32_t, std::string> groundDoodadModelById_; // doodadId -> model path
float groundClutterDensityScale_ = 1.0f;
};
} // namespace rendering

View file

@ -101,6 +101,7 @@ private:
bool pendingSeparateBags = true;
bool pendingAutoLoot = false;
bool pendingUseOriginalSoundtrack = true;
int pendingGroundClutterDensity = 100;
// UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)
float uiOpacity_ = 0.65f;