diff --git a/features/Light Limit Fix/Shaders/Features/LightLimitFix.ini b/features/Light Limit Fix/Shaders/Features/LightLimitFix.ini index 01aaedc093..312d7ff985 100644 --- a/features/Light Limit Fix/Shaders/Features/LightLimitFix.ini +++ b/features/Light Limit Fix/Shaders/Features/LightLimitFix.ini @@ -1,2 +1,2 @@ [Info] -Version = 1-0-2 \ No newline at end of file +Version = 1-1-0 \ No newline at end of file diff --git a/features/Light Limit Fix/Shaders/LightLimitFix/LightLimitFix.hlsli b/features/Light Limit Fix/Shaders/LightLimitFix/LightLimitFix.hlsli index e682c4e6e4..67becf8b81 100644 --- a/features/Light Limit Fix/Shaders/LightLimitFix/LightLimitFix.hlsli +++ b/features/Light Limit Fix/Shaders/LightLimitFix/LightLimitFix.hlsli @@ -21,7 +21,6 @@ struct PerPassLLF bool EnableContactShadows; bool EnableLightsVisualisation; uint LightsVisualisationMode; - uint StrictLightsCount; float LightsNear; float LightsFar; float4 CameraData; @@ -39,6 +38,16 @@ Texture2D TexDepthSampler : register(t20); StructuredBuffer perPassLLF : register(t32); +struct StrictLightData +{ + uint NumLights; + float3 PointLightPosition[15]; + float PointLightRadius[15]; + float3 PointLightColor[15]; +}; + +StructuredBuffer strictLightData : register(t37); + bool GetClusterIndex(in float2 uv, in float z, out uint clusterIndex) { if (z < perPassLLF[0].LightsNear || z > perPassLLF[0].LightsFar) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index f05fee90ed..081dbfb267 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1570,17 +1570,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if !defined(LOD) if (numLights > 0) { - [loop] for (float lightIndex = 0; lightIndex < numLights; ++lightIndex) +# if defined(LIGHT_LIMIT_FIX) + [loop] for (uint lightIndex = 0; lightIndex < strictLightData[0].NumLights; lightIndex++) { - int intLightIndex = lightIndex; - float3 lightDirection = PointLightPosition[eyeIndex * numLights + intLightIndex].xyz - input.InputPosition.xyz; + float3 lightDirection = strictLightData[0].PointLightPosition[lightIndex] - input.InputPosition; float lightDist = length(lightDirection); - float intensityFactor = saturate(lightDist / PointLightPosition[intLightIndex].w); + float intensityFactor = saturate(lightDist / strictLightData[0].PointLightRadius[lightIndex]); if (intensityFactor == 1) continue; float intensityMultiplier = 1 - intensityFactor * intensityFactor; - - float3 lightColor = PointLightColor[intLightIndex].xyz; + float3 lightColor = strictLightData[0].PointLightColor[lightIndex]; +# else + [loop] for (uint lightIndex = 0; lightIndex < numLights; ++lightIndex) + { + float3 lightDirection = PointLightPosition[eyeIndex * numLights + lightIndex].xyz - input.InputPosition.xyz; + float lightDist = length(lightDirection); + float intensityFactor = saturate(lightDist / PointLightPosition[lightIndex].w); + if (intensityFactor == 1) + continue; + float intensityMultiplier = 1 - intensityFactor * intensityFactor; + float3 lightColor = PointLightColor[lightIndex].xyz; +# endif float3 nsLightColor = lightColor; float shadowComponent = 1.0; @@ -1664,11 +1674,11 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (lightCount) { uint lightOffset = lightGrid[clusterIndex].offset; + float shadowQualityScale = saturate(1.0 - ((float)lightCount / 128.0)); + float3 worldSpaceNormal = normalize(mul(CameraViewInverse[eyeIndex], float4(screenSpaceNormal, 0))); float3 worldSpaceViewDirection = -normalize(input.WorldPosition.xyz); - float shadowQualityScale = saturate(1.0 - ((float)lightCount / 128.0)); - # if (defined(SKINNED) || !defined(MODELSPACENORMALS)) float3 worldSpaceVertexNormal = vertexNormal; # if (!defined(DRAW_IN_WORLDSPACE)) @@ -1690,6 +1700,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } # endif # endif + [loop] for (uint i = 0; i < lightCount; i++) { uint light_index = lightList[lightOffset + i]; @@ -1923,9 +1934,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(LIGHT_LIMIT_FIX) if (perPassLLF[0].EnableLightsVisualisation) { if (perPassLLF[0].LightsVisualisationMode == 0) { - psout.Albedo.xyz = TurboColormap(perPassLLF[0].StrictLightsCount > 7); + psout.Albedo.xyz = TurboColormap(strictLightData[0].NumLights >= 7.0); } else if (perPassLLF[0].LightsVisualisationMode == 1) { - psout.Albedo.xyz = TurboColormap((float)perPassLLF[0].StrictLightsCount / 7.0); + psout.Albedo.xyz = TurboColormap((float)strictLightData[0].NumLights / 15.0); } else { psout.Albedo.xyz = TurboColormap((float)lightCount / 128.0); } diff --git a/src/Features/LightLimitFix.cpp b/src/Features/LightLimitFix.cpp index 9938c794b2..a473de0c67 100644 --- a/src/Features/LightLimitFix.cpp +++ b/src/Features/LightLimitFix.cpp @@ -178,6 +178,23 @@ void LightLimitFix::SetupResources() perPass->CreateSRV(srvDesc); } + { + D3D11_BUFFER_DESC sbDesc{}; + sbDesc.Usage = D3D11_USAGE_DYNAMIC; + sbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + sbDesc.StructureByteStride = sizeof(StrictLightData); + sbDesc.ByteWidth = sizeof(StrictLightData); + strictLightData = std::make_unique(sbDesc); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = 1; + strictLightData->CreateSRV(srvDesc); + } { clusterBuildingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterBuildingCS.hlsl", {}, "cs_5_0"); clusterCullingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\LightLimitFix\\ClusterCullingCS.hlsl", {}, "cs_5_0"); @@ -269,9 +286,45 @@ void LightLimitFix::Save(json& o_json) o_json[GetName()] = settings; } -void LightLimitFix::BSLightingShader_SetupGeometry_Before(RE::BSRenderPass* a_pass) +void LightLimitFix::BSLightingShader_SetupGeometry_Before(RE::BSRenderPass*) +{ + strictLightDataTemp.NumLights = 0; +} + +void LightLimitFix::BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass, DirectX::XMMATRIX& Transform, uint32_t, uint32_t, float WorldScale, Space RenderSpace) +{ + strictLightDataTemp.NumLights = a_pass->numLights - 1; + for (uint32_t i = 0; i < strictLightDataTemp.NumLights; i++) { + auto bsLight = a_pass->sceneLights[i + 1]; + auto niLight = bsLight->light.get(); + + auto& runtimeData = niLight->GetLightRuntimeData(); + + float3 worldPos = { niLight->world.translate.x, niLight->world.translate.y, niLight->world.translate.z }; + + if (RenderSpace == Space::Model) { + strictLightDataTemp.PointLightPosition[i] = DirectX::SimpleMath::Vector3::Transform(worldPos, Transform); + strictLightDataTemp.PointLightRadius[i] = runtimeData.radius.x / WorldScale; + } else { + auto posAdjust = RE::BSGraphics::RendererShadowState::GetSingleton()->GetRuntimeData().posAdjust.getEye(); + strictLightDataTemp.PointLightPosition[i] = worldPos - float3(posAdjust.x, posAdjust.y, posAdjust.z); + strictLightDataTemp.PointLightRadius[i] = runtimeData.radius.x; + } + + strictLightDataTemp.PointLightColor[i] = { runtimeData.diffuse.red, runtimeData.diffuse.green, runtimeData.diffuse.blue }; + strictLightDataTemp.PointLightColor[i] *= runtimeData.fade; + strictLightDataTemp.PointLightColor[i] *= bsLight->lodDimmer; + } +} + +void LightLimitFix::BSLightingShader_SetupGeometry_After(RE::BSRenderPass*) { - strictLightsCount = a_pass->numLights - 1; + auto context = RE::BSGraphics::Renderer::GetSingleton()->GetRuntimeData().context; + D3D11_MAPPED_SUBRESOURCE mapped; + DX::ThrowIfFailed(context->Map(strictLightData->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); + size_t bytes = sizeof(StrictLightData); + memcpy_s(mapped.pData, bytes, &strictLightDataTemp, bytes); + context->Unmap(strictLightData->resource.get(), 0); } void LightLimitFix::SetLightPosition(LightLimitFix::LightData& a_light, RE::NiPoint3& a_initialPosition) @@ -355,6 +408,7 @@ void LightLimitFix::Bind() { PerPass perPassData{}; + perPassData.CameraData.x = accumulator->kCamera->GetRuntimeData2().viewFrustum.fFar; perPassData.CameraData.y = accumulator->kCamera->GetRuntimeData2().viewFrustum.fNear; perPassData.CameraData.z = accumulator->kCamera->GetRuntimeData2().viewFrustum.fFar - accumulator->kCamera->GetRuntimeData2().viewFrustum.fNear; @@ -386,7 +440,6 @@ void LightLimitFix::Bind() perPassData.EnableContactShadows = settings.EnableContactShadows; perPassData.EnableLightsVisualisation = settings.EnableLightsVisualisation; perPassData.LightsVisualisationMode = settings.LightsVisualisationMode; - perPassData.StrictLightsCount = strictLightsCount; D3D11_MAPPED_SUBRESOURCE mapped; DX::ThrowIfFailed(context->Map(perPass->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); @@ -401,6 +454,12 @@ void LightLimitFix::Bind() views[0] = perPass->srv.get(); context->PSSetShaderResources(32, ARRAYSIZE(views), views); } + + { + ID3D11ShaderResourceView* views[1]{}; + views[0] = strictLightData->srv.get(); + context->PSSetShaderResources(37, ARRAYSIZE(views), views); + } } bool LightLimitFix::IsValidLight(RE::BSLight* a_light) @@ -605,7 +664,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector& lightsData dimmer = 0.0f; } - //light.color *= dimmer; + light.color *= dimmer; float distantLightFadeStart = lightsFar * lightsFar * (lightFadeStart / lightFadeEnd); float distantLightFadeEnd = lightsFar * lightsFar; @@ -618,7 +677,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector& lightsData dimmer = 0.0f; } - //light.color *= dimmer; + light.color *= dimmer; if ((light.color.x + light.color.y + light.color.z) > 1e-4 && light.radius > 1e-4) { if (a_geometry && a_config && a_config->flicker) { @@ -636,7 +695,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector& lightsData light.positionWS[eyeIndex].y += (float)perlin2.noise1D(scaledTimer) * a_config->flickerMovement; light.positionWS[eyeIndex].z += (float)perlin3.noise1D(scaledTimer) * a_config->flickerMovement; } - dimmer = std::max(0.0f, dimmer - ((float)perlin4.noise1D_01(scaledTimer) * a_config->flickerIntensity)); + dimmer = std::max(0.0f, dimmer - ((float)perlin4.noise1D_01(scaledTimer) * a_config->flickerIntensity)); // todo: this is wrong } CachedParticleLight cachedParticleLight{}; diff --git a/src/Features/LightLimitFix.h b/src/Features/LightLimitFix.h index 0e6e44643f..e079f855d5 100644 --- a/src/Features/LightLimitFix.h +++ b/src/Features/LightLimitFix.h @@ -63,7 +63,6 @@ struct LightLimitFix : Feature uint EnableContactShadows; uint EnableLightsVisualisation; uint LightsVisualisationMode; - uint StrictLightsCount; float LightsNear; float LightsFar; float4 CameraData; @@ -71,6 +70,16 @@ struct LightLimitFix : Feature uint FrameCount; }; + struct StrictLightData + { + uint NumLights; + float3 PointLightPosition[15]; + float PointLightRadius[15]; + float3 PointLightColor[15]; + }; + + StrictLightData strictLightDataTemp; + struct CachedParticleLight { float grey; @@ -79,6 +88,7 @@ struct LightLimitFix : Feature }; std::unique_ptr perPass = nullptr; + std::unique_ptr strictLightData = nullptr; bool rendered = false; int eyeCount = !REL::Module::IsVR() ? 1 : 2; @@ -107,8 +117,6 @@ struct LightLimitFix : Feature eastl::hash_map queuedParticleLights; eastl::hash_map particleLights; - std::uint32_t strictLightsCount = 0; - virtual void SetupResources(); virtual void Reset(); @@ -153,6 +161,7 @@ struct LightLimitFix : Feature Settings settings; bool CheckParticleLights(RE::BSRenderPass* a_pass, uint32_t a_technique); + void BSLightingShader_SetupGeometry_Before(RE::BSRenderPass* a_pass); enum class Space @@ -161,6 +170,10 @@ struct LightLimitFix : Feature Model = 1, }; + void BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(RE::BSRenderPass* a_pass, DirectX::XMMATRIX& Transform, uint32_t, uint32_t, float WorldScale, Space RenderSpace); + + void BSLightingShader_SetupGeometry_After(RE::BSRenderPass* a_pass); + std::shared_mutex cachedParticleLightsMutex; eastl::vector cachedParticleLights; uint32_t particleLightsDetectionHits = 0; @@ -174,7 +187,7 @@ struct LightLimitFix : Feature { static bool thunk(RE::BSShaderProperty* a_property, RE::BSLight* a_light) { - return func(a_property, a_light) && (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light)); + return func(a_property, a_light) && (!netimmerse_cast(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light))); } static inline REL::Relocation func; }; @@ -183,7 +196,7 @@ struct LightLimitFix : Feature { static bool thunk(RE::BSShaderProperty* a_property, RE::BSLight* a_light) { - return func(a_property, a_light) && (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light)); + return func(a_property, a_light) && (!netimmerse_cast(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light))); } static inline REL::Relocation func; }; @@ -192,7 +205,7 @@ struct LightLimitFix : Feature { static bool thunk(RE::BSShaderProperty* a_property, RE::BSLight* a_light) { - return func(a_property, a_light) && (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light)); + return func(a_property, a_light) && (!netimmerse_cast(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast(a_light))); } static inline REL::Relocation func; }; @@ -233,6 +246,7 @@ struct LightLimitFix : Feature { GetSingleton()->BSLightingShader_SetupGeometry_Before(Pass); func(This, Pass, RenderFlags); + GetSingleton()->BSLightingShader_SetupGeometry_After(Pass); } static inline REL::Relocation func; }; @@ -247,6 +261,16 @@ struct LightLimitFix : Feature static inline REL::Relocation func; }; + struct BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights + { + static void thunk(RE::BSGraphics::PixelShader* PixelShader, RE::BSRenderPass* Pass, DirectX::XMMATRIX& Transform, uint32_t LightCount, uint32_t ShadowLightCount, float WorldScale, Space RenderSpace) + { + GetSingleton()->BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights(Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); + func(PixelShader, Pass, Transform, LightCount, ShadowLightCount, WorldScale, RenderSpace); + } + static inline REL::Relocation func; + }; + static void Install() { stl::write_thunk_call(REL::RelocationID(100994, 107781).address() + 0x92); @@ -262,6 +286,8 @@ struct LightLimitFix : Feature stl::write_vfunc<0x6, BSLightingShader_SetupGeometry>(RE::VTABLE_BSLightingShader[0]); logger::info("[LLF] Installed hooks"); + + stl::write_thunk_call(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe)); } }; };