From 8df81eb46d9cc4d951680a3d1627157ac38aaed9 Mon Sep 17 00:00:00 2001 From: Hirek193 Date: Mon, 14 Sep 2026 21:11:08 +0200 Subject: [PATCH] Improve skybox --- environment/skydome.cpp | 5 ++++- shaders/color.frag | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/environment/skydome.cpp b/environment/skydome.cpp index f5b936f5..830eb145 100644 --- a/environment/skydome.cpp +++ b/environment/skydome.cpp @@ -218,7 +218,10 @@ void CSkyDome::RebuildColors() { vertex = glm::normalize( m_vertices[ i ] ); // angle between sun and vertex - const float gamma = std::acos( glm::dot( vertex, m_sundirection ) ); + // NOTE: the dot product can exceed the [ -1, 1 ] range by a rounding error, + // which would turn the vertex - and, through the averages, the fog and ambient + // light - into a NaN, so it gets clamped before feeding it to acos() + const float gamma = std::acos( std::clamp( glm::dot( vertex, m_sundirection ), -1.0f, 1.0f ) ); // warning : major hack!!! .. i had to do something with values under horizon //vertex.y = Clamp( vertex.y, 0.05f, 1.0f ); diff --git a/shaders/color.frag b/shaders/color.frag index 45c0829e..2f7fabc5 100644 --- a/shaders/color.frag +++ b/shaders/color.frag @@ -10,9 +10,26 @@ layout(location = 0) out vec4 out_color; layout(location = 1) out vec4 out_motion; #endif +// the skydome vertex colours carry Perez luminance scaled by a fixed exposure +// (see CSkyDome::SetExposure), so the circumsolar region and the horizon band +// routinely land well above 1.0. hard-clipping them, as this shader used to do, +// flattened everything within ~20 degrees of the sun - and most of the lower sky - +// into one solid white patch. compress the top end instead: below the knee the +// response is unchanged, above it it rolls off towards SKY_SHOULDER_WHITE, so the +// brightness gradient around the sun survives and the patch keeps a soft edge. +const float SKY_SHOULDER_KNEE = 0.25; +const float SKY_SHOULDER_WHITE = 0.95; + +vec3 sky_shoulder(vec3 color) +{ + const float range = SKY_SHOULDER_WHITE - SKY_SHOULDER_KNEE; + vec3 excess = max(color - vec3(SKY_SHOULDER_KNEE), vec3(0.0)); + return min(color, vec3(SKY_SHOULDER_KNEE)) + range * (vec3(1.0) - exp(-excess / range)); +} + void main() { - vec3 col = clamp(pow(f_color.rgb, vec3(2.2)),0, 1); + vec3 col = sky_shoulder(pow(max(f_color.rgb, vec3(0.0)), vec3(2.2))); #if POSTFX_ENABLED out_color = vec4(apply_fog(col), 1.0f); #else