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
4 changes: 2 additions & 2 deletions package/Shaders/ISVolumetricLightingGenerateCS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ cbuffer PerTechnique : register(b0)
{ 0.001, 0.001, 0.001 }
};

float3 normalizedCoordinates = dispatchID.xyz * rcp(TextureDimensions.xyz);
float3 normalizedCoordinates = float3(dispatchID.xy + 0.5, dispatchID.z - 1.0) * rcp(TextureDimensions.xyz);
float2 uv = normalizedCoordinates.xy;
uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(uv);
float3 depthUv = Stereo::ConvertFromStereoUV(normalizedCoordinates, eyeIndex) + StepCoefficients[IterationIndex];
Expand All @@ -94,7 +94,7 @@ cbuffer PerTechnique : register(b0)

float shadowMapDepth = positionCSShifted.z;

bool noShadow = true;
bool noShadow = !SharedData::InInterior;
if (EndSplitDistances.z >= shadowMapDepth) {
uint cascadeIndex = ShadowMapCount >= 3.0f && shadowMapDepth > EndSplitDistances.y ? 2 : shadowMapDepth > EndSplitDistances.x ? 1 : 0;
float shadowMapThreshold = cascadeIndex == 0 ? 0.01f : 0.0f;
Expand Down
17 changes: 10 additions & 7 deletions package/Shaders/Utility.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,9 @@ PS_OUTPUT main(PS_INPUT input)
uint3 seed = Random::pcg3d(uint3(input.PositionCS.xy, input.PositionCS.x * Math::PI));

# if defined(RENDER_SHADOWMASK)
if(SharedData::InInterior)
shadowColor = float4(0,0,0,0);

if (EndSplitDistances.z >= shadowMapDepth) {
float4x3 lightProjectionMatrix = ShadowMapProj[eyeIndex][0];
float shadowMapThreshold = AlphaTestRef.y;
Expand All @@ -647,13 +650,13 @@ PS_OUTPUT main(PS_INPUT input)

# if SHADOWFILTER == 0
float shadowMapValue = TexShadowMapSampler.Sample(SampShadowMapSampler, float3(positionLS.xy, cascadeIndex)).x;
if (shadowMapValue >= positionLS.z - shadowMapThreshold) {
if (shadowMapValue >= positionLS.z) {
shadowVisibility = 1;
}
# elif SHADOWFILTER == 1
shadowVisibility = TexShadowMapSamplerComp.SampleCmpLevelZero(SampShadowMapSamplerComp, float3(positionLS.xy, cascadeIndex), positionLS.z - shadowMapThreshold).x;
shadowVisibility = TexShadowMapSamplerComp.SampleCmpLevelZero(SampShadowMapSamplerComp, float3(positionLS.xy, cascadeIndex), positionLS.z).x;
# elif SHADOWFILTER == 3
shadowVisibility = GetPoissonDiskFilteredShadowVisibility(noise, rotationMatrix, TexShadowMapSamplerComp, SampShadowMapSamplerComp, positionLS.xy, cascadeIndex, positionLS.z - shadowMapThreshold, false);
shadowVisibility = GetPoissonDiskFilteredShadowVisibility(noise, rotationMatrix, TexShadowMapSamplerComp, SampShadowMapSamplerComp, positionLS.xy, cascadeIndex, positionLS.z, false);
# endif

if (cascadeIndex < 1 && StartSplitDistances.y < shadowMapDepth) {
Expand All @@ -663,13 +666,13 @@ PS_OUTPUT main(PS_INPUT input)

# if SHADOWFILTER == 0
float cascade1ShadowMapValue = TexShadowMapSampler.Sample(SampShadowMapSampler, float3(cascade1PositionLS.xy, 1)).x;
if (cascade1ShadowMapValue >= cascade1PositionLS.z - AlphaTestRef.z) {
if (cascade1ShadowMapValue >= cascade1PositionLS.z) {
cascade1ShadowVisibility = 1;
}
# elif SHADOWFILTER == 1
cascade1ShadowVisibility = TexShadowMapSamplerComp.SampleCmpLevelZero(SampShadowMapSamplerComp, float3(cascade1PositionLS.xy, 1), cascade1PositionLS.z - AlphaTestRef.z).x;
cascade1ShadowVisibility = TexShadowMapSamplerComp.SampleCmpLevelZero(SampShadowMapSamplerComp, float3(cascade1PositionLS.xy, 1), cascade1PositionLS.z).x;
# elif SHADOWFILTER == 3
cascade1ShadowVisibility = GetPoissonDiskFilteredShadowVisibility(noise, rotationMatrix, TexShadowMapSamplerComp, SampShadowMapSamplerComp, cascade1PositionLS.xy, 1, cascade1PositionLS.z - AlphaTestRef.z, false);
cascade1ShadowVisibility = GetPoissonDiskFilteredShadowVisibility(noise, rotationMatrix, TexShadowMapSamplerComp, SampShadowMapSamplerComp, cascade1PositionLS.xy, 1, cascade1PositionLS.z, false);
# endif

float cascade1BlendFactor = smoothstep(0, 1, (shadowMapDepth - StartSplitDistances.y) / (EndSplitDistances.x - StartSplitDistances.y));
Expand All @@ -692,7 +695,7 @@ PS_OUTPUT main(PS_INPUT input)
shadowVisibility = min(shadowVisibility, lerp(1, focusShadowVisibility, focusShadowFade));
}

shadowColor.xyzw = fadeFactor * (shadowVisibility - 1) + 1;
shadowColor.xyzw = lerp(1.0 * !SharedData::InInterior, shadowVisibility, fadeFactor);
}
# elif defined(RENDER_SHADOWMASKSPOT)
float4 positionLS = mul(transpose(ShadowMapProj[eyeIndex][0]), float4(positionMS.xyz, 1));
Expand Down
5 changes: 4 additions & 1 deletion src/EngineFix.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#include "EngineFix.h"

#include "EngineFixes/ShadowmapCascadeCullingFix.h"
#include "EngineFixes/ShadowmapCascadeRasterizerFix.h"

const std::vector<EngineFix*>& EngineFix::GetOnPostPostLoadFixesList()
{
static ShadowmapCascadeCullingFix shadowmapCascadeCullingFix;
static ShadowmapRasterizerFix shadowmapRasterizerFix;

static std::vector<EngineFix*> fixes = {
&shadowmapCascadeCullingFix
&shadowmapCascadeCullingFix,
&shadowmapRasterizerFix
};

return fixes;
Expand Down
67 changes: 67 additions & 0 deletions src/EngineFixes/ShadowmapCascadeRasterizerFix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "ShadowmapCascadeRasterizerFix.h"

void ShadowmapRasterizerFix::Install()
{
// This function is called once per cascade to begin the updating and rendering process
stl::write_thunk_call<BSShadowDirectionalLight_RenderShadowmaps_RenderCascade>(REL::RelocationID(101495, 108489).address() + REL::Relocate(0xC6, 0xC6));

gRasterStates = reinterpret_cast<RasterStateArray*>(REL::RelocationID(524748, 411363).address());
Comment thread
Dawntic marked this conversation as resolved.
}

void ShadowmapRasterizerFix::BSShadowDirectionalLight_RenderShadowmaps_RenderCascade::thunk(RE::BSShadowDirectionalLight* light, void* arg1, void* arg2, uint32_t flags)
{
static uint cascade = 0;

static bool initialized = false;
if (!initialized) {
//Backup
if (cascade == 0) {
std::memcpy(backupGameRasterStates, *gRasterStates, sizeof(RasterStateArray));
numCascades = std::min(RE::GetINISetting("iNumSplits:Display")->data.u, maxCascades);
}
Comment thread
Dawntic marked this conversation as resolved.

//Clone
CloneRasterStates(gRasterStates, cascade);

initialized = cascade == numCascades - 1;
}

//Emplace
std::memcpy(*gRasterStates, shadowmapRasterStates[cascade], sizeof(RasterStateArray));

func(light, arg1, arg2, flags);

//Restore
if (cascade == numCascades - 1)
std::memcpy(*gRasterStates, backupGameRasterStates, sizeof(RasterStateArray));

cascade = ++cascade < numCascades ? cascade : 0;
}
Comment thread
Dawntic marked this conversation as resolved.

void ShadowmapRasterizerFix::GetUpdatedRasterDesc(D3D11_RASTERIZER_DESC& outputDesc, ShadowMapRasterizerDescriptor shadowmapDesc)
{
outputDesc.DepthBias = shadowmapDesc.rasterDepthBias;
outputDesc.DepthBiasClamp = shadowmapDesc.rasterDepthBiasClamp;
outputDesc.SlopeScaledDepthBias = shadowmapDesc.rasterSlopeScaleBias;
}

// Since state objects are shared globally across the pipeline we make duplicate arrays that cover the same range of states the game does
void ShadowmapRasterizerFix::CloneRasterStates(RasterStateArray* inputArray, int cascade)
{
for (int fill = 0; fill < 2; fill++) {
for (int cull = 0; cull < 3; cull++) {
for (int depth = 0; depth < 12; depth++) {
for (int scissor = 0; scissor < 2; scissor++) {
if (auto* gRasterizer = (*inputArray)[fill][cull][depth][scissor]) {
D3D11_RASTERIZER_DESC desc{};
gRasterizer->GetDesc(&desc);

GetUpdatedRasterDesc(desc, cascadeDescriptors[cascade]);

DX::ThrowIfFailed(globals::d3d::device->CreateRasterizerState(&desc, &shadowmapRasterStates[cascade][fill][cull][depth][scissor]));
}
Comment thread
Dawntic marked this conversation as resolved.
}
}
}
}
}
Comment thread
Dawntic marked this conversation as resolved.
51 changes: 51 additions & 0 deletions src/EngineFixes/ShadowmapCascadeRasterizerFix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

// This overrides the shadow cascade rasterizers to fix issues with peter panning and self shadowing
struct ShadowmapRasterizerFix : EngineFix
{
std::string GetName() override { return "Shadowmap Cascade Rasterizer Fix"; }
void Install() override;

using RasterStateArray = ID3D11RasterizerState* [2][3][12][2];

static void CloneRasterStates(RasterStateArray* inputArray, int cascade);

static constexpr uint maxCascades = 3;
static inline uint numCascades = 0;

static inline RasterStateArray* gRasterStates = nullptr;
static inline RasterStateArray backupGameRasterStates = {};
static inline RasterStateArray shadowmapRasterStates[maxCascades] = {};
Comment thread
Dawntic marked this conversation as resolved.

static constexpr int firstCascadeDepthBias = 160;
static constexpr float firstCascadeDepthBiasClamp = 0.015f;
static constexpr float firstCascadeSlopeScaleBias = 3.2f;

static constexpr int secondCascadeDepthBias = 100;
static constexpr float secondCascadeDepthBiasClamp = 0.015f;
static constexpr float secondCascadeSlopeScaleBias = 3.8f;

static constexpr int thirdCascadeDepthBias = 100;
static constexpr float thirdCascadeDepthBiasClamp = 0.015f;
static constexpr float thirdCascadeSlopeScaleBias = 3.8f;

struct ShadowMapRasterizerDescriptor
{
int rasterDepthBias;
float rasterDepthBiasClamp;
float rasterSlopeScaleBias;
};
static void GetUpdatedRasterDesc(D3D11_RASTERIZER_DESC& outputDesc, ShadowMapRasterizerDescriptor desc);

static constexpr ShadowMapRasterizerDescriptor cascadeDescriptors[maxCascades] = {
{ firstCascadeDepthBias, firstCascadeDepthBiasClamp, firstCascadeSlopeScaleBias },
{ secondCascadeDepthBias, secondCascadeDepthBiasClamp, secondCascadeSlopeScaleBias },
{ thirdCascadeDepthBias, thirdCascadeDepthBiasClamp, thirdCascadeSlopeScaleBias }
};

struct BSShadowDirectionalLight_RenderShadowmaps_RenderCascade
{
static void thunk(RE::BSShadowDirectionalLight* light, void* arg1, void* arg2, uint32_t flags);
static inline REL::Relocation<decltype(thunk)> func;
};
};