diff --git a/include/rendering/terrain_manager.hpp b/include/rendering/terrain_manager.hpp index e4562537..06215fe7 100644 --- a/include/rendering/terrain_manager.hpp +++ b/include/rendering/terrain_manager.hpp @@ -323,6 +323,9 @@ private: // Dedup set for doodad placements across tile boundaries std::unordered_set placedDoodadIds; + + // Dedup set for WMO placements across tile boundaries (prevents rendering Stormwind 16x) + std::unordered_set placedWmoIds; }; } // namespace rendering diff --git a/src/rendering/terrain_manager.cpp b/src/rendering/terrain_manager.cpp index a4c97871..ed28217e 100644 --- a/src/rendering/terrain_manager.cpp +++ b/src/rendering/terrain_manager.cpp @@ -683,11 +683,20 @@ void TerrainManager::finalizeTile(const std::shared_ptr& pending) { int loadedWMOs = 0; int loadedLiquids = 0; + int skippedWmoDedup = 0; for (auto& wmoReady : pending->wmoModels) { + // Deduplicate WMO instances by uniqueId (prevents Stormwind from rendering 16x) + // uniqueId is stored in modelId field (see line 522 in prepareTile) + if (placedWmoIds.count(wmoReady.modelId)) { + skippedWmoDedup++; + continue; + } + if (wmoRenderer->loadModel(wmoReady.model, wmoReady.modelId)) { uint32_t wmoInstId = wmoRenderer->createInstance(wmoReady.modelId, wmoReady.position, wmoReady.rotation); if (wmoInstId) { wmoInstanceIds.push_back(wmoInstId); + placedWmoIds.insert(wmoReady.modelId); loadedWMOs++; // Load WMO liquids (canals, pools, etc.) @@ -710,6 +719,10 @@ void TerrainManager::finalizeTile(const std::shared_ptr& pending) { } } } + if (loadedWMOs > 0 || skippedWmoDedup > 0) { + LOG_INFO(" Loaded WMOs for tile [", x, ",", y, "]: ", + loadedWMOs, " instances, ", skippedWmoDedup, " dedup skipped"); + } if (loadedLiquids > 0) { LOG_DEBUG(" Loaded WMO liquids for tile [", x, ",", y, "]: ", loadedLiquids); }