Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[Info]
Version = 1-0-2
Version = 1-1-0
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ struct PerPassLLF
bool EnableContactShadows;
bool EnableLightsVisualisation;
uint LightsVisualisationMode;
uint StrictLightsCount;
float LightsNear;
float LightsFar;
float4 CameraData;
Expand All @@ -39,6 +38,16 @@ Texture2D<float4> TexDepthSampler : register(t20);

StructuredBuffer<PerPassLLF> perPassLLF : register(t32);

struct StrictLightData
{
uint NumLights;
float3 PointLightPosition[15];
float PointLightRadius[15];
float3 PointLightColor[15];
};

StructuredBuffer<StrictLightData> strictLightData : register(t37);

bool GetClusterIndex(in float2 uv, in float z, out uint clusterIndex)
{
if (z < perPassLLF[0].LightsNear || z > perPassLLF[0].LightsFar)
Expand Down
31 changes: 21 additions & 10 deletions package/Shaders/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand All @@ -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];
Expand Down Expand Up @@ -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);
}
Expand Down
71 changes: 65 additions & 6 deletions src/Features/LightLimitFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Buffer>(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");
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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)
Expand Down Expand Up @@ -605,7 +664,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector<LightData>& lightsData
dimmer = 0.0f;
}

//light.color *= dimmer;
light.color *= dimmer;

float distantLightFadeStart = lightsFar * lightsFar * (lightFadeStart / lightFadeEnd);
float distantLightFadeEnd = lightsFar * lightsFar;
Expand All @@ -618,7 +677,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector<LightData>& 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) {
Expand All @@ -636,7 +695,7 @@ bool LightLimitFix::AddCachedParticleLights(eastl::vector<LightData>& 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{};
Expand Down
38 changes: 32 additions & 6 deletions src/Features/LightLimitFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,23 @@ struct LightLimitFix : Feature
uint EnableContactShadows;
uint EnableLightsVisualisation;
uint LightsVisualisationMode;
uint StrictLightsCount;
float LightsNear;
float LightsFar;
float4 CameraData;
float2 BufferDim;
uint FrameCount;
};

struct StrictLightData
{
uint NumLights;
float3 PointLightPosition[15];
float PointLightRadius[15];
float3 PointLightColor[15];
};

StrictLightData strictLightDataTemp;

struct CachedParticleLight
{
float grey;
Expand All @@ -79,6 +88,7 @@ struct LightLimitFix : Feature
};

std::unique_ptr<Buffer> perPass = nullptr;
std::unique_ptr<Buffer> strictLightData = nullptr;

bool rendered = false;
int eyeCount = !REL::Module::IsVR() ? 1 : 2;
Expand Down Expand Up @@ -107,8 +117,6 @@ struct LightLimitFix : Feature
eastl::hash_map<RE::BSGeometry*, ParticleLightInfo> queuedParticleLights;
eastl::hash_map<RE::BSGeometry*, ParticleLightInfo> particleLights;

std::uint32_t strictLightsCount = 0;

virtual void SetupResources();
virtual void Reset();

Expand Down Expand Up @@ -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
Expand All @@ -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<CachedParticleLight> cachedParticleLights;
uint32_t particleLightsDetectionHits = 0;
Expand All @@ -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<RE::BSShadowLight*>(a_light));
return func(a_property, a_light) && (!netimmerse_cast<RE::BSLightingShaderProperty*>(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast<RE::BSShadowLight*>(a_light)));
}
static inline REL::Relocation<decltype(thunk)> func;
};
Expand All @@ -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<RE::BSShadowLight*>(a_light));
return func(a_property, a_light) && (!netimmerse_cast<RE::BSLightingShaderProperty*>(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast<RE::BSShadowLight*>(a_light)));
}
static inline REL::Relocation<decltype(thunk)> func;
};
Expand All @@ -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<RE::BSShadowLight*>(a_light));
return func(a_property, a_light) && (!netimmerse_cast<RE::BSLightingShaderProperty*>(a_property) || (a_light->portalStrict || !a_light->portalGraph || skyrim_cast<RE::BSShadowLight*>(a_light)));
}
static inline REL::Relocation<decltype(thunk)> func;
};
Expand Down Expand Up @@ -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<decltype(thunk)> func;
};
Expand All @@ -247,6 +261,16 @@ struct LightLimitFix : Feature
static inline REL::Relocation<decltype(thunk)> 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<decltype(thunk)> func;
};

static void Install()
{
stl::write_thunk_call<ValidLight1>(REL::RelocationID(100994, 107781).address() + 0x92);
Expand All @@ -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<BSLightingShader_SetupGeometry_GeometrySetupConstantPointLights>(REL::RelocationID(100565, 107300).address() + REL::Relocate(0x523, 0xB0E, 0x5fe));
}
};
};
Expand Down