diff --git a/include/rendering/water_renderer.hpp b/include/rendering/water_renderer.hpp index 42b0a8c2..653e0742 100644 --- a/include/rendering/water_renderer.hpp +++ b/include/rendering/water_renderer.hpp @@ -130,6 +130,13 @@ public: */ int getSurfaceCount() const { return static_cast(surfaces.size()); } + /** + * Set fog parameters + */ + void setFog(const glm::vec3& color, float start, float end) { + fogColor = color; fogStart = start; fogEnd = end; + } + private: void createWaterMesh(WaterSurface& surface); void destroyWaterMesh(WaterSurface& surface); @@ -140,6 +147,11 @@ private: std::unique_ptr waterShader; std::vector surfaces; bool renderingEnabled = true; + + // Fog parameters + glm::vec3 fogColor = glm::vec3(0.5f, 0.6f, 0.7f); + float fogStart = 800.0f; // Match WMO renderer fog settings + float fogEnd = 1500.0f; }; } // namespace rendering diff --git a/include/rendering/wmo_renderer.hpp b/include/rendering/wmo_renderer.hpp index 70871a78..21b8dc2e 100644 --- a/include/rendering/wmo_renderer.hpp +++ b/include/rendering/wmo_renderer.hpp @@ -534,8 +534,8 @@ private: // Fog parameters glm::vec3 fogColor = glm::vec3(0.5f, 0.6f, 0.7f); - float fogStart = 400.0f; - float fogEnd = 1200.0f; + float fogStart = 3000.0f; // Increased to allow clearer visibility at distance + float fogEnd = 4000.0f; // Increased to match extended view distance // Shadow mapping GLuint shadowDepthTex = 0; diff --git a/src/rendering/water_renderer.cpp b/src/rendering/water_renderer.cpp index 794961f6..c2cf014a 100644 --- a/src/rendering/water_renderer.cpp +++ b/src/rendering/water_renderer.cpp @@ -88,6 +88,10 @@ bool WaterRenderer::initialize() { uniform float shimmerStrength; uniform float alphaScale; + uniform vec3 uFogColor; + uniform float uFogStart; + uniform float uFogEnd; + out vec4 FragColor; void main() { @@ -139,7 +143,13 @@ bool WaterRenderer::initialize() { float distAlpha = mix(0.0, 0.5, distFade); // Add up to 50% opacity at distance float alpha = clamp(waterAlpha * alphaScale * (0.68 + fresnel * 0.45) + distAlpha, 0.12, 0.95); - FragColor = vec4(result, alpha); + + // Apply distance fog + float fogDist = length(viewPos - FragPos); + float fogFactor = clamp((uFogEnd - fogDist) / (uFogEnd - uFogStart), 0.0, 1.0); + vec3 finalColor = mix(uFogColor, result, fogFactor); + + FragColor = vec4(finalColor, alpha); } )"; @@ -395,6 +405,9 @@ void WaterRenderer::render(const Camera& camera, float time) { waterShader->setUniform("projection", projection); waterShader->setUniform("viewPos", camera.getPosition()); waterShader->setUniform("time", time); + waterShader->setUniform("uFogColor", fogColor); + waterShader->setUniform("uFogStart", fogStart); + waterShader->setUniform("uFogEnd", fogEnd); // Render each water surface for (const auto& surface : surfaces) { diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index ee7893f0..ada42f58 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -919,10 +919,11 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm: if (gi < instance.worldGroupBounds.size()) { const auto& [gMin, gMax] = instance.worldGroupBounds[gi]; - // Hard distance cutoff + // Hard distance cutoff (increased for better visibility of major structures) + // 500 units = 250000.0f squared (was 160 units / 25600.0f) glm::vec3 closestPoint = glm::clamp(camPos, gMin, gMax); float distSq = glm::dot(closestPoint - camPos, closestPoint - camPos); - if (distSq > 25600.0f) { + if (distSq > 250000.0f) { result.distanceCulled++; continue; } @@ -1019,20 +1020,44 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm: for (uint32_t gi : dl.visibleGroups) { const auto& group = model.groups[gi]; - // Hide floating LOD shell groups that are positioned too high - // Groups 92/93 are at worldZ 200-225 (floating shell with massive height) - // Group 95 at worldZ=162 is legitimate (keep it) - glm::vec3 groupCenter = (group.boundingBoxMin + group.boundingBoxMax) * 0.5f; - glm::vec4 worldCenter = instance.modelMatrix * glm::vec4(groupCenter, 1.0f); - glm::vec3 size = group.boundingBoxMax - group.boundingBoxMin; + // STORMWIND.WMO specific fix: LOD shell visibility control + // Combination of distance culling + backface culling for best results + bool isLODShell = false; + if (instance.modelId == 10047) { + glm::vec3 groupCenter = (group.boundingBoxMin + group.boundingBoxMax) * 0.5f; + glm::vec4 worldCenter = instance.modelMatrix * glm::vec4(groupCenter, 1.0f); + glm::vec3 size = group.boundingBoxMax - group.boundingBoxMin; - // Skip groups that are both HIGH (worldZ > 180) AND very tall (sizeZ > 100) - // This catches groups 92 (worldZ=225, sizeZ=251) and 93 (worldZ=201, sizeZ=165) - if (worldCenter.z > 180.0f && size.z > 100.0f) { - continue; // Skip floating LOD shell + // Detect LOD shell groups: Groups 92/93 at worldZ 200-225 with massive height + if (worldCenter.z > 195.0f && size.z > 160.0f) { + // Measure distance to the actual group center, not WMO origin + float distToGroup = glm::length(cameraPos - glm::vec3(worldCenter)); + + static int logCounter = 0; + if (logCounter++ % 300 == 0) { + LOG_INFO("LOD Shell Group ", gi, ": worldZ=", worldCenter.z, " sizeZ=", size.z, + " distToGroup=", distToGroup, " (hiding if < 185)"); + } + + // Completely hide LOD shell when close (underneath/inside city) + // NOTE: 185 units threshold - may need further tuning based on gameplay testing + if (distToGroup < 185.0f) { + continue; // Skip rendering entirely when close + } + + // When farther away, use backface culling to hide interior faces + isLODShell = true; + glEnable(GL_CULL_FACE); // Enable backface culling for LOD shell + glCullFace(GL_BACK); // Cull back faces (reduces artifacts from outside) + } } renderGroup(group, model, instance.modelMatrix, view, projection); + + // Restore culling state after LOD shell group + if (isLODShell) { + glDisable(GL_CULL_FACE); + } } lastPortalCulledGroups += dl.portalCulled;