From 411ee8b4850931504f9ab7653115a8437369850b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Feb 2026 18:38:45 -0800 Subject: [PATCH] Fix WMO instance duplication causing 16x Stormwind rendering Added deduplication for WMO instances based on uniqueId, matching the existing M2 doodad deduplication logic. This prevents creating multiple instances of the same WMO when it's referenced from multiple ADT tiles. Before: STORMWIND.WMO (uniqueId=10047) was being rendered 16 times (one instance per ADT tile that references it) After: Only 1 instance is created and shared across all tiles Changes: - Added placedWmoIds set to TerrainManager (like placedDoodadIds) - Check uniqueId before creating WMO instance - Skip duplicate WMO placements across tile boundaries - Log dedup statistics: 'X instances, Y dedup skipped' This should fix the floating cathedral visual issue if it was caused by rendering artifacts from 16x overdraw, and will massively improve performance in Stormwind. --- include/rendering/terrain_manager.hpp | 3 +++ src/rendering/terrain_manager.cpp | 13 +++++++++++++ 2 files changed, 16 insertions(+) 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); }