diff --git a/assets/shaders/wmo.frag.glsl b/assets/shaders/wmo.frag.glsl index 705ecd47..dbd55436 100644 --- a/assets/shaders/wmo.frag.glsl +++ b/assets/shaders/wmo.frag.glsl @@ -152,11 +152,29 @@ void main() { vec3 result; + // Sample shadow map for all non-window WMO surfaces + float shadow = 1.0; + if (shadowParams.x > 0.5) { + vec3 ldir = normalize(-lightDir.xyz); + float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir))); + vec3 biasedPos = FragPos + norm * normalOffset; + vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0); + vec3 proj = lsPos.xyz / lsPos.w; + proj.xy = proj.xy * 0.5 + 0.5; + if (proj.x >= 0.0 && proj.x <= 1.0 && + proj.y >= 0.0 && proj.y <= 1.0 && + proj.z >= 0.0 && proj.z <= 1.0) { + float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005); + shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias)); + } + shadow = mix(1.0, shadow, shadowParams.y); + } + if (unlit != 0) { - result = texColor.rgb; + result = texColor.rgb * shadow; } else if (isInterior != 0) { vec3 mocv = max(VertColor.rgb, vec3(0.5)); - result = texColor.rgb * mocv; + result = texColor.rgb * mocv * shadow; } else { vec3 ldir = normalize(-lightDir.xyz); float diff = max(dot(norm, ldir), 0.0); @@ -165,22 +183,6 @@ void main() { vec3 halfDir = normalize(ldir + viewDir); float spec = pow(max(dot(norm, halfDir), 0.0), 32.0) * specularIntensity; - float shadow = 1.0; - if (shadowParams.x > 0.5) { - float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir))); - vec3 biasedPos = FragPos + norm * normalOffset; - vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0); - vec3 proj = lsPos.xyz / lsPos.w; - proj.xy = proj.xy * 0.5 + 0.5; - if (proj.x >= 0.0 && proj.x <= 1.0 && - proj.y >= 0.0 && proj.y <= 1.0 && - proj.z >= 0.0 && proj.z <= 1.0) { - float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005); - shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias)); - } - shadow = mix(1.0, shadow, shadowParams.y); - } - result = ambientColor.rgb * texColor.rgb + shadow * (diff * lightColor.rgb * texColor.rgb + spec * lightColor.rgb); diff --git a/assets/shaders/wmo.frag.spv b/assets/shaders/wmo.frag.spv index f1241ab8..a7b9ef94 100644 Binary files a/assets/shaders/wmo.frag.spv and b/assets/shaders/wmo.frag.spv differ diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index bdf159b7..cd0cf212 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -80,7 +80,7 @@ private: bool pendingFullscreen = false; bool pendingVsync = false; int pendingResIndex = 0; - bool pendingShadows = false; + bool pendingShadows = true; int pendingMasterVolume = 100; int pendingMusicVolume = 30; int pendingAmbientVolume = 100; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index bd66a99a..7115d935 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -603,7 +603,8 @@ void Renderer::updatePerFrameUBO() { } } - currentFrameData.shadowParams = glm::vec4(shadowsEnabled ? 1.0f : 0.0f, 0.5f, 0.0f, 0.0f); + currentFrameData.lightSpaceMatrix = lightSpaceMatrix; + currentFrameData.shadowParams = glm::vec4(shadowsEnabled ? 1.0f : 0.0f, 0.8f, 0.0f, 0.0f); // Player water ripple data: pack player XY into shadowParams.zw, ripple strength into fogParams.w if (cameraController) { diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index bc0489d3..8c0ae570 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -5893,7 +5893,7 @@ void GameScreen::renderSettingsWindow() { constexpr int kDefaultResH = 1080; constexpr bool kDefaultFullscreen = false; constexpr bool kDefaultVsync = true; - constexpr bool kDefaultShadows = false; + constexpr bool kDefaultShadows = true; constexpr int kDefaultMusicVolume = 30; constexpr float kDefaultMouseSensitivity = 0.2f; constexpr bool kDefaultInvertMouse = false; @@ -5910,8 +5910,8 @@ void GameScreen::renderSettingsWindow() { if (!settingsInit) { pendingFullscreen = window->isFullscreen(); pendingVsync = window->isVsyncEnabled(); - pendingShadows = renderer ? renderer->areShadowsEnabled() : true; if (renderer) { + renderer->setShadowsEnabled(pendingShadows); // Read non-volume settings from actual state (volumes come from saved settings) if (auto* cameraController = renderer->getCameraController()) { pendingMouseSensitivity = cameraController->getMouseSensitivity(); @@ -7089,6 +7089,7 @@ void GameScreen::saveSettings() { // Gameplay out << "auto_loot=" << (pendingAutoLoot ? 1 : 0) << "\n"; out << "ground_clutter_density=" << pendingGroundClutterDensity << "\n"; + out << "shadows=" << (pendingShadows ? 1 : 0) << "\n"; out << "antialiasing=" << pendingAntiAliasing << "\n"; out << "normal_mapping=" << (pendingNormalMapping ? 1 : 0) << "\n"; out << "normal_map_strength=" << pendingNormalMapStrength << "\n"; @@ -7172,6 +7173,7 @@ void GameScreen::loadSettings() { // Gameplay else if (key == "auto_loot") pendingAutoLoot = (std::stoi(val) != 0); else if (key == "ground_clutter_density") pendingGroundClutterDensity = std::clamp(std::stoi(val), 0, 150); + else if (key == "shadows") pendingShadows = (std::stoi(val) != 0); else if (key == "antialiasing") pendingAntiAliasing = std::clamp(std::stoi(val), 0, 3); else if (key == "normal_mapping") pendingNormalMapping = (std::stoi(val) != 0); else if (key == "normal_map_strength") pendingNormalMapStrength = std::clamp(std::stof(val), 0.0f, 2.0f);