diff --git a/src/Features/LinearLighting.cpp b/src/Features/LinearLighting.cpp index c4bb82de7f..fdab954530 100644 --- a/src/Features/LinearLighting.cpp +++ b/src/Features/LinearLighting.cpp @@ -4,6 +4,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( LinearLighting::Settings, enableLinearLighting, enableGammaCorrection, + clearRenderGamma, lightGamma, colorGamma, emitColorGamma, @@ -48,6 +49,7 @@ void LinearLighting::DrawSettings() ImGui::SliderFloat("Effect Gamma", &settings.effectGamma, 0.1f, 3.0f, "%.2f"); ImGui::SliderFloat("Effect Transparency Gamma", &settings.effectAlphaGamma, 0.1f, 3.0f, "%.2f"); ImGui::SliderFloat("Sky Gamma", &settings.skyGamma, 0.1f, 3.0f, "%.2f"); + ImGui::SliderFloat("Clear Render Gamma", &settings.clearRenderGamma, 0.1f, 3.0f, "%.2f"); ImGui::SliderFloat("Water Gamma", &settings.waterGamma, 0.1f, 3.0f, "%.2f"); ImGui::SliderFloat("Volumetric Lighting Gamma", &settings.vlGamma, 0.1f, 3.0f, "%.2f"); @@ -93,6 +95,61 @@ void LinearLighting::SetupResources() PerGeometryCB = new ConstantBuffer(ConstantBufferDesc()); } +void LinearLighting::EarlyPrepass() +{ + ConvertClearColor(); +} + +void LinearLighting::ReflectionsPrepass() +{ + ConvertClearColor(); +} + +void LinearLighting::ConvertClearColor() +{ + bool isMainLoadingMenu = globals::game::ui && (globals::game::ui->IsMenuOpen(RE::MainMenu::MENU_NAME) || globals::game::ui->IsMenuOpen(RE::LoadingMenu::MENU_NAME)); + if (!settings.enableLinearLighting || isMainLoadingMenu) + return; + + // Convert clear color from gamma space to linear space at the source + // This affects the background color visible at worldspace edges and in water reflections + auto renderer = globals::game::renderer; + if (renderer) { + auto& rendererData = renderer->GetRendererData(); + + const bool isAlreadyConverted = + rendererData.clearColor[0] == lastConvertedClearColor[0] && + rendererData.clearColor[1] == lastConvertedClearColor[1] && + rendererData.clearColor[2] == lastConvertedClearColor[2]; + + // Only refresh the source color when the engine has changed it + if (!isAlreadyConverted && + (rendererData.clearColor[0] != lastOriginalClearColor[0] || + rendererData.clearColor[1] != lastOriginalClearColor[1] || + rendererData.clearColor[2] != lastOriginalClearColor[2])) { + lastOriginalClearColor[0] = rendererData.clearColor[0]; + lastOriginalClearColor[1] = rendererData.clearColor[1]; + lastOriginalClearColor[2] = rendererData.clearColor[2]; + } + + float gamma = std::clamp(settings.clearRenderGamma, 0.1f, 3.0f); + if (isAlreadyConverted && gamma == lastConvertedClearGamma) { + return; + } + + rendererData.clearColor[0] = std::pow(lastOriginalClearColor[0], gamma); + rendererData.clearColor[1] = std::pow(lastOriginalClearColor[1], gamma); + rendererData.clearColor[2] = std::pow(lastOriginalClearColor[2], gamma); + // Alpha (clearColor[3]) typically doesn't need gamma correction + + // Remember what we converted to + lastConvertedClearColor[0] = rendererData.clearColor[0]; + lastConvertedClearColor[1] = rendererData.clearColor[1]; + lastConvertedClearColor[2] = rendererData.clearColor[2]; + lastConvertedClearGamma = gamma; + } +} + void LinearLighting::Prepass() { bool isMainLoadingMenu = globals::game::ui && (globals::game::ui->IsMenuOpen(RE::MainMenu::MENU_NAME) || globals::game::ui->IsMenuOpen(RE::LoadingMenu::MENU_NAME)); diff --git a/src/Features/LinearLighting.h b/src/Features/LinearLighting.h index 8c7b26db41..f866e3a89a 100644 --- a/src/Features/LinearLighting.h +++ b/src/Features/LinearLighting.h @@ -28,6 +28,7 @@ struct LinearLighting : Feature { uint enableLinearLighting = false; uint enableGammaCorrection = true; + float clearRenderGamma = 1.62f; float lightGamma = 1.8f; float colorGamma = 1.8f; float emitColorGamma = 1.8f; @@ -108,6 +109,9 @@ struct LinearLighting : Feature uint isDirLightLinear = false; float dirLightMult = 1.0f; + float lastConvertedClearColor[3] = { -1.0f, -1.0f, -1.0f }; // Track to avoid double conversion + float lastOriginalClearColor[3] = { -1.0f, -1.0f, -1.0f }; // Source gamma-space color + float lastConvertedClearGamma = -1.0f; virtual void DrawSettings() override; @@ -116,6 +120,8 @@ struct LinearLighting : Feature virtual void RestoreDefaultSettings() override; + virtual void EarlyPrepass() override; + virtual void ReflectionsPrepass() override; virtual void Prepass() override; virtual void PostPostLoad() override; @@ -127,5 +133,7 @@ struct LinearLighting : Feature void BSLightingShader_SetupGeometry(RE::BSRenderPass* a_pass); + void ConvertClearColor(); + struct Hooks; };