diff --git a/src/rendering/celestial.cpp b/src/rendering/celestial.cpp index d80529c7..3629b284 100644 --- a/src/rendering/celestial.cpp +++ b/src/rendering/celestial.cpp @@ -211,7 +211,13 @@ void Celestial::renderSun(const Camera& camera, float timeOfDay, celestialShader->use(); - glm::vec3 dir = sunDir ? glm::normalize(*sunDir) : glm::vec3(0.0f, 0.0f, 1.0f); + // Prefer opposite of light-ray direction (sun->world), but guard against + // profile/convention mismatches that can place the sun below the horizon. + glm::vec3 lightDir = sunDir ? glm::normalize(*sunDir) : glm::vec3(0.0f, 0.0f, -1.0f); + glm::vec3 dir = -lightDir; + if (dir.z < 0.0f) { + dir = lightDir; + } // Place sun on sky sphere at fixed distance const float sunDistance = 800.0f; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 51045bb1..2103419a 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -3599,8 +3599,24 @@ glm::mat4 Renderer::computeLightSpaceMatrix() { constexpr float kShadowNearPlane = 1.0f; constexpr float kShadowFarPlane = 600.0f; - // Fixed sun direction matching current world lighting setup. + // Use active lighting direction so shadow projection matches sun/celestial. glm::vec3 sunDir = glm::normalize(glm::vec3(-0.3f, -0.7f, -0.6f)); + if (lightingManager) { + const auto& lighting = lightingManager->getLightingParams(); + if (glm::length(lighting.directionalDir) > 0.001f) { + sunDir = glm::normalize(lighting.directionalDir); + } + } + // Shadow camera expects light rays pointing downward in render space (Z up). + // Some profiles/opcode paths provide the opposite convention; normalize here. + if (sunDir.z > 0.0f) { + sunDir = -sunDir; + } + // Keep a minimum downward component so the frustum doesn't collapse at grazing angles. + if (sunDir.z > -0.08f) { + sunDir.z = -0.08f; + sunDir = glm::normalize(sunDir); + } // Keep a stable shadow focus center and move it smoothly toward the player // to avoid visible shadow "state jumps" during movement. @@ -3738,6 +3754,19 @@ void Renderer::renderShadowPass() { // directly by calling renderShadow with the light view/proj split. // For simplicity, compute the split: glm::vec3 sunDir = glm::normalize(glm::vec3(-0.3f, -0.7f, -0.6f)); + if (lightingManager) { + const auto& lighting = lightingManager->getLightingParams(); + if (glm::length(lighting.directionalDir) > 0.001f) { + sunDir = glm::normalize(lighting.directionalDir); + } + } + if (sunDir.z > 0.0f) { + sunDir = -sunDir; + } + if (sunDir.z > -0.08f) { + sunDir.z = -0.08f; + sunDir = glm::normalize(sunDir); + } glm::vec3 center = shadowCenterInitialized ? shadowCenter : characterPosition; float halfExtent = kShadowHalfExtent; glm::vec3 up(0.0f, 0.0f, 1.0f); diff --git a/src/rendering/sky_system.cpp b/src/rendering/sky_system.cpp index 941c6fe0..3e96a290 100644 --- a/src/rendering/sky_system.cpp +++ b/src/rendering/sky_system.cpp @@ -148,9 +148,13 @@ void SkySystem::render(const Camera& camera, const SkyParams& params) { glm::vec3 SkySystem::getSunPosition(const SkyParams& params) const { glm::vec3 dir = glm::normalize(params.directionalDir); if (glm::length(dir) < 0.0001f) { - dir = glm::vec3(0.0f, 0.0f, 1.0f); + dir = glm::vec3(0.0f, 0.0f, -1.0f); } - glm::vec3 pos = dir * 800.0f; + glm::vec3 sunDir = -dir; + if (sunDir.z < 0.0f) { + sunDir = dir; + } + glm::vec3 pos = sunDir * 800.0f; return pos; }