diff --git a/features/Terrain Shadows/Shaders/Features/TerrainShadows.ini b/features/Terrain Shadows/Shaders/Features/TerrainShadows.ini index 735cfd23a9..01aaedc093 100644 --- a/features/Terrain Shadows/Shaders/Features/TerrainShadows.ini +++ b/features/Terrain Shadows/Shaders/Features/TerrainShadows.ini @@ -1,2 +1,2 @@ [Info] -Version = 1-0-1 \ No newline at end of file +Version = 1-0-2 \ No newline at end of file diff --git a/features/Terrain Shadows/Shaders/TerrainShadows/ShadowUpdate.cs.hlsl b/features/Terrain Shadows/Shaders/TerrainShadows/ShadowUpdate.cs.hlsl index 42f7ef3632..2375fe2d76 100644 --- a/features/Terrain Shadows/Shaders/TerrainShadows/ShadowUpdate.cs.hlsl +++ b/features/Terrain Shadows/Shaders/TerrainShadows/ShadowUpdate.cs.hlsl @@ -81,7 +81,7 @@ groupshared float2 g_shadowHeight[NTHREADS]; float2 threadUV = rawThreadUV - floor(rawThreadUV); // wraparound float2 threadPxCoord = threadUV * dims; -float2 pastHeights = 0.0f.xx; + float2 pastHeights = 0.0; if (isValid) { pastHeights = RWTexShadowHeights[uint2(threadPxCoord)]; diff --git a/features/Terrain Shadows/Shaders/TerrainShadows/TerrainShadows.hlsli b/features/Terrain Shadows/Shaders/TerrainShadows/TerrainShadows.hlsli index c30fc6a19f..d87a6524b1 100644 --- a/features/Terrain Shadows/Shaders/TerrainShadows/TerrainShadows.hlsli +++ b/features/Terrain Shadows/Shaders/TerrainShadows/TerrainShadows.hlsli @@ -9,7 +9,7 @@ namespace TerrainShadows float GetTerrainZ(float norm_z) { - return lerp(SharedData::terraOccSettings.ZRange.x, SharedData::terraOccSettings.ZRange.y, norm_z) - 1024; + return lerp(SharedData::terraOccSettings.ZRange.x, SharedData::terraOccSettings.ZRange.y, norm_z) - 256; } float2 GetTerrainZ(float2 norm_z) diff --git a/package/Shaders/Common/Permutation.hlsli b/package/Shaders/Common/Permutation.hlsli index 5cd4babe9c..5a45489dfd 100644 --- a/package/Shaders/Common/Permutation.hlsli +++ b/package/Shaders/Common/Permutation.hlsli @@ -59,9 +59,8 @@ namespace Permutation static const uint InWorld = (1 << 0); static const uint InReflection = (1 << 1); static const uint IsBeastRace = (1 << 2); - static const uint EffectShadows = (1 << 3); - static const uint IsTree = (1 << 4); - static const uint GrassSphereNormal = (1 << 5); + static const uint IsTree = (1 << 3); + static const uint GrassSphereNormal = (1 << 4); } namespace ExtraFeatureFlags @@ -81,6 +80,8 @@ namespace Permutation uint PixelShaderDescriptor; uint ExtraShaderDescriptor; uint ExtraFeatureDescriptor; + + float EffectRadius; }; } diff --git a/package/Shaders/Common/ShadowSampling.hlsli b/package/Shaders/Common/ShadowSampling.hlsli index 000bfdb5cf..b6ac3cbe86 100644 --- a/package/Shaders/Common/ShadowSampling.hlsli +++ b/package/Shaders/Common/ShadowSampling.hlsli @@ -4,11 +4,23 @@ #include "Common/Math.hlsli" #include "Common/Random.hlsli" #include "Common/SharedData.hlsli" +#include "Common/Color.hlsli" + +#if defined(TERRAIN_SHADOWS) +# include "TerrainShadows/TerrainShadows.hlsli" +#endif + +#if defined(CLOUD_SHADOWS) +# include "CloudShadows/CloudShadows.hlsli" +#endif + +#if defined(IBL) +# include "IBL/IBL.hlsli" +#endif namespace ShadowSampling { - - Texture2DArray SharedShadowMap : register(t18); + Texture2D SharedShadowMap : register(t18); struct ShadowData { @@ -29,57 +41,130 @@ namespace ShadowSampling StructuredBuffer SharedShadowData : register(t19); + float GetWorldShadow(float3 positionWS, float3 offset, uint eyeIndex) + { + if (SharedData::InInterior || SharedData::HideSky) + return 1.0; + + float worldShadow = 1.0; +#if defined(TERRAIN_SHADOWS) + worldShadow = TerrainShadows::GetTerrainShadow(positionWS + offset, LinearSampler); +#endif + +#if defined(CLOUD_SHADOWS) + if (!SharedData::InMapMenu) + worldShadow *= CloudShadows::GetCloudShadowMult(positionWS, LinearSampler); +#endif + + return worldShadow; + } + float GetShadowDepth(float3 positionWS, uint eyeIndex) { float4 positionCSShifted = mul(FrameBuffer::CameraViewProj[eyeIndex], float4(positionWS, 1)); return positionCSShifted.z / positionCSShifted.w; } - float Get3DFilteredShadow(float3 positionWS, float3 viewDirection, float2 screenPosition, uint eyeIndex) + float Get3DFilteredShadow(float3 positionWS, float3 viewDirection, float2 screenPosition, uint eyeIndex, float depth) { - ShadowData sD = SharedShadowData[0]; + static const uint sampleCount8 = 8; + static const float rcpSampleCount8 = 1.0 / float(sampleCount8); + static const uint sampleCount8Minus1 = sampleCount8 - 1; - float fadeFactor = 1.0 - pow(saturate(dot(positionWS, positionWS) / sD.ShadowLightParam.z), 8); - uint sampleCount = ceil(8.0 * (1.0 - saturate(length(positionWS) / sqrt(sD.ShadowLightParam.z)))); + static const uint sampleCount16 = 16; + static const float rcpSampleCount16 = 1.0 / float(sampleCount16); + static const uint sampleCount16Minus1 = sampleCount16 - 1; - if (sampleCount == 0) - return 1.0; + float noise = Random::InterleavedGradientNoise(screenPosition, SharedData::FrameCount); + float noiseTransform = noise * 2.0 - 1.0; + float2 rotation; + sincos(Math::TAU * noise, rotation.y, rotation.x); + float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); + + float screenDepth = SharedData::GetScreenDepth(depth); + float objectDepth = length(positionWS); + float maxDistance = max(0, screenDepth - objectDepth); + +#if defined(EFFECT) + // Enough for non-billboards + enough for Sovngarde fog + float viewRayLength = min(Permutation::EffectRadius * 0.1, 128); + float3 startPosition = positionWS - viewDirection * viewRayLength; + float3 endPosition = positionWS + viewDirection * min(viewRayLength, maxDistance); +#elif defined(UNDERWATER) + // Enough for Eastmarch water + float viewRayLength = 128.0; + float3 startPosition = positionWS - viewDirection * viewRayLength; + float3 endPosition = positionWS; +#else + // Enough for Eastmarch water + float viewRayLength = 128.0; + float3 startPosition = positionWS; + float3 endPosition = positionWS + viewDirection * min(viewRayLength, maxDistance); +#endif + + float worldShadow = 0; + for(uint i = 0; i < sampleCount8; i++){ + uint noisyIndex = uint((float(i) + sampleCount8 * noise) % sampleCount8); + float t = (float(sampleCount8Minus1) - float(noisyIndex)) * rcpSampleCount8; + float tSample = t + noiseTransform * rcpSampleCount8; + + float3 samplePositionWS = lerp(startPosition, endPosition, tSample); + samplePositionWS.xy += mul(Random::SpiralSampleOffsets8[i], rotationMatrix) * viewRayLength; + samplePositionWS.z += length(Random::SpiralSampleOffsets8[i]); + + worldShadow += ShadowSampling::GetWorldShadow(samplePositionWS, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, eyeIndex); + } + + if (worldShadow == 0.0) + return 0.0; - float rcpSampleCount = rcp((float)sampleCount); + worldShadow *= rcpSampleCount8; - uint3 seed = Random::pcg3d(uint3(screenPosition.xy, screenPosition.x * Math::PI)); + float shadowMapDepth = GetShadowDepth(positionWS, eyeIndex); - float2 compareValue; - compareValue.x = mul(transpose(sD.ShadowMapProj[eyeIndex][0]), float4(positionWS, 1)).z - 0.01; - compareValue.y = mul(transpose(sD.ShadowMapProj[eyeIndex][1]), float4(positionWS, 1)).z - 0.01; + ShadowData sD = SharedShadowData[0]; + + // Early out beyond cascade 2 + if (sD.EndSplitDistances.w < shadowMapDepth) + return worldShadow; + + // Precompute cascade data + float cascade1Probability = saturate((shadowMapDepth - sD.StartSplitDistances.y) / (sD.EndSplitDistances.x - sD.StartSplitDistances.y)); + + float compareValues[2]; + float sampleRadii[2]; + float3 positionsLS[2]; + float3 viewOffsetsLS[2]; + for (uint cascadeIdx = 0; cascadeIdx < 2; cascadeIdx++) { + compareValues[cascadeIdx] = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIdx]), float4(positionWS, 1)).z - sD.AlphaTestRef[1 + cascadeIdx]; + sampleRadii[cascadeIdx] = sD.ShadowSampleParam.z * rcp(1 + cascadeIdx) * 2.0; + positionsLS[cascadeIdx] = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIdx]), float4(startPosition, 1)); + viewOffsetsLS[cascadeIdx] = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIdx]), float4(endPosition, 1)); + } float shadow = 0.0; - if (sD.EndSplitDistances.z >= GetShadowDepth(positionWS, eyeIndex)) { - for (uint i = 0; i < sampleCount; i++) { - float3 rnd = Random::R3Modified(i + SharedData::FrameCount * sampleCount, seed / 4294967295.f); - - // https://stats.stackexchange.com/questions/8021/how-to-generate-uniformly-distributed-points-in-the-3-d-unit-ball - float phi = rnd.x * Math::TAU; - float cos_theta = rnd.y * 2 - 1; - float sin_theta = sqrt(1 - cos_theta); - float r = rnd.z; - float4 sincos_phi; - sincos(phi, sincos_phi.y, sincos_phi.x); - float3 sampleOffset = viewDirection * (float(i) - float(sampleCount) * 0.5) * 64 * rcpSampleCount; - sampleOffset += float3(r * sin_theta * sincos_phi.x, r * sin_theta * sincos_phi.y, r * cos_theta) * 64; - - uint cascadeIndex = sD.EndSplitDistances.x < GetShadowDepth(positionWS.xyz + viewDirection * (sampleOffset.x + sampleOffset.y), eyeIndex); // Stochastic cascade sampling - - float3 positionLS = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIndex]), float4(positionWS + sampleOffset, 1)); - - float4 depths = SharedShadowMap.GatherRed(LinearSampler, float3(saturate(positionLS.xy), cascadeIndex), 0); - shadow += dot(depths > compareValue[cascadeIndex], 0.25); - } - } else { - shadow = 1.0; + for (uint k = 0; k < sampleCount16; k++) { + uint noisyIndex = (k + uint(sampleCount16 * noise)) % sampleCount16; + float t = float(sampleCount16Minus1 - noisyIndex) * rcpSampleCount16; + + // Probabilistically select cascade (0 or 1 within the pair) + uint cascadeIndex = uint(frac(t + noise) < cascade1Probability); + + // Offset along view ray with optimised sample pattern + float tSample = t + noiseTransform * rcpSampleCount16; + float3 sampledPositionLS = lerp(positionsLS[cascadeIndex], viewOffsetsLS[cascadeIndex], tSample); + + // Blur shadow with poisson disc + sampledPositionLS.xy += mul(Random::PoissonSampleOffsets16[k], rotationMatrix) * sampleRadii[cascadeIndex]; + + // Average 4 shadow samples for improved quality + float4 depths = SharedShadowMap.SampleLevel(LinearSampler, saturate(sampledPositionLS.xy), 1u - cascadeIndex); + float4 shadowVisibilities = float4(depths > compareValues[cascadeIndex]); + shadow += shadowVisibilities.x + shadowVisibilities.y + shadowVisibilities.z + shadowVisibilities.w; } - return lerp(1.0, shadow * rcpSampleCount, fadeFactor); + float fadeFactor = 1.0 - pow(saturate(dot(positionWS, positionWS) / sD.ShadowLightParam.z), 8); + return worldShadow * lerp(1.0, shadow * rcpSampleCount16 * 0.25, fadeFactor); } float Get2DFilteredShadowCascade(float noise, float2x2 rotationMatrix, float sampleOffsetScale, float2 baseUV, float cascadeIndex, float compareValue, uint eyeIndex) @@ -90,16 +175,14 @@ namespace ShadowSampling float visibility = 0.0; -#if defined(WATER) - sampleOffsetScale *= 2.0; -#endif + sampleOffsetScale *= 4.0; for (uint sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) { float2 sampleOffset = mul(Random::PoissonSampleOffsets16[sampleIndex], rotationMatrix); float2 sampleUV = layerIndexRcp * sampleOffset * sampleOffsetScale + baseUV; - float4 depths = SharedShadowMap.GatherRed(LinearSampler, float3(saturate(sampleUV), cascadeIndex), 0); + float4 depths = SharedShadowMap.SampleLevel(LinearSampler, saturate(sampleUV), 1 - cascadeIndex); visibility += dot(depths > compareValue, 0.25); } @@ -142,37 +225,6 @@ namespace ShadowSampling return 1.0; } - float GetWorldShadow(float3 positionWS, float3 offset, uint eyeIndex) - { - if (SharedData::InInterior || SharedData::HideSky) - return 1.0; - - float worldShadow = 1.0; -#if defined(TERRAIN_SHADOWS) - worldShadow = TerrainShadows::GetTerrainShadow(positionWS + offset, LinearSampler); -#endif - -#if defined(CLOUD_SHADOWS) - if (!SharedData::InMapMenu) - worldShadow *= CloudShadows::GetCloudShadowMult(positionWS, LinearSampler); -#endif - - return worldShadow; - } - - float GetEffectShadow(float3 worldPosition, float3 viewDirection, float2 screenPosition, uint eyeIndex, out bool isWorldShadow) - { - isWorldShadow = false; - float worldShadow = GetWorldShadow(worldPosition, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, eyeIndex); - if (worldShadow != 0.0) { - float shadow = Get3DFilteredShadow(worldPosition, viewDirection, screenPosition, eyeIndex); - isWorldShadow = shadow >= worldShadow; - return min(worldShadow, shadow); - } - isWorldShadow = true; - return worldShadow; - } - float GetLightingShadow(float noise, float3 worldPosition, uint eyeIndex) { float2 rotation; @@ -181,18 +233,56 @@ namespace ShadowSampling return Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); } - float GetWaterShadow(float noise, float3 worldPosition, uint eyeIndex) +#if defined(SKYLIGHTING) && !defined(INTERIOR) + void ExtractLighting(float3 inputColor, out float3 dirColor, out float3 ambientColor, float skylightingDiffuse) +#else + void ExtractLighting(float3 inputColor, out float3 dirColor, out float3 ambientColor) +#endif { - float worldShadow = GetWorldShadow(worldPosition, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, eyeIndex); - if (worldShadow != 0.0) { - float2 rotation; - sincos(Math::TAU * noise, rotation.y, rotation.x); - float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); - float shadow = Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); - return worldShadow * shadow; + float3 ambientColorAmb = max(0, mul(SharedData::DirectionalAmbient, float4(0, 0, 1, 1))); + +# if defined(IBL) + if (SharedData::iblSettings.EnableDiffuseIBL && (!SharedData::InInterior || SharedData::iblSettings.EnableInterior)) { + ambientColorAmb *= SharedData::iblSettings.DALCAmount; +# if defined(SKYLIGHTING) && !defined(INTERIOR) + float3 iblColor = Color::Saturation(ImageBasedLighting::GetIBLColor(float3(0, 0, -1), skylightingDiffuse), SharedData::iblSettings.IBLSaturation) * SharedData::iblSettings.DiffuseIBLScale; +# else + float3 iblColor = Color::Saturation(ImageBasedLighting::GetIBLColor(float3(0, 0, -1)), SharedData::iblSettings.IBLSaturation) * SharedData::iblSettings.DiffuseIBLScale; +# endif + ambientColorAmb += Color::IrradianceToGamma(iblColor); + } +# endif + + float llDirLightMult = (SharedData::linearLightingSettings.enableLinearLighting && !SharedData::linearLightingSettings.isDirLightLinear) ? SharedData::linearLightingSettings.dirLightMult : 1.0f; + float3 dirLightColorDir = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * llDirLightMult; + + { + float maxScale = 1.0; + if (ambientColorAmb.x > 0.0) + maxScale = min(maxScale, inputColor.x / ambientColorAmb.x); + if (ambientColorAmb.y > 0.0) + maxScale = min(maxScale, inputColor.y / ambientColorAmb.y); + if (ambientColorAmb.z > 0.0) + maxScale = min(maxScale, inputColor.z / ambientColorAmb.z); + ambientColorAmb *= maxScale; } - return worldShadow; + { + float maxScale = 1.0; + if (dirLightColorDir.x > 0.0) + maxScale = min(maxScale, inputColor.x / dirLightColorDir.x); + if (dirLightColorDir.y > 0.0) + maxScale = min(maxScale, inputColor.y / dirLightColorDir.y); + if (dirLightColorDir.z > 0.0) + maxScale = min(maxScale, inputColor.z / dirLightColorDir.z); + dirLightColorDir *= maxScale; + } + + float3 dirLightColorAmb = max(0.0, inputColor - ambientColorAmb); + float3 ambientColorDir = max(0.0, inputColor - dirLightColorDir); + + dirColor = lerp(dirLightColorAmb, dirLightColorDir, 0.0); + ambientColor = lerp(ambientColorAmb, ambientColorDir, 0.0); } } diff --git a/package/Shaders/DistantTree.hlsl b/package/Shaders/DistantTree.hlsl index 86236d35f1..345031bd2b 100644 --- a/package/Shaders/DistantTree.hlsl +++ b/package/Shaders/DistantTree.hlsl @@ -167,14 +167,6 @@ const static float DepthOffsets[16] = { # include "ScreenSpaceShadows/ScreenSpaceShadows.hlsli" # endif -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # if defined(IBL) # include "IBL/IBL.hlsli" # endif diff --git a/package/Shaders/DownsampleShadowCS.hlsl b/package/Shaders/DownsampleShadowCS.hlsl new file mode 100644 index 0000000000..f8c7145072 --- /dev/null +++ b/package/Shaders/DownsampleShadowCS.hlsl @@ -0,0 +1,51 @@ +Texture2DArray InputTexture : register(t0); +RWTexture2D OutputTexture : register(u0); + +SamplerState PointSampler : register(s0); + +#if defined(DOWNSAMPLE_SHADOW_MIP0) +[numthreads(8, 8, 1)] void main(uint3 dispatchThreadID : SV_DispatchThreadID) { + uint w, h; + OutputTexture.GetDimensions(w, h); + + if (dispatchThreadID.x < w && dispatchThreadID.y < h) + { + // Each thread gathers a 2x2 block and packs into RGBA + uint2 pixCoord = dispatchThreadID.xy * 2; + + uint inputW, inputH, inputSlices; + InputTexture.GetDimensions(inputW, inputH, inputSlices); + float2 uv = (pixCoord + 0.5) / float2(inputW, inputH); + + OutputTexture[dispatchThreadID.xy] = InputTexture.GatherRed(PointSampler, float3(uv, 1)); + } +} +#elif defined(DOWNSAMPLE_SHADOW_MIP1) +groupshared float g_scratchDepths[8][8]; + +[numthreads(8, 8, 1)] void main(uint3 dispatchThreadID : SV_DispatchThreadID, uint3 groupThreadID : SV_GroupThreadID) { + // MIP 0 -> 1: each thread gathers a 2x2 block and averages + uint2 pixCoord = dispatchThreadID.xy * 2; + + uint inputW, inputH, inputSlices; + InputTexture.GetDimensions(inputW, inputH, inputSlices); + float2 uv = (pixCoord + 0.5) / float2(inputW, inputH); + + float4 depths4 = InputTexture.GatherRed(PointSampler, float3(uv, 0)); + + g_scratchDepths[groupThreadID.x][groupThreadID.y] = dot(depths4, 0.25); + + GroupMemoryBarrierWithGroupSync(); + + // MIP 1 -> 2: 2x2 reduction in shared memory (4x4 total) + [branch] + if (all((groupThreadID.xy % 2) == 0)) + { + float inTL = g_scratchDepths[groupThreadID.x + 0][groupThreadID.y + 0]; + float inTR = g_scratchDepths[groupThreadID.x + 1][groupThreadID.y + 0]; + float inBL = g_scratchDepths[groupThreadID.x + 0][groupThreadID.y + 1]; + float inBR = g_scratchDepths[groupThreadID.x + 1][groupThreadID.y + 1]; + OutputTexture[dispatchThreadID.xy / 2] = float4(inTL, inTR, inBL, inBR); + } +} +#endif \ No newline at end of file diff --git a/package/Shaders/Effect.hlsl b/package/Shaders/Effect.hlsl index 980cf084f7..486f3a9a84 100644 --- a/package/Shaders/Effect.hlsl +++ b/package/Shaders/Effect.hlsl @@ -514,14 +514,6 @@ cbuffer PerGeometry : register(b2) # define LinearSampler SampBaseSampler -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # if defined(SKYLIGHTING) # include "Skylighting/Skylighting.hlsli" # endif @@ -532,106 +524,54 @@ cbuffer PerGeometry : register(b2) # include "Common/ShadowSampling.hlsli" -float ComputeShadowVariance(float shadow) -{ - // Measure local gradient magnitude; classify "no variation" using a small threshold. - const float2 grad = float2(ddx(shadow), ddy(shadow)); - const float v = abs(grad.x) + abs(grad.y) + fwidth(shadow); - const float epsilon = 1e-4; - return (v < epsilon) ? 1.0 : 0.0; -} - # if defined(LIGHTING) -float3 GetLightingColor(float3 msPosition, float3 worldPosition, float4 screenPosition, uint eyeIndex, inout float shadowVariance) +float3 GetLightingColor(float3 msPosition, float3 worldPosition, float2 screenPosition, uint eyeIndex, float depth, inout float shadowVariance) { - float4 lightDistanceSquared = (PLightPositionX[eyeIndex] - msPosition.xxxx) * (PLightPositionX[eyeIndex] - msPosition.xxxx) + (PLightPositionY[eyeIndex] - msPosition.yyyy) * (PLightPositionY[eyeIndex] - msPosition.yyyy) + (PLightPositionZ[eyeIndex] - msPosition.zzzz) * (PLightPositionZ[eyeIndex] - msPosition.zzzz); - float4 lightFadeMul = 1.0.xxxx - saturate(PLightingRadiusInverseSquared * lightDistanceSquared); - float3 color = DLightColor.xyz * Color::EffectLightingMult(); - if ((Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::EffectShadows)) { - float llDirLightMult = (SharedData::linearLightingSettings.enableLinearLighting && !SharedData::linearLightingSettings.isDirLightLinear) ? SharedData::linearLightingSettings.dirLightMult : 1.0f; - float3 dirLightColor = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * llDirLightMult * 0.5 * Color::EffectLightingMult(); - float3 ambientColor = max(0, mul(SharedData::DirectionalAmbient, float4(0, 0, 1, 1))); - -# if defined(IBL) - if (SharedData::iblSettings.EnableDiffuseIBL && (!SharedData::InInterior || SharedData::iblSettings.EnableInterior)) { - ambientColor *= SharedData::iblSettings.DALCAmount; - } -# endif - - color = ambientColor; - # if defined(SKYLIGHTING) # if defined(VR) - float3 positionMSSkylight = worldPosition + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; + float3 positionMSSkylight = worldPosition + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; # else - float3 positionMSSkylight = worldPosition; + float3 positionMSSkylight = worldPosition; # endif - sh2 skylightingSH = Skylighting::sampleNoBias(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, positionMSSkylight); - float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(0, 0, 1))) / Math::PI; - skylightingDiffuse = saturate(skylightingDiffuse); - skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(worldPosition)); - skylightingDiffuse = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse); + sh2 skylightingSH = Skylighting::sampleNoBias(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, positionMSSkylight); - color = Color::IrradianceToLinear(color); - color *= skylightingDiffuse; - color = Color::IrradianceToGamma(color); -# endif + float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(0, 0, 1))) / Math::PI; + skylightingDiffuse = saturate(skylightingDiffuse); + skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(worldPosition)); + skylightingDiffuse = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse); +# endif -# if defined(IBL) - float3 iblColor = 0; - if (SharedData::iblSettings.EnableDiffuseIBL) { - if (!SharedData::InInterior || SharedData::iblSettings.EnableInterior) - { -# if defined(SKYLIGHTING) - iblColor += Color::Saturation(ImageBasedLighting::GetIBLColor(float3(0, 0, -1), skylightingDiffuse), SharedData::iblSettings.IBLSaturation) * SharedData::iblSettings.DiffuseIBLScale; -# else - iblColor += Color::Saturation(ImageBasedLighting::GetIBLColor(float3(0, 0, -1)), SharedData::iblSettings.IBLSaturation) * SharedData::iblSettings.DiffuseIBLScale; -# endif - color += Color::IrradianceToGamma(iblColor); - } - } + float3 dirColor; + float3 ambientColor; +# if defined(SKYLIGHTING) + ShadowSampling::ExtractLighting(color, dirColor, ambientColor, skylightingDiffuse); +# else + ShadowSampling::ExtractLighting(color, dirColor, ambientColor); # endif - if (!SharedData::InInterior){ - bool isWorldShadow = false; - float shadow = ShadowSampling::GetEffectShadow(worldPosition.xyz, normalize(worldPosition.xyz), screenPosition.xy, eyeIndex, isWorldShadow); - color += dirLightColor * shadow; - // Do not denoise world shadows - if (!isWorldShadow) - shadowVariance = ComputeShadowVariance(shadow); - } else { - color += dirLightColor; - } - } else { -# if defined(SKYLIGHTING) -# if defined(VR) - float3 positionMSSkylight = worldPosition + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; -# else - float3 positionMSSkylight = worldPosition; -# endif + float shadow = ShadowSampling::Get3DFilteredShadow(worldPosition.xyz, normalize(worldPosition.xyz), screenPosition, eyeIndex, depth); - sh2 skylightingSH = Skylighting::sampleNoBias(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, positionMSSkylight); + shadowVariance = 1.0 - sqrt(saturate(fwidth(shadow))); - if (!SharedData::InInterior) { - float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(0, 0, 1))) / Math::PI; - skylightingDiffuse = saturate(skylightingDiffuse); - skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(worldPosition)); - skylightingDiffuse = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse); + dirColor *= shadow; - color = Color::IrradianceToLinear(color); - color *= skylightingDiffuse; - color = Color::IrradianceToGamma(color); - } +# if defined(SKYLIGHTING) + ambientColor = Color::IrradianceToLinear(ambientColor); + ambientColor *= skylightingDiffuse; + ambientColor = Color::IrradianceToGamma(ambientColor); # endif - } + + color = dirColor + ambientColor; # if defined(LIGHT_LIMIT_FIX) if (!(Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::InWorld)) # endif { + float4 lightDistanceSquared = (PLightPositionX[eyeIndex] - msPosition.xxxx) * (PLightPositionX[eyeIndex] - msPosition.xxxx) + (PLightPositionY[eyeIndex] - msPosition.yyyy) * (PLightPositionY[eyeIndex] - msPosition.yyyy) + (PLightPositionZ[eyeIndex] - msPosition.zzzz) * (PLightPositionZ[eyeIndex] - msPosition.zzzz); + float4 lightFadeMul = 1.0.xxxx - saturate(PLightingRadiusInverseSquared * lightDistanceSquared); color.x += dot(Color::PointLight(PLightColorR.xxx).x * lightFadeMul * Color::EffectLightingMult(), 1.0.xxxx); color.y += dot(Color::PointLight(PLightColorG.xxx).x * lightFadeMul * Color::EffectLightingMult(), 1.0.xxxx); color.z += dot(Color::PointLight(PLightColorB.xxx).x * lightFadeMul * Color::EffectLightingMult(), 1.0.xxxx); @@ -639,7 +579,56 @@ float3 GetLightingColor(float3 msPosition, float3 worldPosition, float4 screenPo return color; } -# endif +# else +float3 GetLightingShadow(float3 color, float3 worldPosition, float2 screenPosition, float depth, uint eyeIndex, inout float shadowVariance) +{ + float3 dirColor; + float3 ambientColor; + float skylightingDiffuse = 1.0; +# if defined(SKYLIGHTING) + ShadowSampling::ExtractLighting(color, dirColor, ambientColor, skylightingDiffuse); +# else + ShadowSampling::ExtractLighting(color, dirColor, ambientColor); +# endif + + static const uint sampleCount = 8; + static const float rcpSampleCount = 1.0 / float(sampleCount); + + float noise = Random::InterleavedGradientNoise(screenPosition, SharedData::FrameCount); + float noiseTransform = noise * 2.0 - 1.0; + float2 rotation; + sincos(Math::TAU * noise, rotation.y, rotation.x); + float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); + + // Enough for sky statics + float maxDistance = max(0, SharedData::GetScreenDepth(depth)); + float viewRayLength = 4096.0; + float3 viewDirection = normalize(worldPosition); + float3 startPosition = worldPosition - viewDirection * viewRayLength; + float3 endPosition = worldPosition + viewDirection * min(maxDistance, viewRayLength); + + float shadow = 0; + for(uint i = 0; i < sampleCount; i++){ + uint noisyIndex = uint((float(i) + sampleCount * noise) % sampleCount); + float t = (float(sampleCount) - float(noisyIndex + 1)) * rcpSampleCount; + float tSample = t + noiseTransform * rcpSampleCount; + + float3 samplePositionWS = lerp(startPosition, endPosition, tSample); + samplePositionWS.xy += mul(Random::SpiralSampleOffsets8[i], rotationMatrix) * 4096.0; + samplePositionWS.z += length(Random::SpiralSampleOffsets8[i]); + + shadow += ShadowSampling::GetWorldShadow(samplePositionWS, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, eyeIndex); + } + + shadow *= rcpSampleCount; + + shadowVariance = 1.0 - sqrt(saturate(fwidth(shadow))); + + dirColor *= shadow; + + return dirColor + ambientColor; +} +#endif PS_OUTPUT main(PS_INPUT input) { @@ -689,8 +678,9 @@ PS_OUTPUT main(PS_INPUT input) # endif float softMul = 1; + float depth = 1; # if defined(SOFT) - float depth = TexDepthSamplerEffect.Load(int3(input.Position.xy, 0)).x; + depth = TexDepthSamplerEffect.Load(int3(input.Position.xy, 0)).x; softMul = saturate(-input.TexCoord0.w + LightingInfluence.y / ((1 - depth) * CameraDataEffect.z + CameraDataEffect.y)); # endif @@ -699,42 +689,42 @@ PS_OUTPUT main(PS_INPUT input) float shadowVariance = 1.0; # if defined(LIGHTING) - propertyColor = GetLightingColor(input.MSPosition.xyz, input.WorldPosition.xyz, input.Position.xyzw, eyeIndex, shadowVariance); + propertyColor = GetLightingColor(input.MSPosition.xyz, input.WorldPosition.xyz, input.Position.xy, eyeIndex, depth, shadowVariance); # if defined(LIGHT_LIMIT_FIX) uint lightCount = 0; - if (LightingInfluence.x > 0.0) { - float3 viewPosition = mul(FrameBuffer::CameraView[eyeIndex], float4(input.WorldPosition.xyz, 1)).xyz; - float2 screenUV = FrameBuffer::ViewToUV(viewPosition, true, eyeIndex); - bool inWorld = Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::InWorld; - - uint clusterIndex = 0; - if (inWorld && LightLimitFix::GetClusterIndex(screenUV, viewPosition.z, clusterIndex)) { - lightCount = LightLimitFix::lightGrid[clusterIndex].lightCount; - uint lightOffset = LightLimitFix::lightGrid[clusterIndex].offset; - [loop] for (uint i = 0; i < lightCount; i++) - { - uint clusteredLightIndex = LightLimitFix::lightList[lightOffset + i]; - LightLimitFix::Light light = LightLimitFix::lights[clusteredLightIndex]; - if (LightLimitFix::IsLightIgnored(light) || light.lightFlags & LightLimitFix::LightFlags::Shadow) { - continue; - } - float3 lightDirection = light.positionWS[eyeIndex].xyz - input.WorldPosition.xyz; - float lightDist = length(lightDirection); + + float3 viewPosition = mul(FrameBuffer::CameraView[eyeIndex], float4(input.WorldPosition.xyz, 1)).xyz; + float2 screenUV = FrameBuffer::ViewToUV(viewPosition, true, eyeIndex); + bool inWorld = Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::InWorld; + + uint clusterIndex = 0; + if (inWorld && LightLimitFix::GetClusterIndex(screenUV, viewPosition.z, clusterIndex)) { + lightCount = LightLimitFix::lightGrid[clusterIndex].lightCount; + uint lightOffset = LightLimitFix::lightGrid[clusterIndex].offset; + [loop] for (uint i = 0; i < lightCount; i++) + { + uint clusteredLightIndex = LightLimitFix::lightList[lightOffset + i]; + LightLimitFix::Light light = LightLimitFix::lights[clusteredLightIndex]; + if (LightLimitFix::IsLightIgnored(light) || light.lightFlags & LightLimitFix::LightFlags::Shadow) { + continue; + } + float3 lightDirection = light.positionWS[eyeIndex].xyz - input.WorldPosition.xyz; + float lightDist = length(lightDirection); # if defined(ISL) - float intensityMultiplier = InverseSquareLighting::GetAttenuation(lightDist, light); + float intensityMultiplier = InverseSquareLighting::GetAttenuation(lightDist, light); # else - float intensityFactor = saturate(lightDist / light.radius); - float intensityMultiplier = 1 - intensityFactor * intensityFactor; + float intensityFactor = saturate(lightDist / light.radius); + float intensityMultiplier = 1 - intensityFactor * intensityFactor; # endif - const bool isPointLightLinear = light.lightFlags & LightLimitFix::LightFlags::Linear; - float3 lightColor = Color::PointLight(light.color.xyz, isPointLightLinear) * intensityMultiplier * 0.5 * light.fade * Color::EffectLightingMult(); - propertyColor += lightColor; - } + const bool isPointLightLinear = light.lightFlags & LightLimitFix::LightFlags::Linear; + float3 lightColor = Color::PointLight(light.color.xyz, isPointLightLinear) * intensityMultiplier * 0.5 * light.fade * Color::EffectLightingMult(); + propertyColor += lightColor; } } + # endif # elif defined(MEMBRANE) propertyColor *= 0; @@ -817,7 +807,7 @@ PS_OUTPUT main(PS_INPUT input) baseColor.xyz = Color::Effect(baseColorScale * TexGrayscaleSampler.Sample(SampGrayscaleSampler, grayscaleToColorUv).xyz); } - float3 lightColor = lerp(baseColor.xyz, propertyColor * baseColor.xyz, lightingInfluence.xxx); + float3 lightColor = lerp(baseColor.xyz, propertyColor * baseColor.xyz, lightingInfluence); # if !defined(MOTIONVECTORS_NORMALS) if (alpha * fogMul.w - AlphaTestRefRS < 0) { @@ -825,6 +815,11 @@ PS_OUTPUT main(PS_INPUT input) } # endif +#if !defined(LIGHTING) && defined(VC) && defined(TEXCOORD) && defined(NORMALS) && defined(TEXTURE) && defined(FALLOFF) && defined(SOFT) + if(Permutation::PixelShaderDescriptor & Permutation::EffectFlags::GrayscaleToAlpha && lightingInfluence == 1.0) + lightColor = GetLightingShadow(lightColor, input.WorldPosition.xyz, input.Position.xy, depth, eyeIndex, shadowVariance); +#endif + # if !defined(MOTIONVECTORS_NORMALS) # if defined(ADDBLEND) float3 blendedColor = lightColor * (1 - Color::FogAlpha(input.FogParam.w).xxx); diff --git a/package/Shaders/ISVolumetricLightingGenerateCS.hlsl b/package/Shaders/ISVolumetricLightingGenerateCS.hlsl index 01372dedb4..23053313c4 100644 --- a/package/Shaders/ISVolumetricLightingGenerateCS.hlsl +++ b/package/Shaders/ISVolumetricLightingGenerateCS.hlsl @@ -20,14 +20,6 @@ RWTexture3D DensityRW : register(u0); # include "Common/Framebuffer.hlsli" # include "Common/SharedData.hlsli" -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # include "Common/ShadowSampling.hlsli" cbuffer PerTechnique : register(b0) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index e01129f82a..ff42265d45 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -905,14 +905,6 @@ float GetSnowParameterY(float texProjTmp, float alpha) # undef SOFT_LIGHTING # endif -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # if defined(SKYLIGHTING) # include "Skylighting/Skylighting.hlsli" # endif diff --git a/package/Shaders/Particle.hlsl b/package/Shaders/Particle.hlsl index 9a725c336a..87b77e3bb3 100644 --- a/package/Shaders/Particle.hlsl +++ b/package/Shaders/Particle.hlsl @@ -247,14 +247,6 @@ cbuffer PerGeometry : register(b2) float3 TextureSize : packoffset(c1); }; -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # define LinearSampler SampSourceTexture # include "Common/ShadowSampling.hlsli" diff --git a/package/Shaders/RunGrass.hlsl b/package/Shaders/RunGrass.hlsl index a57bec6f1f..b297af415f 100644 --- a/package/Shaders/RunGrass.hlsl +++ b/package/Shaders/RunGrass.hlsl @@ -434,14 +434,6 @@ cbuffer AlphaTestRefCB : register(b11) # include "DynamicCubemaps/DynamicCubemaps.hlsli" # endif -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # if defined(SKYLIGHTING) # include "Skylighting/Skylighting.hlsli" # endif diff --git a/package/Shaders/Water.hlsl b/package/Shaders/Water.hlsl index e7d3011ee1..8773dab99d 100644 --- a/package/Shaders/Water.hlsl +++ b/package/Shaders/Water.hlsl @@ -434,18 +434,10 @@ float CalculateDepthMultFromUV(float2 uv, float depth, uint eyeIndex = 0) # define SampColorSampler Normals01Sampler # define LinearSampler Normals01Sampler -# if defined(TERRAIN_SHADOWS) -# include "TerrainShadows/TerrainShadows.hlsli" -# endif - # if defined(SKYLIGHTING) # include "Skylighting/Skylighting.hlsli" # endif -# if defined(CLOUD_SHADOWS) -# include "CloudShadows/CloudShadows.hlsli" -# endif - # include "Common/ShadowSampling.hlsli" # if defined(SIMPLE) || defined(UNDERWATER) || defined(LOD) || defined(SPECULAR) @@ -684,10 +676,11 @@ struct WaterNormalData float4 rippleInfo; // xyz = scaled ripple normal (normalized normal * intensity), w = splash effect intensity }; -WaterNormalData GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth, uint eyeIndex) +WaterNormalData GetWaterNormal(PS_INPUT input, float distanceFactor, float normalsDepthFactor, float3 viewDirection, float depth, uint eyeIndex, float wetnessOcclusion) { WaterNormalData result; result.rippleInfo = float4(0, 0, 0, 0); + float3 normalScalesRcp = rcp(input.NormalsScale.xyz); # if defined(WATER_PARALLAX) @@ -802,21 +795,6 @@ WaterNormalData GetWaterNormal(PS_INPUT input, float distanceFactor, float norma // Wetness Effects Debug System: // DEBUG_WETNESS_EFFECTS Color Legend: // - BRIGHT MAGENTA: Ripples, BRIGHT GREEN: Splashes, CYAN: Both effects - const bool inWorld = (Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::InWorld); -# if defined(SKYLIGHTING) -# if defined(VR) - float3 positionMSSkylight = input.WPosition.xyz + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; -# else - float3 positionMSSkylight = input.WPosition.xyz; -# endif - sh2 skylightingSH = Skylighting::sample(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, Skylighting::stbn_vec3_2Dx1D_128x128x64, input.HPosition.xy, positionMSSkylight, float3(0, 0, 1)); - float skylighting = SphericalHarmonics::Unproject(skylightingSH, float3(0, 0, 1)); - - float wetnessOcclusion = inWorld ? pow(saturate(skylighting), 2) : 0; -# else - float wetnessOcclusion = inWorld; -# endif - float4 raindropInfo = float4(0, 0, 1, 0); float maxRainDropDistance = SharedData::wetnessEffectsSettings.RaindropFxRange * SharedData::wetnessEffectsSettings.RaindropFxRange * 3; float rainDropDistance = dot(input.WPosition, input.WPosition); @@ -863,111 +841,69 @@ WaterNormalData GetWaterNormal(PS_INPUT input, float distanceFactor, float norma return result; } -float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection, - float distanceFactor, float refractionsDepthFactor, uint eyeIndex = 0) +float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection, float distanceFactor, float skylightingSpecular) { - if (Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Reflections) { - float3 finalSsrReflectionColor = 0.0.xxx; - float ssrFraction = 0.0; - float3 reflectionColor = 0.0.xxx; - float3 R = reflect(viewDirection, WaterParams.y * normal + float3(0, 0, 1 - WaterParams.y)); - - if (Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Cubemap) { -# if defined(DYNAMIC_CUBEMAPS) -# if defined(SKYLIGHTING) - - float3 dynamicCubemap; - if (SharedData::InInterior) { - dynamicCubemap = DynamicCubemaps::EnvTexture.SampleLevel(CubeMapSampler, R, 0).xyz; - } else { -# if defined(VR) - float3 positionMSSkylight = input.WPosition.xyz + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; -# else - float3 positionMSSkylight = input.WPosition.xyz; -# endif - - sh2 skylighting = Skylighting::sample(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, Skylighting::stbn_vec3_2Dx1D_128x128x64, input.HPosition.xy, positionMSSkylight, R); - sh2 specularLobe = SphericalHarmonics::FauxSpecularLobe(normal, -viewDirection, 0.0); + if (!(Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Reflections)) + return ReflectionColor.xyz * VarAmounts.y; - float skylightingSpecular = SphericalHarmonics::FuncProductIntegral(skylighting, specularLobe); - skylightingSpecular = lerp(1.0, skylightingSpecular, Skylighting::getFadeOutFactor(input.WPosition.xyz)); - skylightingSpecular = Skylighting::mixSpecular(SharedData::skylightingSettings, skylightingSpecular); + float3 R = reflect(viewDirection, WaterParams.y * normal + float3(0, 0, 1 - WaterParams.y)); + float3 reflectionColor = CubeMapTex.SampleLevel(CubeMapSampler, R, 0).xyz; - float3 specularIrradiance = 1; +# if defined(DYNAMIC_CUBEMAPS) + float3 dynamicCubemap; + if (SharedData::InInterior) { + dynamicCubemap = DynamicCubemaps::EnvTexture.SampleLevel(CubeMapSampler, R, 0).xyz; + } else { + float3 specularIrradiance = 1.0; + if (skylightingSpecular < 1.0) + specularIrradiance = Color::IrradianceToLinear(DynamicCubemaps::EnvTexture.SampleLevel(CubeMapSampler, R, 0).xyz); - if (skylightingSpecular < 1.0) { - specularIrradiance = Color::IrradianceToLinear(DynamicCubemaps::EnvTexture.SampleLevel(CubeMapSampler, R, 0).xyz); - } + float3 specularIrradianceReflections = 1.0; + if (skylightingSpecular > 0.0) + specularIrradianceReflections = Color::IrradianceToLinear(DynamicCubemaps::EnvReflectionsTexture.SampleLevel(CubeMapSampler, R, 0).xyz); - float3 specularIrradianceReflections = 1.0; + dynamicCubemap = Color::IrradianceToGamma(lerp(specularIrradiance, specularIrradianceReflections, skylightingSpecular)); + } - if (skylightingSpecular > 0.0) { - specularIrradianceReflections = Color::IrradianceToLinear(DynamicCubemaps::EnvReflectionsTexture.SampleLevel(CubeMapSampler, R, 0).xyz); - } + float reflectionAmount = saturate(length(input.WPosition.xyz) / 1024.0); - dynamicCubemap = Color::IrradianceToGamma(lerp(specularIrradiance, specularIrradianceReflections, skylightingSpecular)); - } -# else - float3 dynamicCubemap = DynamicCubemaps::EnvReflectionsTexture.SampleLevel(CubeMapSampler, R, 0); -# endif - -# if defined(VR) - // Reflection cubemap is incorrect for interiors in VR, ignore it - if (Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Interior || SharedData::HideSky) - reflectionColor = dynamicCubemap.xyz; - else - reflectionColor = lerp(dynamicCubemap.xyz, CubeMapTex.SampleLevel(CubeMapSampler, R, 0).xyz, saturate(length(input.WPosition.xyz) / 1024.0)); -# else - if (SharedData::HideSky) - reflectionColor = dynamicCubemap.xyz; - else - reflectionColor = lerp(dynamicCubemap.xyz, CubeMapTex.SampleLevel(CubeMapSampler, R, 0).xyz, saturate(length(input.WPosition.xyz) / 1024.0)); -# endif -# else - reflectionColor = CubeMapTex.SampleLevel(CubeMapSampler, R, 0).xyz; -# endif - } else { -# if !defined(LOD) && NUM_SPECULAR_LIGHTS == 0 - float4 reflectionNormalRaw = float4((VarAmounts.w * refractionsDepthFactor) * normal.xy + input.MPosition.xy, input.MPosition.z, 1); +# if defined(VR) + // Reflection cubemap is incorrect for interiors in VR, ignore it + if (Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Interior || SharedData::HideSky) + reflectionAmount = 0.0; # else - float4 reflectionNormalRaw = float4(VarAmounts.w * normal.xy, 0, 1); -# endif - - float4 reflectionNormal = mul(transpose(TextureProj[eyeIndex]), reflectionNormalRaw); - reflectionColor = ReflectionTex.SampleLevel(ReflectionSampler, reflectionNormal.xy / reflectionNormal.ww, 0).xyz; - } - -# if !defined(LOD) && NUM_SPECULAR_LIGHTS == 0 - if (Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Cubemap) { - float pointingDirection = dot(viewDirection, R); - float pointingAlignment = dot(reflect(viewDirection, float3(0, 0, 1)), R); - float ssrAmount = min(pointingAlignment, pointingDirection); - if (SSRParams.x > 0.0 && ssrAmount > 0.0) { - float2 ssrReflectionUv = ((FrameBuffer::DynamicResolutionParams2.xy * input.HPosition.xy) * SSRParams.zw) + 0.05 * normal.xy; - float2 ssrReflectionUvDR = FrameBuffer::GetDynamicResolutionAdjustedScreenPosition(ssrReflectionUv); - float4 ssrReflectionColorBlurred = RawSSRReflectionTex.Sample(RawSSRReflectionSampler, ssrReflectionUvDR); - float4 ssrReflectionColorRaw = RawSSRReflectionTex.Sample(RawSSRReflectionSampler, ssrReflectionUvDR); - float4 ssrReflectionColor = lerp(ssrReflectionColorBlurred, ssrReflectionColorRaw, ssrAmount * 0.7); - - finalSsrReflectionColor = max(0, ssrReflectionColor.xyz); - ssrFraction = saturate(ssrReflectionColor.w * distanceFactor * ssrAmount); - } - } + if (SharedData::HideSky) + reflectionAmount = 0.0; # endif + reflectionColor = lerp(dynamicCubemap, reflectionColor, reflectionAmount); +# endif - float3 finalReflectionColor = Color::IrradianceToGamma(lerp(Color::IrradianceToLinear(reflectionColor), Color::IrradianceToLinear(finalSsrReflectionColor), ssrFraction)); - return finalReflectionColor; +# if !defined(LOD) && NUM_SPECULAR_LIGHTS == 0 + float pointingDirection = dot(viewDirection, R); + float pointingAlignment = dot(reflect(viewDirection, float3(0, 0, 1)), R); + float ssrAmount = min(pointingAlignment, pointingDirection); + if (SSRParams.x > 0.0 && ssrAmount > 0.0) { + float2 ssrReflectionUv = ((FrameBuffer::DynamicResolutionParams2.xy * input.HPosition.xy) * SSRParams.zw) + 0.05 * normal.xy; + float2 ssrReflectionUvDR = FrameBuffer::GetDynamicResolutionAdjustedScreenPosition(ssrReflectionUv); + float4 ssrReflectionColorBlurred = RawSSRReflectionTex.Sample(RawSSRReflectionSampler, ssrReflectionUvDR); + float4 ssrReflectionColorRaw = RawSSRReflectionTex.Sample(RawSSRReflectionSampler, ssrReflectionUvDR); + float4 ssrReflectionColor = lerp(ssrReflectionColorBlurred, ssrReflectionColorRaw, ssrAmount * 0.7); + float3 finalSsrReflectionColor = max(0, ssrReflectionColor.xyz); + float ssrFraction = saturate(ssrReflectionColor.w * distanceFactor * ssrAmount); + reflectionColor = lerp(reflectionColor, finalSsrReflectionColor, ssrFraction); } - return ReflectionColor.xyz * VarAmounts.y; +# endif + + return reflectionColor; } -float GetScreenDepthWater(float2 screenPosition, uint a_useVR = 0) +float GetScreenDepthWater(float2 screenPosition, out float realDepth, uint a_useVR = 0) { - float depth = DepthTex.Load(float3(screenPosition, 0)).x; + realDepth = DepthTex.Load(float3(screenPosition, 0)).x; # if defined(VR) // VR appears to use hard coded values - return depth * 1.01 + -0.01; + return realDepth * 1.01 + -0.01; # else - return (CameraDataWater.w / (-depth * CameraDataWater.z + CameraDataWater.x)); + return (CameraDataWater.w / (-realDepth * CameraDataWater.z + CameraDataWater.x)); # endif } @@ -999,10 +935,13 @@ struct DiffuseOutput float3 refractionDiffuseColor; float depth; float refractionMul; + float3 refractionDepthAdjustedViewDirection; }; -DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, inout float4 distanceMul, float refractionsDepthFactor, float fresnel, uint eyeIndex, float3 viewPosition, float noise, float depth) +DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, inout float4 distanceMul, float refractionsDepthFactor, float fresnel, uint eyeIndex, float3 viewPosition, float depth, inout float realDepth) { + float3 refractionDepthAdjustedViewDirection = viewDirection; + # if defined(REFRACTIONS) float4 refractionNormal = mul(transpose(TextureProj[eyeIndex]), float4((VarAmounts.w * refractionsDepthFactor * normal.xy) + input.MPosition.xy, input.MPosition.z, 1)); @@ -1018,8 +957,9 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir float2 refractionScreenPosition = FrameBuffer::DynamicResolutionParams1.xy * (refractionUvRaw / VPOSOffset.xy); float4 refractionWorldPosition = float4(input.WPosition.xyz * depth / viewPosition.z, 0); + # if defined(DEPTH) && !defined(VERTEX_ALPHA_DEPTH) - float refractionDepth = GetScreenDepthWater(refractionScreenPosition); + float refractionDepth = GetScreenDepthWater(refractionScreenPosition, realDepth); # if !defined(VR) float refractionDepthMul = length(float3((((VPOSOffset.zw + refractionUvRaw) * 2 - 1)) * refractionDepth / ProjData.xy, refractionDepth)); @@ -1027,7 +967,7 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir float refractionDepthMul = CalculateDepthMultFromUV(refractionUvRawNoStereo, refractionDepth, eyeIndex); # endif //VR - float3 refractionDepthAdjustedViewDirection = -viewDirection * refractionDepthMul; + refractionDepthAdjustedViewDirection = -viewDirection * refractionDepthMul; float refractionViewSurfaceAngle = dot(refractionDepthAdjustedViewDirection, ReflectPlane[eyeIndex].xyz); float refractionPlaneMul = (1 - ReflectPlane[eyeIndex].w / refractionViewSurfaceAngle); @@ -1050,26 +990,6 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir float3 refractionColor = RefractionTex.Sample(RefractionSampler, refractionUV).xyz; float3 refractionDiffuseColor = lerp(Color::Water(ShallowColor.xyz), Color::Water(DeepColor.xyz), distanceMul.y); - if (!(Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Interior)) { -# if defined(SKYLIGHTING) - float3 skylightingPosition = lerp(input.WPosition.xyz, refractionWorldPosition.xyz, noise); - -# if defined(VR) - float3 positionMSSkylight = skylightingPosition + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; -# else - float3 positionMSSkylight = skylightingPosition; -# endif - - sh2 skylightingSH = Skylighting::sampleNoBias(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, positionMSSkylight); - float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(0, 0, 1))) / Math::PI; - skylightingDiffuse = saturate(skylightingDiffuse); - skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(input.WPosition.xyz)); - - float3 refractionDiffuseColorSkylight = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse); - refractionDiffuseColor = Color::LinearToGamma(Color::GammaToLinear(refractionDiffuseColor) * refractionDiffuseColorSkylight); -# endif - } - # if defined(UNDERWATER) float refractionMul = 0; # else @@ -1081,6 +1001,7 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir output.refractionDiffuseColor = refractionDiffuseColor; output.depth = depth; output.refractionMul = refractionMul; + output.refractionDepthAdjustedViewDirection = refractionDepthAdjustedViewDirection; return output; # else DiffuseOutput output; @@ -1088,6 +1009,7 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir output.refractionDiffuseColor = output.refractionColor; output.depth = 1; output.refractionMul = 1; + output.refractionDepthAdjustedViewDirection = refractionDepthAdjustedViewDirection; return output; # endif } @@ -1141,6 +1063,7 @@ PS_OUTPUT main(PS_INPUT input) bool isSpecular = false; float depth = 0; + float realDepth = 1.0; # if defined(DEPTH) # if defined(VERTEX_ALPHA_DEPTH) @@ -1150,7 +1073,7 @@ PS_OUTPUT main(PS_INPUT input) # else distanceMul = 0; - depth = GetScreenDepthWater(screenPosition); + depth = GetScreenDepthWater(screenPosition, realDepth); float2 depthOffset = FrameBuffer::DynamicResolutionParams2.xy * input.HPosition.xy * VPOSOffset.xy + VPOSOffset.zw; # if !defined(VR) @@ -1179,16 +1102,49 @@ PS_OUTPUT main(PS_INPUT input) # endif float3 viewPosition = mul(FrameBuffer::CameraView[eyeIndex], float4(input.WPosition.xyz, 1)).xyz; float2 screenUV = FrameBuffer::ViewToUV(viewPosition, true, eyeIndex); + const bool inWorld = (Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::InWorld); + +# if defined(SKYLIGHTING) + float wetnessOcclusion = 1.0; + +# if defined(VR) + float3 positionMSSkylight = input.WPosition.xyz + FrameBuffer::CameraPosAdjust[eyeIndex].xyz - FrameBuffer::CameraPosAdjust[0].xyz; +# else + float3 positionMSSkylight = input.WPosition.xyz; +# endif + + sh2 skylightingSH = Skylighting::sampleNoBias(SharedData::skylightingSettings, Skylighting::SkylightingProbeArray, positionMSSkylight); + float skylighting = SphericalHarmonics::Unproject(skylightingSH, float3(0, 0, 1)); + + float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(0, 0, 1))) / Math::PI; + skylightingDiffuse = saturate(skylightingDiffuse); + skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(input.WPosition.xyz)); + skylightingDiffuse = Skylighting::mixDiffuse(SharedData::skylightingSettings, skylightingDiffuse); + + wetnessOcclusion = inWorld ? pow(saturate(skylighting), 2) : 0; +# endif + +#if defined(SKYLIGHTING) + WaterNormalData waterData = GetWaterNormal(input, distanceBlendFactor, depthControl.z, viewDirection, depth, eyeIndex, wetnessOcclusion); +#else + WaterNormalData waterData = GetWaterNormal(input, distanceBlendFactor, depthControl.z, viewDirection, depth, eyeIndex, inWorld); +#endif - WaterNormalData waterData = GetWaterNormal(input, distanceBlendFactor, depthControl.z, viewDirection, depth, eyeIndex); float3 normal = waterData.normal; +# if defined(SKYLIGHTING) + sh2 specularLobe = SphericalHarmonics::FauxSpecularLobe(normal, -viewDirection, 0.0); + float skylightingSpecular = SphericalHarmonics::FuncProductIntegral(skylightingSH, specularLobe); + skylightingSpecular = saturate(skylightingSpecular); + skylightingSpecular = Skylighting::mixSpecular(SharedData::skylightingSettings, skylightingSpecular); +# endif + float fresnel = GetFresnelValue(normal, viewDirection); # if defined(SPECULAR) && (NUM_SPECULAR_LIGHTS != 0) float3 finalColor = 0.0.xxx; - for (int lightIndex = 0; lightIndex < NUM_SPECULAR_LIGHTS; ++lightIndex) { + [unroll] for (int lightIndex = 0; lightIndex < NUM_SPECULAR_LIGHTS; ++lightIndex) { float3 lightVector = LightPos[lightIndex].xyz - (PosAdjust[eyeIndex].xyz + input.WPosition.xyz); float3 lightDirection = normalize(normalize(lightVector) - viewDirection); float lightFade = saturate(length(lightVector) / LightPos[lightIndex].w); @@ -1210,12 +1166,33 @@ PS_OUTPUT main(PS_INPUT input) isSpecular = true; # else - float shadow = 1; +#if defined(SKYLIGHTING) + float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, skylightingSpecular); +#else + float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, 1.0); +#endif + + DiffuseOutput diffuseOutput = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, eyeIndex, viewPosition, depth, realDepth); + + float dirShadow = ShadowSampling::Get3DFilteredShadow(input.WPosition.xyz, diffuseOutput.refractionDepthAdjustedViewDirection, input.HPosition.xy, eyeIndex, realDepth); + + float3 dirColor; + float3 ambientColor; +# if defined(SKYLIGHTING) && !defined(INTERIOR) + ShadowSampling::ExtractLighting(diffuseOutput.refractionDiffuseColor, dirColor, ambientColor, skylightingDiffuse); +# else + ShadowSampling::ExtractLighting(diffuseOutput.refractionDiffuseColor, dirColor, ambientColor); +# endif + + dirColor *= dirShadow; - float screenNoise = Random::InterleavedGradientNoise(input.HPosition.xy, SharedData::FrameCount); +# if defined(SKYLIGHTING) + ambientColor = Color::IrradianceToLinear(ambientColor); + ambientColor *= skylightingDiffuse; + ambientColor = Color::IrradianceToGamma(ambientColor); +# endif - float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, depthControl.y, eyeIndex); - DiffuseOutput diffuseOutput = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, eyeIndex, viewPosition, screenNoise, depth); + diffuseOutput.refractionDiffuseColor = dirColor + ambientColor; float3 diffuseColor = lerp(diffuseOutput.refractionColor, diffuseOutput.refractionDiffuseColor, diffuseOutput.refractionMul); @@ -1273,11 +1250,7 @@ PS_OUTPUT main(PS_INPUT input) } # endif # else - float3 sunColor = GetSunColor(normal, viewDirection); - - if (!(Permutation::PixelShaderDescriptor & Permutation::WaterFlags::Interior) && any(sunColor > 0.0)) { - sunColor *= ShadowSampling::GetWaterShadow(screenNoise, input.WPosition.xyz, eyeIndex); - } + float3 sunColor = GetSunColor(normal, viewDirection) * dirShadow; # if defined(VC) float specularFraction = lerp(1, fresnel * diffuseOutput.refractionMul, distanceBlendFactor); @@ -1297,7 +1270,7 @@ PS_OUTPUT main(PS_INPUT input) } # endif -float3 finalColor = lerp(finalColorPreFog, fogColor * PosAdjust[eyeIndex].w, Color::FogAlpha(fogDistanceFactor)); + float3 finalColor = lerp(finalColorPreFog, fogColor * PosAdjust[eyeIndex].w, Color::FogAlpha(fogDistanceFactor)); # if defined(WETNESS_EFFECTS) && defined(DEBUG_WETNESS_EFFECTS) // DEBUG MODE: Override water color with debug visualization @@ -1325,7 +1298,7 @@ float3 finalColor = lerp(finalColorPreFog, fogColor * PosAdjust[eyeIndex].w, Col } # endif -finalColorPreFog = lerp(finalColorPreFog, preFogColor * PosAdjust[eyeIndex].w, Color::FogAlpha(fogDistanceFactor)); + finalColorPreFog = lerp(finalColorPreFog, preFogColor * PosAdjust[eyeIndex].w, Color::FogAlpha(fogDistanceFactor)); float3 refractionColor = diffuseOutput.refractionColor; @@ -1368,4 +1341,4 @@ finalColorPreFog = lerp(finalColorPreFog, preFogColor * PosAdjust[eyeIndex].w, C # endif -#endif \ No newline at end of file +#endif diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 686ac8d78e..3e7b79772c 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -156,6 +156,13 @@ void Deferred::SetupResources() perShadow->CreateUAV(uavDesc); copyShadowCS = static_cast(Util::CompileShader(L"Data\\Shaders\\CopyShadowDataCS.hlsl", {}, "cs_5_0")); + + std::vector> defines; + defines.push_back({ "DOWNSAMPLE_SHADOW_MIP0", nullptr }); + downsampleShadowMip0CS = static_cast(Util::CompileShader(L"Data\\Shaders\\DownsampleShadowCS.hlsl", defines, "cs_5_0")); + defines.clear(); + defines.push_back({ "DOWNSAMPLE_SHADOW_MIP1", nullptr }); + downsampleShadowMip1CS = static_cast(Util::CompileShader(L"Data\\Shaders\\DownsampleShadowCS.hlsl", defines, "cs_5_0")); } { @@ -212,8 +219,115 @@ void Deferred::CopyShadowData() { context->PSGetShaderResources(4, 1, &shadowView); + // Downsample shadow texture array to 4x smaller resolution + if (shadowView) { + ID3D11Resource* shadowResource = nullptr; + shadowView->GetResource(&shadowResource); + + if (shadowResource) { + ID3D11Texture2D* shadowTexture = nullptr; + shadowResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast(&shadowTexture)); + + if (shadowTexture) { + D3D11_TEXTURE2D_DESC srcDesc; + shadowTexture->GetDesc(&srcDesc); + + uint32_t newWidth = srcDesc.Width / 2; + uint32_t newHeight = srcDesc.Height / 2; + + // Lazily create or recreate downscaled texture if dimensions changed + if (!shadowCopyTexture || shadowCopyWidth != newWidth || shadowCopyHeight != newHeight) { + if (shadowCopySRV) { + shadowCopySRV->Release(); + shadowCopySRV = nullptr; + } + if (shadowCopyMip0UAV) { + shadowCopyMip0UAV->Release(); + shadowCopyMip0UAV = nullptr; + } + if (shadowCopyMip1UAV) { + shadowCopyMip1UAV->Release(); + shadowCopyMip1UAV = nullptr; + } + if (shadowCopyMip2UAV) { + shadowCopyMip2UAV->Release(); + shadowCopyMip2UAV = nullptr; + } + if (shadowCopyTexture) { + shadowCopyTexture->Release(); + shadowCopyTexture = nullptr; + } + + shadowCopyWidth = newWidth; + shadowCopyHeight = newHeight; + + D3D11_TEXTURE2D_DESC copyDesc{}; + copyDesc.Width = newWidth; + copyDesc.Height = newHeight; + copyDesc.MipLevels = 2; + copyDesc.ArraySize = 1; + copyDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; + copyDesc.SampleDesc.Count = 1; + copyDesc.SampleDesc.Quality = 0; + copyDesc.Usage = D3D11_USAGE_DEFAULT; + copyDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_RENDER_TARGET; + copyDesc.MiscFlags = 0; + + auto device = globals::d3d::device; + DX::ThrowIfFailed(device->CreateTexture2D(©Desc, nullptr, &shadowCopyTexture)); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{}; + srvDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 2; + DX::ThrowIfFailed(device->CreateShaderResourceView(shadowCopyTexture, &srvDesc, &shadowCopySRV)); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{}; + uavDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = 0; + DX::ThrowIfFailed(device->CreateUnorderedAccessView(shadowCopyTexture, &uavDesc, &shadowCopyMip0UAV)); + + uavDesc.Texture2D.MipSlice = 1; + DX::ThrowIfFailed(device->CreateUnorderedAccessView(shadowCopyTexture, &uavDesc, &shadowCopyMip1UAV)); + } + + // Dispatch downsample compute shader + ID3D11ShaderResourceView* csSrvs[1]{ shadowView }; + context->CSSetShaderResources(0, 1, csSrvs); + + context->CSSetSamplers(0, 1, &pointSampler); + + // Mip 0 with second cascade + ID3D11UnorderedAccessView* csUavs[1]{ shadowCopyMip0UAV }; + context->CSSetUnorderedAccessViews(0, 1, csUavs, nullptr); + context->CSSetShader(downsampleShadowMip0CS, nullptr, 0); + context->Dispatch((shadowCopyWidth + 7) >> 3, (shadowCopyHeight + 7) >> 3, 1); + + // Mip 1 with first cascade + csUavs[0] = shadowCopyMip1UAV; + context->CSSetUnorderedAccessViews(0, 1, csUavs, nullptr); + context->CSSetShader(downsampleShadowMip1CS, nullptr, 0); + context->Dispatch((shadowCopyWidth + 7) >> 3, (shadowCopyHeight + 7) >> 3, 1); + + // Cleanup CS state + csSrvs[0] = nullptr; + context->CSSetShaderResources(0, 1, csSrvs); + csUavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, csUavs, nullptr); + ID3D11SamplerState* nullSampler = nullptr; + context->CSSetSamplers(0, 1, &nullSampler); + context->CSSetShader(nullptr, nullptr, 0); + + shadowTexture->Release(); + } + shadowResource->Release(); + } + } + ID3D11ShaderResourceView* srvs[2]{ - shadowView, + shadowCopySRV ? shadowCopySRV : shadowView, perShadow->srv.get(), }; diff --git a/src/Deferred.h b/src/Deferred.h index 8c920f3593..93664fe042 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -67,9 +67,18 @@ class Deferred STATIC_ASSERT_ALIGNAS_16(PerGeometry); ID3D11ComputeShader* copyShadowCS = nullptr; + ID3D11ComputeShader* downsampleShadowMip0CS = nullptr; + ID3D11ComputeShader* downsampleShadowMip1CS = nullptr; Buffer* perShadow = nullptr; ID3D11ShaderResourceView* shadowView = nullptr; + ID3D11Texture2D* shadowCopyTexture = nullptr; + ID3D11ShaderResourceView* shadowCopySRV = nullptr; + ID3D11UnorderedAccessView* shadowCopyMip0UAV = nullptr; + ID3D11UnorderedAccessView* shadowCopyMip1UAV = nullptr; + uint32_t shadowCopyWidth = 0; + uint32_t shadowCopyHeight = 0; + struct Hooks { struct Main_RenderShadowMaps diff --git a/src/Features/TerrainShadows.cpp b/src/Features/TerrainShadows.cpp index b138dcf0e1..5104ab46c5 100644 --- a/src/Features/TerrainShadows.cpp +++ b/src/Features/TerrainShadows.cpp @@ -281,7 +281,7 @@ void TerrainShadows::Precompute() .Height = texHeightMap->desc.Height, .MipLevels = 1, .ArraySize = 1, - .Format = DXGI_FORMAT_R16G16_FLOAT, + .Format = DXGI_FORMAT_R16G16_UNORM, .SampleDesc = { .Count = 1 }, .Usage = D3D11_USAGE_DEFAULT, .BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS @@ -372,7 +372,7 @@ void TerrainShadows::UpdateShadow() // soft shadow angles float lenUV = float2{ dirLightDir.x, dirLightDir.y }.Length(); float dirLightAngle = atan2(-dirLightDir.z, lenUV); - float shadowSofteningRadiusAngle = 4.f * RE::NI_PI / 180.f; + float shadowSofteningRadiusAngle = RE::NI_PI / 180.f; float upperAngle = std::max(0.f, dirLightAngle - shadowSofteningRadiusAngle); float lowerAngle = std::min(RE::NI_HALF_PI - 1e-2f, dirLightAngle + shadowSofteningRadiusAngle); diff --git a/src/Hooks.cpp b/src/Hooks.cpp index d29a3f04ad..c72bb30585 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -169,16 +169,7 @@ namespace EffectExtensions static void thunk(RE::BSShader* shader, RE::BSRenderPass* pass, uint32_t renderFlags) { func(shader, pass, renderFlags); - - auto state = globals::state; - - state->permutationData.ExtraShaderDescriptor &= ~static_cast(State::ExtraShaderDescriptors::EffectShadows); - - if (auto* shaderProperty = static_cast(pass->geometry->GetGeometryRuntimeData().properties[1].get())) { - if (shaderProperty->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kUniformScale)) { - state->permutationData.ExtraShaderDescriptor |= static_cast(State::ExtraShaderDescriptors::EffectShadows); - } - } + globals::state->permutationData.EffectRadius = pass->geometry->worldBound.radius; } static inline REL::Relocation func; }; @@ -364,6 +355,8 @@ struct BSShaderRenderTargets_Create */ static void thunk() { + auto iniPrefSettingCollection = RE::INIPrefSettingCollection::GetSingleton(); + iniPrefSettingCollection->GetSetting("iNumFocusShadow:Display")->data.i = 0; func(); globals::ReInit(); globals::state->Setup(); diff --git a/src/State.h b/src/State.h index e8a9de3477..360a4b4e06 100644 --- a/src/State.h +++ b/src/State.h @@ -153,9 +153,8 @@ class State InWorld = 1 << 0, IsReflections = 1 << 1, IsBeastRace = 1 << 2, - EffectShadows = 1 << 3, - IsTree = 1 << 4, - GrassSphereNormal = 1 << 5 + IsTree = 1 << 3, + GrassSphereNormal = 1 << 4 }; enum class ExtraFeatureDescriptors : uint32_t @@ -182,11 +181,14 @@ class State uint ExtraShaderDescriptor; uint ExtraFeatureDescriptor; + float EffectRadius; + float3 pad0; + bool operator==(const PermutationCB& other) const { return PixelShaderDescriptor == other.PixelShaderDescriptor && ExtraShaderDescriptor == other.ExtraShaderDescriptor && - ExtraFeatureDescriptor == other.ExtraFeatureDescriptor; + ExtraFeatureDescriptor == other.ExtraFeatureDescriptor && EffectRadius == other.EffectRadius; } }; STATIC_ASSERT_ALIGNAS_16(PermutationCB);