From 2c5b7cd368dc5ce03c3bcca1a6f546542862093c Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 6 Mar 2026 23:48:35 -0800 Subject: [PATCH] WMO glass transparency for instances, disable interior shadows - Add case-insensitive "glass" detection for WMO window materials - Make instance (WMO-only) glass highly transparent (12-35% alpha) so underwater scenes are visible through Deeprun Tram windows - Keep normal world windows at existing opacity (40-95% alpha) - Disable shadow mapping for interior WMO groups to fix dark indoor areas like Ironforge --- assets/shaders/wmo.frag.glsl | 11 ++++++++--- include/rendering/wmo_renderer.hpp | 2 ++ src/core/application.cpp | 4 +++- src/rendering/wmo_renderer.cpp | 13 ++++++++++--- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/assets/shaders/wmo.frag.glsl b/assets/shaders/wmo.frag.glsl index dbd55436..b8db595d 100644 --- a/assets/shaders/wmo.frag.glsl +++ b/assets/shaders/wmo.frag.glsl @@ -152,9 +152,9 @@ void main() { vec3 result; - // Sample shadow map for all non-window WMO surfaces + // Sample shadow map — skip for interior WMO groups (no sun indoors) float shadow = 1.0; - if (shadowParams.x > 0.5) { + if (shadowParams.x > 0.5 && isInterior == 0) { vec3 ldir = normalize(-lightDir.xyz); float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir))); vec3 biasedPos = FragPos + norm * normalOffset; @@ -219,7 +219,12 @@ void main() { glass += specBroad * lightColor.rgb * 0.12; result = glass; - alpha = mix(0.4, 0.95, NdotV); + if (isWindow == 2) { + // Instance/dungeon glass: mostly transparent to see through + alpha = mix(0.12, 0.35, fresnel); + } else { + alpha = mix(0.4, 0.95, NdotV); + } } outColor = vec4(result, alpha); diff --git a/include/rendering/wmo_renderer.hpp b/include/rendering/wmo_renderer.hpp index 4587d0b7..5c928571 100644 --- a/include/rendering/wmo_renderer.hpp +++ b/include/rendering/wmo_renderer.hpp @@ -196,6 +196,7 @@ public: void setNormalMapStrength(float s) { normalMapStrength_ = s; materialSettingsDirty_ = true; } void setPOMEnabled(bool enabled) { pomEnabled_ = enabled; materialSettingsDirty_ = true; } void setPOMQuality(int q) { pomQuality_ = q; materialSettingsDirty_ = true; } + void setWMOOnlyMap(bool v) { wmoOnlyMap_ = v; materialSettingsDirty_ = true; } bool isNormalMappingEnabled() const { return normalMappingEnabled_; } float getNormalMapStrength() const { return normalMapStrength_; } bool isPOMEnabled() const { return pomEnabled_; } @@ -670,6 +671,7 @@ private: bool pomEnabled_ = true; // on by default int pomQuality_ = 1; // 0=Low(16), 1=Medium(32), 2=High(64) bool materialSettingsDirty_ = false; // rebuild UBOs when settings change + bool wmoOnlyMap_ = false; // true for dungeon/instance WMO-only maps // Rendering state bool wireframeMode = false; diff --git a/src/core/application.cpp b/src/core/application.cpp index 3310c406..2a8ef041 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -3525,9 +3525,10 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float renderer->getCameraController()->reset(); } - // Set map name for WMO renderer + // Set map name for WMO renderer and reset instance mode if (renderer->getWMORenderer()) { renderer->getWMORenderer()->setMapName(mapName); + renderer->getWMORenderer()->setWMOOnlyMap(false); } // Set map name for terrain manager @@ -3634,6 +3635,7 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float // Set map name on WMO renderer and disable terrain streaming (no ADT tiles for instances) if (renderer->getWMORenderer()) { renderer->getWMORenderer()->setMapName(mapName); + renderer->getWMORenderer()->setWMOOnlyMap(true); } if (renderer->getTerrainManager()) { renderer->getTerrainManager()->setStreamingEnabled(false); diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index 6fe36a41..5bae174f 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -593,16 +593,23 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) { // Detect window/glass materials by texture name. // Flag 0x10 (F_SIDN) marks night-glow materials (windows AND lamps), - // so we additionally check for "window" in the texture path to + // so we additionally check for "window" or "glass" in the texture path to // distinguish actual glass from lamp post geometry. bool isWindow = false; if (batch.materialId < modelData.materialTextureIndices.size()) { uint32_t ti = modelData.materialTextureIndices[batch.materialId]; if (ti < modelData.textureNames.size()) { - isWindow = (modelData.textureNames[ti].find("window") != std::string::npos); + const auto& texName = modelData.textureNames[ti]; + // Case-insensitive search for "window" or "glass" + std::string texNameLower = texName; + std::transform(texNameLower.begin(), texNameLower.end(), texNameLower.begin(), ::tolower); + isWindow = (texNameLower.find("window") != std::string::npos || + texNameLower.find("glass") != std::string::npos); } } + + BatchKey key{ reinterpret_cast(tex), alphaTest, unlit, isWindow }; auto& mb = batchMap[key]; if (mb.draws.empty()) { @@ -651,7 +658,7 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) { matData.unlit = mb.unlit ? 1 : 0; matData.isInterior = isInterior ? 1 : 0; matData.specularIntensity = 0.5f; - matData.isWindow = mb.isWindow ? 1 : 0; + matData.isWindow = mb.isWindow ? (wmoOnlyMap_ ? 2 : 1) : 0; matData.enableNormalMap = normalMappingEnabled_ ? 1 : 0; matData.enablePOM = pomEnabled_ ? 1 : 0; matData.pomScale = 0.012f;