Fix Stormwind cathedral LOD shell and extend view distance

- Add distance-based + backface culling for STORMWIND.WMO LOD shell groups
- Hide floating cathedral shell when within 185 units of group center
- Enable backface culling for LOD shell to reduce artifacts from inside
- Increase WMO view distance from 160 to 500 units for better visibility
- Extend fog distances to 3000-4000 units for clearer long-range views
- Add fog support to water renderer matching WMO fog settings
This commit is contained in:
Kelsi 2026-02-09 19:57:22 -08:00
parent 7e69978f40
commit 277c53d77c
4 changed files with 65 additions and 15 deletions

View file

@ -130,6 +130,13 @@ public:
*/
int getSurfaceCount() const { return static_cast<int>(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<Shader> waterShader;
std::vector<WaterSurface> 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

View file

@ -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;

View file

@ -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) {

View file

@ -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;