From 4d1be18c18ab27e75103cd32a966d6c5eabd2d78 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 21:27:01 -0700 Subject: [PATCH] wmo: apply MOHD ambient color to interior group lighting Read the ambient color from the MOHD chunk (BGRA uint32) and store it on WMOModel as a normalized RGB vec3. Pass it through ModelData into the per-batch WMOMaterialUBO (replacing the unused pad[3] bytes, keeping the struct at 64 bytes). The GLSL interior branch now floors vertex colors against the WMO ambient instead of a hardcoded 0.5, so dungeon interiors respect the artist-specified ambient tint from the WMO root rather than always clamping to grey. --- assets/shaders/wmo.frag.glsl | 11 ++++++++++- assets/shaders/wmo.frag.spv | Bin 12456 -> 21268 bytes include/pipeline/wmo_loader.hpp | 1 + include/rendering/wmo_renderer.hpp | 5 ++++- src/pipeline/wmo_loader.cpp | 6 +++++- src/rendering/wmo_renderer.cpp | 4 ++++ 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/assets/shaders/wmo.frag.glsl b/assets/shaders/wmo.frag.glsl index a4bae057..c2b3b1cd 100644 --- a/assets/shaders/wmo.frag.glsl +++ b/assets/shaders/wmo.frag.glsl @@ -29,6 +29,9 @@ layout(set = 1, binding = 1) uniform WMOMaterial { float heightMapVariance; float normalMapStrength; int isLava; + float wmoAmbientR; + float wmoAmbientG; + float wmoAmbientB; }; layout(set = 1, binding = 2) uniform sampler2D uNormalHeightMap; @@ -185,7 +188,13 @@ void main() { } else if (unlit != 0) { result = texColor.rgb * shadow; } else if (isInterior != 0) { - vec3 mocv = max(VertColor.rgb, vec3(0.5)); + // WMO interior: vertex colors (MOCV) are pre-baked lighting from the artist. + // The MOHD ambient color tints/floors the vertex colors so dark spots don't + // go completely black, matching the WoW client's interior shading. + vec3 wmoAmbient = vec3(wmoAmbientR, wmoAmbientG, wmoAmbientB); + // Clamp ambient to at least 0.3 to avoid total darkness when MOHD color is zero + wmoAmbient = max(wmoAmbient, vec3(0.3)); + vec3 mocv = max(VertColor.rgb, wmoAmbient); result = texColor.rgb * mocv * shadow; } else { vec3 ldir = normalize(-lightDir.xyz); diff --git a/assets/shaders/wmo.frag.spv b/assets/shaders/wmo.frag.spv index 524dbd1ea425698858608248b93668dbc5ee5e21..3507f3c9915f392474e058da739b368c11de9e60 100644 GIT binary patch literal 21268 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 literal 12456 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 groups; glm::vec3 boundingBoxMin; glm::vec3 boundingBoxMax; + glm::vec3 wmoAmbientColor{0.5f, 0.5f, 0.5f}; // From MOHD, used for interior lighting bool isLowPlatform = false; // Doodad templates (M2 models placed in WMO, stored for instancing) diff --git a/src/pipeline/wmo_loader.cpp b/src/pipeline/wmo_loader.cpp index 22a4df42..076e4579 100644 --- a/src/pipeline/wmo_loader.cpp +++ b/src/pipeline/wmo_loader.cpp @@ -109,7 +109,11 @@ WMOModel WMOLoader::load(const std::vector& wmoData) { model.nDoodadDefs = read(wmoData, offset); model.nDoodadSets = read(wmoData, offset); - [[maybe_unused]] uint32_t ambColor = read(wmoData, offset); // Ambient color (BGRA) + uint32_t ambColor = read(wmoData, offset); // Ambient color (BGRA) + // Unpack BGRA bytes to normalized [0,1] RGB + model.ambientColor.r = ((ambColor >> 16) & 0xFF) / 255.0f; + model.ambientColor.g = ((ambColor >> 8) & 0xFF) / 255.0f; + model.ambientColor.b = ((ambColor >> 0) & 0xFF) / 255.0f; [[maybe_unused]] uint32_t wmoID = read(wmoData, offset); model.boundingBoxMin.x = read(wmoData, offset); diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index 51d8c2a2..4d52fd76 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -414,6 +414,7 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) { modelData.id = id; modelData.boundingBoxMin = model.boundingBoxMin; modelData.boundingBoxMax = model.boundingBoxMax; + modelData.wmoAmbientColor = model.ambientColor; { glm::vec3 ext = model.boundingBoxMax - model.boundingBoxMin; float horiz = std::max(ext.x, ext.y); @@ -681,6 +682,9 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) { matData.heightMapVariance = mb.heightMapVariance; matData.normalMapStrength = normalMapStrength_; matData.isLava = mb.isLava ? 1 : 0; + matData.wmoAmbientR = modelData.wmoAmbientColor.r; + matData.wmoAmbientG = modelData.wmoAmbientColor.g; + matData.wmoAmbientB = modelData.wmoAmbientColor.b; if (matBuf.info.pMappedData) { memcpy(matBuf.info.pMappedData, &matData, sizeof(matData)); }