diff --git a/features/Inverse Square Lighting/Shaders/Features/InverseSquareLighting.ini b/features/Inverse Square Lighting/Shaders/Features/InverseSquareLighting.ini index 19f01444dc..312d7ff985 100644 --- a/features/Inverse Square Lighting/Shaders/Features/InverseSquareLighting.ini +++ b/features/Inverse Square Lighting/Shaders/Features/InverseSquareLighting.ini @@ -1,2 +1,2 @@ [Info] -Version = 1-0-0 \ No newline at end of file +Version = 1-1-0 \ No newline at end of file diff --git a/features/Inverse Square Lighting/Shaders/InverseSquareLighting/InverseSquareLighting.hlsli b/features/Inverse Square Lighting/Shaders/InverseSquareLighting/InverseSquareLighting.hlsli index 444bb3d5bc..db8339fb17 100644 --- a/features/Inverse Square Lighting/Shaders/InverseSquareLighting/InverseSquareLighting.hlsli +++ b/features/Inverse Square Lighting/Shaders/InverseSquareLighting/InverseSquareLighting.hlsli @@ -12,7 +12,7 @@ namespace InverseSquareLighting float isEnabled = 1.0f - float((light.lightFlags & LightLimitFix::LightFlags::Disabled) != 0); float isInvSq = float((light.lightFlags & LightLimitFix::LightFlags::InverseSquare) != 0); - float invSq = SCALED_UNITS_SQ * rcp(distance * distance + SCALED_UNITS_SQ); + float invSq = SCALED_UNITS_SQ * rcp(distance * distance + SCALED_UNITS_SQ * light.size * light.size / 2.0f); float t = saturate((light.radius - distance) * light.fadeZone); float fastSmoothstep = t * t * (3.0f - 2.0f * t); invSq *= fastSmoothstep; diff --git a/features/Light Limit Fix/Shaders/LightLimitFix/Common.hlsli b/features/Light Limit Fix/Shaders/LightLimitFix/Common.hlsli index cb7d595a03..0432665d9c 100644 --- a/features/Light Limit Fix/Shaders/LightLimitFix/Common.hlsli +++ b/features/Light Limit Fix/Shaders/LightLimitFix/Common.hlsli @@ -34,14 +34,18 @@ struct LightGrid struct Light { float3 color; + float fade; float radius; + float invRadius; + float fadeZone; + float size; float4 positionWS[2]; float4 positionVS[2]; uint4 roomFlags; uint lightFlags; uint shadowLightIndex; - float invRadius; - float fadeZone; + uint pad0; + uint pad1; }; #endif //__LLF_COMMON_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/PBR.hlsli b/package/Shaders/Common/PBR.hlsli index c0795cb8ed..1ae7a5bd9f 100644 --- a/package/Shaders/Common/PBR.hlsli +++ b/package/Shaders/Common/PBR.hlsli @@ -147,7 +147,7 @@ namespace PBR // [Lagarde et al. 2014, "Moving Frostbite to Physically Based Rendering 3.0"] float SpecularAOLagarde(float NdotV, float ao, float roughness) { - return saturate(pow(NdotV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao); + return saturate(pow(abs(NdotV + ao), exp2(-16.0 * roughness - 1.0)) - 1.0 + ao); } #if defined(GLINT) diff --git a/src/Features/InverseSquareLighting.cpp b/src/Features/InverseSquareLighting.cpp index f36d97ab3e..c8d413b3f2 100644 --- a/src/Features/InverseSquareLighting.cpp +++ b/src/Features/InverseSquareLighting.cpp @@ -1,6 +1,7 @@ #include "InverseSquareLighting.h" #include "Features/InverseSquareLighting/Common.h" #include "LightLimitFix.h" +#include void InverseSquareLighting::DrawSettings() { @@ -38,6 +39,8 @@ void InverseSquareLighting::SetExtLightData(RE::NiLight* niLight, const RE::TESO runtimeData->flags.set(LightLimitFix::LightFlags::InverseSquare); runtimeData->cutoffOverride = std::clamp(ligh->data.fallofExponent, 0.01f, 1.f); runtimeData->lighFormId = ligh->formID; + const float size = ligh->data.fov >= 50.0f ? std::numbers::sqrt2_v : ligh->data.fov; + runtimeData->size = std::clamp(size, 0.01f, 50.0f); } void InverseSquareLighting::ProcessLight(LightLimitFix::LightData& light, RE::BSLight* bsLight, RE::NiLight* niLight) const @@ -56,26 +59,27 @@ void InverseSquareLighting::ProcessLight(LightLimitFix::LightData& light, RE::BS if (bsLight->pointLight && isInvSq) { const float intensity = runtimeData->fade * 4; - light.radius = CalculateRadius(intensity, bsLight->IsShadowLight(), runtimeData->cutoffOverride); + light.radius = CalculateRadius(intensity, bsLight->IsShadowLight(), runtimeData->cutoffOverride, runtimeData->size); + runtimeData->radius = light.radius; light.invRadius = 1.f / light.radius; light.fadeZone = 1.f / (light.radius * std::clamp(FadeZoneBase * light.invRadius, 0.f, 1.f)); - runtimeData->radius.x = light.radius; - runtimeData->radius.y = light.radius; - runtimeData->radius.z = light.radius; + light.size = runtimeData->size; light.color /= std::max(0.001f, std::max(light.color.x, std::max(light.color.y, light.color.z))); light.color *= intensity; + light.fade = intensity; } else { - light.radius = runtimeData->radius.x; + light.radius = runtimeData->radius; light.invRadius = 1.f / light.radius; light.color *= runtimeData->fade; + light.fade = runtimeData->fade; } } -float InverseSquareLighting::CalculateRadius(const float intensity, const bool shadowCaster, const float cutoffOverride) +float InverseSquareLighting::CalculateRadius(const float intensity, const bool shadowCaster, const float cutoffOverride, const float size) { float cutoff = shadowCaster ? DefaultShadowCasterCutoff : DefaultCutoff; cutoff = cutoffOverride == 1.f ? cutoff : cutoffOverride; - const float radius = std::sqrt(ScaledUnitsSq * ((intensity - cutoff) / cutoff)); + const float radius = std::sqrt(ScaledUnitsSq * ((2 * intensity - cutoff * size * size) / (2 * cutoff))); return isnan(radius) ? 1.f : radius; } @@ -85,9 +89,9 @@ inline float InverseSquareLighting::SmoothStep(const float edge0, const float ed return t * t * (3.0f - 2.0f * t); } -float InverseSquareLighting::GetAttenuation(const float distance, const float radius) +float InverseSquareLighting::GetAttenuation(const float distance, const float radius, const float size) { - const float attenuation = ScaledUnitsSq / (distance * distance + ScaledUnitsSq); + const float attenuation = ScaledUnitsSq / (distance * distance + ScaledUnitsSq * size * size / 2); const float fadeZone = std::clamp(FadeZoneBase / radius, 0.0f, 1.0f); const float fade = SmoothStep(0, radius * fadeZone, radius - distance); return attenuation * fade; @@ -105,7 +109,7 @@ float InverseSquareLighting::BSLight_GetLuminance::thunk(RE::BSLight* bsLight, R return func(bsLight, targetPosition, refLight); const float dist = niLight->world.translate.GetDistance(*targetPosition); - const float attenuation = GetAttenuation(dist, runtimeData->radius.x); + const float attenuation = GetAttenuation(dist, runtimeData->radius, runtimeData->size); const float luminance = (runtimeData->diffuse.red + runtimeData->diffuse.green + runtimeData->diffuse.blue) * runtimeData->fade * attenuation * (1.0f / 3.0f); bsLight->luminance = luminance; diff --git a/src/Features/InverseSquareLighting.h b/src/Features/InverseSquareLighting.h index f8582173f0..bc73c1a836 100644 --- a/src/Features/InverseSquareLighting.h +++ b/src/Features/InverseSquareLighting.h @@ -39,11 +39,11 @@ struct InverseSquareLighting : Feature virtual void PostPostLoad() override; - static float CalculateRadius(float intensity, bool shadowCaster, float cutoffOverride); + static float CalculateRadius(float intensity, bool shadowCaster, float cutoffOverride, float size); void ProcessLight(LightLimitFix::LightData& light, RE::BSLight* bsLight, RE::NiLight* niLight) const; - static float GetAttenuation(float distance, float radius); + static float GetAttenuation(float distance, float radius, float size); struct CreatePointLight { diff --git a/src/Features/InverseSquareLighting/Common.h b/src/Features/InverseSquareLighting/Common.h index 83fc21d795..ae0a1ef2af 100644 --- a/src/Features/InverseSquareLighting/Common.h +++ b/src/Features/InverseSquareLighting/Common.h @@ -14,7 +14,9 @@ struct ISLCommon float cutoffOverride; RE::FormID lighFormId; RE::NiColor diffuse; - RE::NiPoint3 radius; + float radius; + float pad1C; + float size; float fade; std::uint32_t unk138; diff --git a/src/Features/InverseSquareLighting/LightEditor.cpp b/src/Features/InverseSquareLighting/LightEditor.cpp index 7261053b0d..d6dfe27234 100644 --- a/src/Features/InverseSquareLighting/LightEditor.cpp +++ b/src/Features/InverseSquareLighting/LightEditor.cpp @@ -92,12 +92,14 @@ void LightEditor::DrawSettings() if (isInvSq) ImGui::BeginDisabled(); - ImGui::SliderFloat("Radius", ¤t.data.radius.x, 2.f, 8096.f, "%.0f"); + ImGui::SliderFloat("Radius", ¤t.data.radius, 2.f, 8096.f, "%.0f"); if (isInvSq) ImGui::EndDisabled(); - if (isInvSq) - ImGui::SliderFloat("Cutoff Override", ¤t.data.cutoffOverride, 0.01f, 1.f, "%.3f", ImGuiSliderFlags_AlwaysClamp); + if (isInvSq) { + ImGui::SliderFloat("Size", ¤t.data.size, 0.01f, 10.0f, "%.3f"); + ImGui::SliderFloat("Cutoff", ¤t.data.cutoffOverride, 0.01f, 1.f, "%.3f", ImGuiSliderFlags_AlwaysClamp); + } ImGui::Spacing(); ImGui::Spacing(); @@ -258,10 +260,9 @@ void LightEditor::UpdateSelectedLight(RE::TESObjectREFR* refr, RE::TESObjectLIGH if (current.data.flags.any(LightLimitFix::LightFlags::InverseSquare)) { current.data.radius = runtimeData->radius; - runtimeData->cutoffOverride = std::clamp(current.data.cutoffOverride, 0.01f, 1.f); + runtimeData->cutoffOverride = std::clamp(current.data.cutoffOverride, 0.01f, 1.0f); + runtimeData->size = std::clamp(current.data.size, 0.1f, 50.0f); } else { - current.data.radius.y = current.data.radius.x; - current.data.radius.z = current.data.radius.x; runtimeData->radius = current.data.radius; runtimeData->cutoffOverride = current.data.cutoffOverride; } diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index f1e85cce89..5d7b939d56 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -325,6 +325,7 @@ void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLig } else { light.radius = runtimeData.radius.x; light.color *= runtimeData.fade; + light.fade = runtimeData.fade; } light.color *= bsLight->lodDimmer; diff --git a/src/Features/LightLimitFix.h b/src/Features/LightLimitFix.h index 5db27d5662..6049a1ecb4 100644 --- a/src/Features/LightLimitFix.h +++ b/src/Features/LightLimitFix.h @@ -49,14 +49,18 @@ struct LightLimitFix : Feature struct alignas(16) LightData { float3 color; + float fade; float radius; + float invRadius; + float fadeZone; + float size; PositionOpt positionWS[2]; PositionOpt positionVS[2]; uint128_t roomFlags = uint32_t(0); stl::enumeration lightFlags; uint32_t shadowMaskIndex = 0; - float invRadius; - float fadeZone; + uint pad0; + uint pad1; }; struct ClusterAABB