diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli index 54faab793..165db9fc5 100644 --- a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli @@ -18,7 +18,7 @@ float3 GetDynamicCubemap(float2 uv, float3 N, float3 VN, float3 V, float roughne float3 R = reflect(-V, N); float NoV = saturate(dot(N, V)); - float level = roughness * 9.0; + float level = roughness * 7.0; float2 specularBRDF = EnvBRDFApprox(roughness, NoV); diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl index 1f25e9676..1b04f84a9 100644 --- a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl @@ -1,3 +1,5 @@ +#include "../Common/Color.hlsl" + TextureCube EnvCaptureTexture : register(t0); TextureCube ReflectionsTexture : register(t1); TextureCube DefaultCubemap : register(t2); @@ -44,16 +46,6 @@ float3 GetSamplingVector(uint3 ThreadID, in RWTexture2DArray OutputTextu return normalize(result); } -float3 sRGB2Lin(float3 color) -{ - return color > 0.04045 ? pow(color / 1.055 + 0.055 / 1.055, 2.4) : color / 12.92; -} - -float3 Lin2sRGB(float3 color) -{ - return color > 0.0031308 ? 1.055 * pow(color, 1.0 / 2.4) - 0.055 : 12.92 * color; -} - [numthreads(8, 8, 1)] void main(uint3 ThreadID : SV_DispatchThreadID) { float3 uv = GetSamplingVector(ThreadID, EnvInferredTexture); @@ -66,11 +58,11 @@ float3 Lin2sRGB(float3 color) float brightness = k; #endif - while (color.w < 1.0 && mipLevel <= 10) { + while (color.w < 1.0 && mipLevel <= 8) { mipLevel++; float4 tempColor = 0.0; - if (mipLevel < 10) { + if (mipLevel < 8) { tempColor = EnvCaptureTexture.SampleLevel(LinearSampler, uv, mipLevel); } else { tempColor += EnvCaptureTexture.SampleLevel(LinearSampler, float3(-1.0, 0.0, 0.0), 9); @@ -98,9 +90,9 @@ float3 Lin2sRGB(float3 color) } #if defined(REFLECTIONS) - color.rgb = lerp(color.rgb, sRGB2Lin(ReflectionsTexture.SampleLevel(LinearSampler, uv, 0)), saturate(mipLevel * (1.0 / 10.0))); + color.rgb = lerp(color.rgb, sRGB2Lin(ReflectionsTexture.SampleLevel(LinearSampler, uv, 0)), saturate(mipLevel / 8.0)); #else - color.rgb = lerp(color.rgb, color.rgb * sRGB2Lin(DefaultCubemap.SampleLevel(LinearSampler, uv, 0).x), saturate(mipLevel * (1.0 / 10.0))); + color.rgb = lerp(color.rgb, color.rgb * sRGB2Lin(DefaultCubemap.SampleLevel(LinearSampler, uv, 0).x) * 2, saturate(mipLevel / 8.0)); #endif color.rgb = Lin2sRGB(color.rgb); diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/UpdateCubemapCS.hlsl b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/UpdateCubemapCS.hlsl index 5fcd6584b..56e97206c 100644 --- a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/UpdateCubemapCS.hlsl +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/UpdateCubemapCS.hlsl @@ -1,5 +1,8 @@ #include "../Common/Constants.hlsli" +#include "../Common/DeferredShared.hlsli" +#include "../Common/FrameBuffer.hlsl" #include "../Common/VR.hlsli" + RWTexture2DArray DynamicCubemap : register(u0); RWTexture2DArray DynamicCubemapRaw : register(u1); RWTexture2DArray DynamicCubemapPosition : register(u2); @@ -47,88 +50,12 @@ float3 GetSamplingVector(uint3 ThreadID, in RWTexture2DArray OutputTextu return normalize(result); } -cbuffer PerFrame : register(b0) -{ -#if !defined(VR) - row_major float4x4 CameraView[1] : packoffset(c0); - row_major float4x4 CameraProj[1] : packoffset(c4); - row_major float4x4 CameraViewProj[1] : packoffset(c8); - row_major float4x4 CameraViewProjUnjittered[1] : packoffset(c12); - row_major float4x4 CameraPreviousViewProjUnjittered[1] : packoffset(c16); - row_major float4x4 CameraProjUnjittered[1] : packoffset(c20); - row_major float4x4 CameraProjUnjitteredInverse[1] : packoffset(c24); - row_major float4x4 CameraViewInverse[1] : packoffset(c28); - row_major float4x4 CameraViewProjInverse[1] : packoffset(c32); - row_major float4x4 CameraProjInverse[1] : packoffset(c36); - float4 CameraPosAdjust[1] : packoffset(c40); - float4 CameraPreviousPosAdjust[1] : packoffset(c41); // fDRClampOffset in w - float4 FrameParams : packoffset(c42); // inverse fGamma in x, some flags in yzw - float4 DynamicResolutionParams1 : packoffset(c43); // fDynamicResolutionWidthRatio in x, - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionPreviousWidthRatio in z, - // fDynamicResolutionPreviousHeightRatio in w - float4 DynamicResolutionParams2 : packoffset(c44); // inverse fDynamicResolutionWidthRatio in x, inverse - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionWidthRatio - fDRClampOffset in z, - // fDynamicResolutionPreviousWidthRatio - fDRClampOffset in w -#else - row_major float4x4 CameraView[2] : packoffset(c0); - row_major float4x4 CameraProj[2] : packoffset(c8); - row_major float4x4 CameraViewProj[2] : packoffset(c16); - row_major float4x4 CameraViewProjUnjittered[2] : packoffset(c24); - row_major float4x4 CameraPreviousViewProjUnjittered[2] : packoffset(c32); - row_major float4x4 CameraProjUnjittered[2] : packoffset(c40); - row_major float4x4 CameraProjUnjitteredInverse[2] : packoffset(c48); - row_major float4x4 CameraViewInverse[2] : packoffset(c56); - row_major float4x4 CameraViewProjInverse[2] : packoffset(c64); - row_major float4x4 CameraProjInverse[2] : packoffset(c72); - float4 CameraPosAdjust[2] : packoffset(c80); - float4 CameraPreviousPosAdjust[2] : packoffset(c82); // fDRClampOffset in w - float4 FrameParams : packoffset(c84); // inverse fGamma in x, some flags in yzw - float4 DynamicResolutionParams1 : packoffset(c85); // fDynamicResolutionWidthRatio in x, - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionPreviousWidthRatio in z, - // fDynamicResolutionPreviousHeightRatio in w - float4 DynamicResolutionParams2 : packoffset(c86); // inverse fDynamicResolutionWidthRatio in x, inverse - // fDynamicResolutionHeightRatio in y, - // fDynamicResolutionWidthRatio - fDRClampOffset in z, - // fDynamicResolutionPreviousWidthRatio - fDRClampOffset in w -#endif // !VR -} - cbuffer UpdateData : register(b1) { - float4 CameraData; uint Reset; float3 CameraPreviousPosAdjust2; } -float3 WorldToView(float3 x, bool is_position = true, uint a_eyeIndex = 0) -{ - float4 newPosition = float4(x, (float)is_position); - return mul(CameraView[a_eyeIndex], newPosition).xyz; -} - -float2 ViewToUV(float3 x, bool is_position = true, uint a_eyeIndex = 0) -{ - float4 newPosition = float4(x, (float)is_position); - float4 uv = mul(CameraProj[a_eyeIndex], newPosition); - return (uv.xy / uv.w) * float2(0.5f, -0.5f) + 0.5f; -} - -float GetScreenDepth(float depth) -{ - return (CameraData.w / (-depth * CameraData.z + CameraData.x)); -} - -float2 GetDynamicResolutionAdjustedScreenPosition(float2 screenPosition) -{ - float2 adjustedScreenPosition = - max(0.0.xx, DynamicResolutionParams1.xy * screenPosition); - return min(float2(DynamicResolutionParams2.z, DynamicResolutionParams1.y), - adjustedScreenPosition); -} - bool IsSaturated(float value) { return value == saturate(value); } bool IsSaturated(float2 value) { return IsSaturated(value.x) && IsSaturated(value.y); } @@ -166,6 +93,77 @@ float smoothbumpstep(float edge0, float edge1, float x) } if (IsSaturated(uv) && viewDirection.z < 0.0) { // Check that the view direction exists in screenspace and that it is in front of the camera + float2 PoissonDisc[64] = { + float2(0.403302f, 0.139622f), + float2(0.578204f, 0.624683f), + float2(0.942412f, 0.973693f), + float2(0.0789209f, 0.902676f), + float2(0.904355f, 0.158025f), + float2(0.0505387f, 0.403394f), + float2(0.99176f, 0.587085f), + float2(0.0210273f, 0.00875881f), + float2(0.329905f, 0.460005f), + float2(0.386853f, 0.985321f), + float2(0.625721f, 0.34431f), + float2(0.346782f, 0.687551f), + float2(0.659139f, 0.843989f), + float2(0.798029f, 0.469008f), + float2(0.14127f, 0.19602f), + float2(0.684011f, 0.0732444f), + float2(0.0515458f, 0.672048f), + float2(0.239662f, 0.00369274f), + float2(0.985076f, 0.363414f), + float2(0.191229f, 0.594928f), + float2(0.820887f, 0.720725f), + float2(0.508103f, 0.0209967f), + float2(0.783654f, 0.302744f), + float2(0.467269f, 0.82757f), + float2(0.214911f, 0.809259f), + float2(0.747703f, 0.986847f), + float2(0.966033f, 0.00357067f), + float2(0.447432f, 0.292367f), + float2(0.954253f, 0.813837f), + float2(0.209815f, 0.356304f), + float2(0.561663f, 0.970794f), + float2(0.334544f, 0.340678f), + float2(0.461013f, 0.419691f), + float2(0.229865f, 0.993164f), + float2(0.797327f, 0.838832f), + float2(0.578478f, 0.128452f), + float2(0.265358f, 0.135685f), + float2(0.495621f, 0.710837f), + float2(0.71102f, 0.643971f), + float2(0.0191046f, 0.2219f), + float2(0.990265f, 0.240516f), + float2(0.85403f, 0.589709f), + float2(0.369488f, 0.0120548f), + float2(0.478378f, 0.551805f), + float2(0.664815f, 0.519913f), + float2(0.843684f, 0.0224006f), + float2(0.0827357f, 0.530961f), + float2(0.116398f, 0.0798364f), + float2(0.676931f, 0.221381f), + float2(0.917447f, 0.472091f), + float2(0.334819f, 0.836451f), + float2(0.00308237f, 0.800134f), + float2(0.565752f, 0.823206f), + float2(0.874783f, 0.33668f), + float2(0.336772f, 0.592364f), + float2(0.151402f, 0.729484f), + float2(0.706656f, 0.748802f), + float2(0.723411f, 0.379315f), + float2(0.805109f, 0.16715f), + float2(0.853877f, 0.243294f), + float2(0.91464f, 0.693289f), + float2(0.846828f, 0.918821f), + float2(0.188513f, 0.501236f), + float2(0.0812708f, 0.993774f) + }; + + // Assume projection maps to one cubemap face, and randomly sample an area within the mapped resolution + uv += (PoissonDisc[FrameCountAlwaysActive % 64] * 2.0 - 1.0) * BufferDim.zw * max(1.0, float2(BufferDim.x / 128.0, BufferDim.y / 128.0)) * 0.5; + uv = saturate(uv); + uv = GetDynamicResolutionAdjustedScreenPosition(uv); uv = ConvertToStereoUV(uv, 0); @@ -175,19 +173,15 @@ float smoothbumpstep(float edge0, float edge1, float x) if (linearDepth > 16.5) { // Ignore objects which are too close float3 color = ColorTexture.SampleLevel(LinearSampler, uv, 0); float4 output = float4(sRGB2Lin(color), 1.0); - float lerpFactor = 0.5; - - float4 position = float4(InverseProjectUVZ(uv, depth) * 0.001, 1.0); + float lerpFactor = 1.0 / 64.0; - float distance = length(position.xyz); + half4 positionCS = half4(2 * half2(uv.x, -uv.y + 1) - 1, depth, 1); + positionCS = mul(CameraViewProjInverse[0], positionCS); + positionCS.xyz = positionCS.xyz / positionCS.w; - position.w = smoothstep(1.0, 4096.0 * 0.001, distance); // Objects which are far away from the perspective of the camera do not fade out - - if (linearDepth > (4096.0 * 5.0)) - position.w = 0; + float4 position = float4(positionCS.xyz * 0.001, linearDepth < (4096.0 * 2.5)); DynamicCubemapPosition[ThreadID] = lerp(DynamicCubemapPosition[ThreadID], position, lerpFactor); - DynamicCubemapRaw[ThreadID] = max(0, lerp(DynamicCubemapRaw[ThreadID], output, lerpFactor)); output *= sqrt(saturate(0.5 * length(position.xyz))); @@ -204,8 +198,8 @@ float smoothbumpstep(float edge0, float edge1, float x) float4 color = DynamicCubemapRaw[ThreadID]; - float distanceFactor = sqrt(smoothbumpstep(0.0, 1.0, length(position.xyz))); - color *= max(0.001, max(distanceFactor, position.w)); + float distanceFactor = sqrt(smoothbumpstep(0.0, 2.0, length(position.xyz))); + color *= distanceFactor; DynamicCubemap[ThreadID] = max(0, color); } diff --git a/features/Grass Lighting/Shaders/RunGrass.hlsl b/features/Grass Lighting/Shaders/RunGrass.hlsl index 6b79ef7fe..eae1ea92e 100644 --- a/features/Grass Lighting/Shaders/RunGrass.hlsl +++ b/features/Grass Lighting/Shaders/RunGrass.hlsl @@ -296,6 +296,11 @@ float3x3 CalculateTBN(float3 N, float3 p, float2 uv) # include "CloudShadows/CloudShadows.hlsli" # endif +# if defined(SKYLIGHTING) +# define LinearSampler SampBaseSampler +# include "Skylighting/Skylighting.hlsli" +# endif + PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) { @@ -450,6 +455,18 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace diffuseColor += lightsDiffuseColor; +# if !defined(SSGI) + float3 directionalAmbientColor = mul(DirectionalAmbientShared, float4(normal, 1.0)); + +# if defined(SKYLIGHTING) + float4 skylightingSH = SkylightingTexture.Load(int3(input.HPosition.xy, 0)); + float skylighting = saturate(shUnproject(skylightingSH, normal)); + directionalAmbientColor *= lerp(1.0 / 3.0, 1.0, skylighting); +# endif + + diffuseColor += directionalAmbientColor; +# endif + diffuseColor *= albedo; diffuseColor += max(0, sss * subsurfaceColor * grassLightingSettings.SubsurfaceScatteringAmount); diff --git a/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli index 931c62bc2..3a5f021d0 100644 --- a/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli +++ b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli @@ -1,11 +1,13 @@ +#include "Common/Spherical Harmonics/SphericalHarmonics.hlsli" Texture2D OcclusionMapSampler : register(t29); +Texture2D SkylightingTexture : register(t30); cbuffer SkylightingData : register(b8) { row_major float4x4 OcclusionViewProj; + float4 EyePosition; float4 ShadowDirection; - float4 Parameters; }; float GetVLSkylighting(float3 startPosWS, float3 endPosWS, float2 screenPosition) diff --git a/features/Skylighting/Shaders/Skylighting/SkylightingBlurCS.hlsl b/features/Skylighting/Shaders/Skylighting/SkylightingBlurCS.hlsl new file mode 100644 index 000000000..a885c9693 --- /dev/null +++ b/features/Skylighting/Shaders/Skylighting/SkylightingBlurCS.hlsl @@ -0,0 +1,73 @@ +#include "../Common/FrameBuffer.hlsl" +#include "../Common/GBuffer.hlsli" +#include "../Common/VR.hlsli" + +Texture2D DepthTexture : register(t0); + +Texture2D SkylightingTexture : register(t1); +RWTexture2D SkylightingTextureRW : register(u0); + +cbuffer PerFrame : register(b0) +{ + row_major float4x4 OcclusionViewProj; + float4 EyePosition; + float4 ShadowDirection; + float4 BufferDim; + float4 CameraData; + uint FrameCount; +}; + +SamplerState LinearSampler : register(s0); + +half GetScreenDepth(half depth) +{ + return (CameraData.w / (-depth * CameraData.z + CameraData.x)); +} + +// samples = 8, min distance = 0.5, average samples on radius = 2 +static const float3 g_Poisson8[8] = { + float3(-0.4706069, -0.4427112, +0.6461146), + float3(-0.9057375, +0.3003471, +0.9542373), + float3(-0.3487388, +0.4037880, +0.5335386), + float3(+0.1023042, +0.6439373, +0.6520134), + float3(+0.5699277, +0.3513750, +0.6695386), + float3(+0.2939128, -0.1131226, +0.3149309), + float3(+0.7836658, -0.4208784, +0.8895339), + float3(+0.1564120, -0.8198990, +0.8346850) +}; + +[numthreads(8, 8, 1)] void main(uint3 globalId + : SV_DispatchThreadID) { + half2 uv = half2(globalId.xy + 0.5) * (BufferDim.zw) * DynamicResolutionParams2.xy; + uint eyeIndex = GetEyeIndexFromTexCoord(uv); + + half4 skylightingSH = 0; + half weight = 0.0; + + half rawDepth = DepthTexture[globalId.xy]; + half depth = GetScreenDepth(rawDepth); + + [unroll] for (uint i = 0; i < 8; i++) + { + +#if defined(HORIZONTAL) + half2 testUV = uv + g_Poisson8[i].xy * BufferDim.zw * 8.0; +#else + half2 testUV = uv + g_Poisson8[i].yx * BufferDim.zw * 16.0; +#endif + + if (any(testUV < 0) || any(testUV > 1)) + continue; + + half sampleDepth = GetScreenDepth(DepthTexture.SampleLevel(LinearSampler, testUV, 0)); + half attenuation = g_Poisson8[i].z * lerp(g_Poisson8[i].z * 0.01, 1.0, 1.0 - saturate(0.01 * abs(sampleDepth - depth))); + + [branch] if (attenuation > 0.0) + { + skylightingSH += SkylightingTexture.SampleLevel(LinearSampler, testUV, 0) * attenuation; + weight += attenuation; + } + } + + SkylightingTextureRW[globalId.xy] = skylightingSH / weight; +} \ No newline at end of file diff --git a/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl b/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl index 053248ebc..8c56a0946 100644 --- a/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl +++ b/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl @@ -1,9 +1,9 @@ -#include "../Common/DeferredShared.hlsli" #include "../Common/FrameBuffer.hlsl" #include "../Common/GBuffer.hlsli" +#include "../Common/Spherical Harmonics/SphericalHarmonics.hlsli" #include "../Common/VR.hlsli" -Texture2D DepthTexture : register(t0); +Texture2D DepthTexture : register(t0); struct PerGeometry { @@ -26,15 +26,17 @@ Texture2DArray TexShadowMapSampler : register(t1); StructuredBuffer perShadow : register(t2); Texture2DArray BlueNoise : register(t3); Texture2D OcclusionMapSampler : register(t4); -Texture2D NormalRoughnessTexture : register(t5); -RWTexture2D SkylightingTextureRW : register(u0); +RWTexture2D SkylightingTextureRW : register(u0); cbuffer PerFrame : register(b0) { row_major float4x4 OcclusionViewProj; + float4 EyePosition; float4 ShadowDirection; - float4 Parameters; + float4 BufferDim; + float4 CameraData; + uint FrameCount; }; SamplerState LinearSampler : register(s0); @@ -45,25 +47,13 @@ half GetBlueNoise(half2 uv) return BlueNoise[uint3(uv % 128, FrameCount % 64)]; } -half GetScreenDepth(half depth) -{ - return (CameraData.w / (-depth * CameraData.z + CameraData.x)); -} - -#define PI 3.1415927 - #if !defined(SHADOWMAP) [numthreads(8, 8, 1)] void main(uint3 globalId : SV_DispatchThreadID) { - float2 uv = float2(globalId.xy + 0.5) * BufferDim.zw * DynamicResolutionParams2.xy; + float2 uv = float2(globalId.xy + 0.5) * (BufferDim.zw) * DynamicResolutionParams2.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); uv = ConvertFromStereoUV(uv, eyeIndex); - half3 normalGlossiness = NormalRoughnessTexture[globalId.xy]; - half3 normalVS = DecodeNormal(normalGlossiness.xy); - half3 normalWS = normalize(mul(CameraViewInverse[eyeIndex], half4(normalVS, 0))); - half roughness = 1.0 - normalGlossiness.z; - float rawDepth = DepthTexture[globalId.xy]; float4 positionCS = float4(2 * float2(uv.x, -uv.y + 1) - 1, rawDepth, 1); @@ -71,104 +61,85 @@ half GetScreenDepth(half depth) float4 positionMS = mul(CameraViewProjInverse[eyeIndex], positionCS); positionMS.xyz = positionMS.xyz / positionMS.w; + positionMS.xyz = positionMS.xyz + CameraPosAdjust[eyeIndex] - EyePosition; + float3 startPositionMS = positionMS; - half noise = GetBlueNoise(globalId.xy) * 2.0 * PI; + half noise = GetBlueNoise(globalId.xy) * 2.0 * shPI; half2x2 rotationMatrix = half2x2(cos(noise), sin(noise), -sin(noise), cos(noise)); - half2 PoissonDisk[16] = { - half2(-0.94201624, -0.39906216), - half2(0.94558609, -0.76890725), - half2(-0.094184101, -0.92938870), - half2(0.34495938, 0.29387760), - half2(-0.91588581, 0.45771432), - half2(-0.81544232, -0.87912464), - half2(-0.38277543, 0.27676845), - half2(0.97484398, 0.75648379), - half2(0.44323325, -0.97511554), - half2(0.53742981, -0.47373420), - half2(-0.26496911, -0.41893023), - half2(0.79197514, 0.19090188), - half2(-0.24188840, 0.99706507), - half2(-0.81409955, 0.91437590), - half2(0.19984126, 0.78641367), - half2(0.14383161, -0.14100790) + float2 PoissonDisc[] = { + float2(0.881375f, 0.216315f), + float2(0.0872829f, 0.987854f), + float2(0.0710166f, 0.132633f), + float2(0.517563f, 0.643117f) }; - uint sampleCount = 16; + uint sampleCount = 4; float occlusionThreshold = mul(OcclusionViewProj, float4(positionMS.xyz, 1)).z; - half3 V = normalize(positionMS.xyz); - half3 R = reflect(V, normalWS); - bool fadeOut = length(startPositionMS) > 1024; - half3 skylighting = 0; - half3 weights = 0.0; + half weight = 0; + half wetnessWeight = 0; + + sh2 shSkylighting = shZero(); + float wetnessOcclusion = 0; + + half fadeFactor = pow(saturate(length(positionMS.xyz) / 10000.0), 8); [unroll] for (uint i = 0; i < sampleCount; i++) { - half2 offset = mul(PoissonDisk[i].xy, rotationMatrix); - half shift = half(i) / half(sampleCount); - half radius = length(offset); + float3 rayDir = float3(PoissonDisc[i].xy * 2.0 - 1.0, 0); + rayDir.xy = mul(rayDir.xy, rotationMatrix); - positionMS.xy = startPositionMS + offset * 128; + positionMS.xy = startPositionMS + rayDir.xy * 128; - half2 occlusionPosition = mul((float2x4)OcclusionViewProj, float4(positionMS.xyz, 1)); + half3 occlusionPosition = mul(OcclusionViewProj, float4(positionMS.xyz, 1)); occlusionPosition.y = -occlusionPosition.y; half2 occlusionUV = occlusionPosition.xy * 0.5 + 0.5; - half3 offsetDirection = normalize(half3(offset.xy, pow(1.0 - (radius * 0.5), Parameters.y))); - if ((occlusionUV.x == saturate(occlusionUV.x) && occlusionUV.y == saturate(occlusionUV.y)) || !fadeOut) { - half shadowMapValues = OcclusionMapSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius)); + float shadowMapValues = OcclusionMapSampler.SampleLevel(LinearSampler, occlusionUV, 0); - half3 H = normalize(-offsetDirection + V); - half NoH = dot(normalWS, H); - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - half ggx = k * k * (1.0 / PI); + shadowMapValues = 1.0 - shadowMapValues; + occlusionPosition.z = 1.0 - occlusionPosition.z; - half NDotL = dot(normalWS.xyz, offsetDirection.xyz); + half skylightingContribution = 1.0 - saturate((shadowMapValues - occlusionPosition.z) * 4096); - half3 contributions = half3(saturate(NDotL), ggx, NDotL * 0.5 + 0.5); + sh2 sh = shEvaluate(rayDir); + shSkylighting = shAdd(shSkylighting, shScale(sh, lerp(skylightingContribution, 1.0, fadeFactor))); - skylighting += shadowMapValues * contributions; - weights += contributions; + weight++; } else { - skylighting++; - weights++; + sh2 sh = shEvaluate(rayDir); + shSkylighting = shAdd(shSkylighting, shScale(sh, 1)); + weight++; } } - if (weights.x > 0.0) - skylighting.x /= weights.x; - if (weights.y > 0.0) - skylighting.y /= weights.y; - if (weights.z > 0.0) - skylighting.z /= weights.z; - - skylighting.x = lerp(skylighting.z, 1.0, Parameters.x) * Parameters.z + skylighting.x * saturate(dot(normalWS, float3(0, 0, 1))) * Parameters.w; - skylighting.y = saturate(skylighting.y); - - half fadeFactor = pow(saturate(length(positionMS.xyz) / 10000.0), 8); + if (weight > 0.0) { + float shFactor = 4.0 * shPI * 1.0 / weight; + shSkylighting = shScale(shSkylighting, shFactor); + } - SkylightingTextureRW[globalId.xy] = lerp(skylighting.xy, 1.0, fadeFactor); + SkylightingTextureRW[globalId.xy] = shSkylighting; } #else + +half GetScreenDepth(half depth) +{ + return (CameraData.w / (-depth * CameraData.z + CameraData.x)); +} + [numthreads(8, 8, 1)] void main(uint3 globalId : SV_DispatchThreadID) { float2 uv = float2(globalId.xy + 0.5) * BufferDim.zw * DynamicResolutionParams2.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); uv = ConvertFromStereoUV(uv, eyeIndex); - half3 normalGlossiness = NormalRoughnessTexture[globalId.xy]; - half3 normalVS = DecodeNormal(normalGlossiness.xy); - half3 normalWS = normalize(mul(CameraViewInverse[eyeIndex], half4(normalVS, 0))); - half roughness = 1.0 - normalGlossiness.z; - float rawDepth = DepthTexture[globalId.xy]; float4 positionCS = float4(2 * float2(uv.x, -uv.y + 1) - 1, rawDepth, 1); @@ -187,47 +158,33 @@ half GetScreenDepth(half depth) half fadeFactor = pow(saturate(dot(positionMS.xyz, positionMS.xyz) / sD.ShadowLightParam.z), 8); - half noise = GetBlueNoise(globalId.xy) * 2.0 * PI; + fadeFactor = lerp(1.0, fadeFactor, pow(saturate(dot(float3(0, 0, -1), ShadowDirection.xyz)), 0.5)); + + half noise = GetBlueNoise(globalId.xy) * 2.0 * shPI; half2x2 rotationMatrix = half2x2(cos(noise), sin(noise), -sin(noise), cos(noise)); - half2 PoissonDisk[16] = { - half2(-0.94201624, -0.39906216), - half2(0.94558609, -0.76890725), - half2(-0.094184101, -0.92938870), - half2(0.34495938, 0.29387760), - half2(-0.91588581, 0.45771432), - half2(-0.81544232, -0.87912464), - half2(-0.38277543, 0.27676845), - half2(0.97484398, 0.75648379), - half2(0.44323325, -0.97511554), - half2(0.53742981, -0.47373420), - half2(-0.26496911, -0.41893023), - half2(0.79197514, 0.19090188), - half2(-0.24188840, 0.99706507), - half2(-0.81409955, 0.91437590), - half2(0.19984126, 0.78641367), - half2(0.14383161, -0.14100790) + float2 PoissonDisc[] = { + float2(0.881375f, 0.216315f), + float2(0.0872829f, 0.987854f), + float2(0.0710166f, 0.132633f), + float2(0.517563f, 0.643117f) }; - uint sampleCount = 16; + uint sampleCount = 4; - half3 V = normalize(positionMS.xyz); - half3 R = reflect(V, normalWS); + sh2 shSkylighting = shZero(); - half3 skylighting = 0; - half3 weights = 0.0; + half weight = 0.0; - uint validSamples = 0; [unroll] for (uint i = 0; i < sampleCount; i++) { - half2 offset = mul(PoissonDisk[i].xy, rotationMatrix); - half shift = half(i) / half(sampleCount); - half radius = length(offset); + float3 rayDir = float3(PoissonDisc[i].xy * 2.0 - 1.0, 0); + rayDir.xy = mul(rayDir.xy, rotationMatrix); - positionMS.xy = startPositionMS + offset.xy * 128 + length(offset.xy) * ShadowDirection.xy * 128; + positionMS.xy = startPositionMS + rayDir.xy * 128 + length(rayDir.xy) * ShadowDirection.xy * 128; - half3 offsetDirection = normalize(half3(offset.xy, pow(1.0 - (radius * 0.5), Parameters.y))); + rayDir = normalize(rayDir); float shadowMapDepth = length(positionMS.xyz); @@ -235,52 +192,46 @@ half GetScreenDepth(half depth) { half cascadeIndex = 0; float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0]; - float shadowMapThreshold = sD.AlphaTestRef.y; [flatten] if (2.5 < sD.EndSplitDistances.w && sD.EndSplitDistances.y < shadowMapDepth) { lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][2]; - shadowMapThreshold = sD.AlphaTestRef.z; cascadeIndex = 2; } else if (sD.EndSplitDistances.x < shadowMapDepth) { lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1]; - shadowMapThreshold = sD.AlphaTestRef.z; cascadeIndex = 1; } float3 positionLS = mul(transpose(lightProjectionMatrix), float4(positionMS.xyz, 1)).xyz; - half shadowMapValues = TexShadowMapSampler.SampleLevel(LinearSampler, float3(positionLS.xy, cascadeIndex), 0) > positionLS.z - shadowMapThreshold; + half shadowMapValues = TexShadowMapSampler.SampleLevel(LinearSampler, float3(positionLS.xy, cascadeIndex), 0); - half3 H = normalize(-offsetDirection + V); - half NoH = dot(normalWS, H); - half a = NoH * roughness; - half k = roughness / (1.0 - NoH * NoH + a * a); - half ggx = k * k * (1.0 / PI); + shadowMapValues = 1.0 - shadowMapValues; + positionLS.z = 1.0 - positionLS.z; - half NDotL = dot(normalWS.xyz, offsetDirection.xyz); + half skylightingContribution = 1.0 - saturate((shadowMapValues - positionLS.z) * 4096); - half3 contributions = half3(saturate(NDotL), ggx, NDotL * 0.5 + 0.5); + sh2 sh = shEvaluate(rayDir); + shSkylighting = shAdd(shSkylighting, shScale(sh, lerp(skylightingContribution, 1.0, fadeFactor))); - skylighting += shadowMapValues * contributions; - weights += contributions; + weight++; } - } - - if (weights.x > 0.0) - skylighting.x /= weights.x; - if (weights.y > 0.0) - skylighting.y /= weights.y; - if (weights.z > 0.0) - skylighting.z /= weights.z; + else + { + sh2 sh = shEvaluate(rayDir); + shSkylighting = shAdd(shSkylighting, shScale(sh, 1.0)); - skylighting.x = lerp(skylighting.z, 1.0, Parameters.x) * Parameters.z + skylighting.x * saturate(dot(normalWS, float3(0, 0, 1))) * Parameters.w; - skylighting.y = saturate(skylighting.y); + weight++; + } + } - skylighting = lerp(1.0, skylighting, pow(saturate(dot(float3(0, 0, -1), ShadowDirection.xyz)), 0.25)); + if (weight > 0.0) { + float shFactor = 4.0 * shPI * 1.0 / weight; + shSkylighting = shScale(shSkylighting, shFactor); + } - SkylightingTextureRW[globalId.xy] = lerp(skylighting.xy, 1.0, fadeFactor); + SkylightingTextureRW[globalId.xy] = shSkylighting; } #endif \ No newline at end of file diff --git a/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl b/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl index d47bc80cb..5224cd618 100644 --- a/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl +++ b/features/Terrain Blending/Shaders/TerrainBlending/DepthBlend.hlsl @@ -1,4 +1,6 @@ RWTexture2D BlendedDepthTexture : register(u0); +RWTexture2D BlendedDepthTexture16 : register(u1); + Texture2D MainDepthTexture : register(t0); Texture2D TerrainDepthTexture : register(t1); @@ -6,4 +8,5 @@ Texture2D TerrainDepthTexture : register(t1); : SV_DispatchThreadID) { float mixedDepth = min(MainDepthTexture[DTid.xy], TerrainDepthTexture[DTid.xy]); BlendedDepthTexture[DTid.xy] = mixedDepth; + BlendedDepthTexture16[DTid.xy] = mixedDepth; } diff --git a/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli b/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli index 64faaeddc..e35739ebc 100644 --- a/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli +++ b/features/Water Caustics/Shaders/WaterCaustics/WaterCaustics.hlsli @@ -1,11 +1,4 @@ -struct PerPassWaterCaustics -{ - bool EnableWaterCaustics; - float pad[3]; -}; - Texture2D WaterCaustics : register(t70); -StructuredBuffer perPassWaterCaustics : register(t71); float2 PanCausticsUV(float2 uv, float speed, float tiling) { @@ -15,7 +8,6 @@ float2 PanCausticsUV(float2 uv, float speed, float tiling) float3 SampleCaustics(float2 uv) { return WaterCaustics.Sample(SampColorSampler, uv).r; - ; } float3 ComputeWaterCaustics(float2 uv) diff --git a/features/Water Parallax/Shaders/WaterParallax/WaterParallax.hlsli b/features/Water Parallax/Shaders/WaterParallax/WaterParallax.hlsli index e4bde6c1f..cc6a4fbcb 100644 --- a/features/Water Parallax/Shaders/WaterParallax/WaterParallax.hlsli +++ b/features/Water Parallax/Shaders/WaterParallax/WaterParallax.hlsli @@ -5,14 +5,6 @@ // http://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf // https://bartwronski.files.wordpress.com/2014/03/ac4_gdc.pdf -struct PerPassWaterParallax -{ - bool EnableWaterParallax; - float pad[3]; -}; - -StructuredBuffer perPassWaterParallax : register(t72); - float GetMipLevel(float2 coords, Texture2D tex) { // Compute the current gradients: @@ -47,8 +39,6 @@ float GetHeight(PS_INPUT input, float2 currentOffset, float3 normalScalesRcp, fl float2 GetParallaxOffset(PS_INPUT input, float3 normalScalesRcp) { - if (!perPassWaterParallax[0].EnableWaterParallax) - return 0.0.xx; float3 viewDirection = normalize(input.WPosition.xyz); float2 parallaxOffsetTS = viewDirection.xy / -viewDirection.z; @@ -60,7 +50,7 @@ float2 GetParallaxOffset(PS_INPUT input, float3 normalScalesRcp) mipLevels.y = GetMipLevel(input.TexCoord1.zw, Normals02Tex); mipLevels.z = GetMipLevel(input.TexCoord2.xy, Normals03Tex); - float stepSize = rcp(lerp(32.0, 1.0, dot(viewDirection, float3(0, 0, -1)))); + float stepSize = 16.0; float currBound = 0.0; float currHeight = 1.0; float prevHeight = 1.0; diff --git a/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli b/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli index 426985b7e..7aa63b8a0 100644 --- a/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli +++ b/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli @@ -193,10 +193,10 @@ float3 GetWetnessAmbientSpecular(float2 uv, float3 N, float3 VN, float3 V, float #if defined(DYNAMIC_CUBEMAPS) # if defined(DEFERRED) - float level = roughness * 9.0; + float level = roughness * 7.0; float3 specularIrradiance = 1.0; # else - float level = roughness * 9.0; + float level = roughness * 7.0; float3 specularIrradiance = sRGB2Lin(specularTexture.SampleLevel(SampColorSampler, R, level)); # endif #else @@ -220,6 +220,6 @@ float3 GetWetnessAmbientSpecular(float2 uv, float3 N, float3 VN, float3 V, float float3 GetWetnessSpecular(float3 N, float3 L, float3 V, float3 lightColor, float roughness) { - lightColor *= 0.1; + lightColor *= 0.01; return LightingFuncGGX_OPT3(N, V, L, roughness, 1.0 - roughness) * lightColor; } diff --git a/package/Shaders/AmbientCompositeCS.hlsl b/package/Shaders/AmbientCompositeCS.hlsl index 4dcc2e995..a89e550ab 100644 --- a/package/Shaders/AmbientCompositeCS.hlsl +++ b/package/Shaders/AmbientCompositeCS.hlsl @@ -8,7 +8,8 @@ Texture2D AlbedoTexture : register(t0); Texture2D NormalRoughnessTexture : register(t1); #if defined(SKYLIGHTING) -Texture2D SkylightingTexture : register(t2); +# include "Common/Spherical Harmonics/SphericalHarmonics.hlsli" +Texture2D SkylightingTexture : register(t2); #endif #if defined(SSGI) @@ -37,21 +38,26 @@ RWTexture2D DiffuseAmbientRW : register(u1); half3 ambient = albedo * directionalAmbientColor; - diffuseColor = sRGB2Lin(diffuseColor); - ambient = sRGB2Lin(max(0, ambient)); // Fixes black blobs on the world map - albedo = sRGB2Lin(albedo); - #if defined(SKYLIGHTING) - half skylightingDiffuse = SkylightingTexture[dispatchID.xy].x; - ambient *= skylightingDiffuse; + sh2 skylightingSH = SkylightingTexture[dispatchID.xy]; + + half skylighting = saturate(shUnproject(skylightingSH, normalWS)); + + ambient *= lerp(0.25, 1.0, skylighting); #endif + #if defined(SSGI) half4 ssgiDiffuse = SSGITexture[dispatchID.xy]; - ambient = ambient * ssgiDiffuse.a + ssgiDiffuse.rgb * albedo; -#endif + ambient *= ssgiDiffuse.a; + + diffuseColor = sRGB2Lin(diffuseColor); + albedo = sRGB2Lin(albedo); + + diffuseColor += ssgiDiffuse.rgb * albedo; diffuseColor = Lin2sRGB(diffuseColor); - ambient = Lin2sRGB(ambient); + +#endif diffuseColor += ambient; diff --git a/package/Shaders/Common/DeferredShared.hlsli b/package/Shaders/Common/DeferredShared.hlsli index 14a383ef4..dddf70e13 100644 --- a/package/Shaders/Common/DeferredShared.hlsli +++ b/package/Shaders/Common/DeferredShared.hlsli @@ -4,7 +4,7 @@ cbuffer PerFrameDeferredShared : register(b11) float4 CameraData; row_major float3x4 DirectionalAmbient; uint FrameCount; - uint pad0[3]; + uint FrameCountAlwaysActive; }; float GetScreenDepth(float depth) diff --git a/package/Shaders/Common/Spherical Harmonics/LICENSE b/package/Shaders/Common/Spherical Harmonics/LICENSE new file mode 100644 index 000000000..8550be47f --- /dev/null +++ b/package/Shaders/Common/Spherical Harmonics/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 SebH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli b/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli new file mode 100644 index 000000000..8eac93a36 --- /dev/null +++ b/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli @@ -0,0 +1,202 @@ + +// SphericalHarmonics.hlsl from https://github.com/sebh/HLSL-Spherical-Harmonics + +// Great documents about spherical harmonics: +// [1] http://www.cse.chalmers.se/~uffe/xjobb/Readings/GlobalIllumination/Spherical%20Harmonic%20Lighting%20-%20the%20gritty%20details.pdf +// [2] https://www.ppsloan.org/publications/StupidSH36.pdf +// [3] https://cseweb.ucsd.edu/~ravir/papers/envmap/envmap.pdf +// [4] https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2011/06/10-14.pdf +// [5] https://github.com/kayru/Probulator +// [6] https://www.ppsloan.org/publications/SHJCGT.pdf +// [7] http://www.patapom.com/blog/SHPortal/ +// [8] https://grahamhazel.com/blog/2017/12/22/converting-sh-radiance-to-irradiance/ +// [9] http://www.ppsloan.org/publications/shdering.pdf +// [10] http://limbicsoft.com/volker/prosem_paper.pdf +// [11] https://bartwronski.files.wordpress.com/2014/08/bwronski_volumetric_fog_siggraph2014.pdf +// + +// +// Provided functions are commented. A "SH function" means a "spherical function represented as spherical harmonics". +// You can also find a FAQ below. +// +//**** HOW TO PROJECT RADIANCE FROM A SPHERE INTO SH? +// +// // Initialise sh to 0 +// sh2 shR = shZero(); +// sh2 shG = shZero(); +// sh2 shB = shZero(); +// +// // Accumulate coefficients according to surounding direction/color tuples. +// for (float az = 0.5f; az < axisSampleCount; az += 1.0f) +// for (float ze = 0.5f; ze < axisSampleCount; ze += 1.0f) +// { +// float3 rayDir = shGetUniformSphereSample(az / axisSampleCount, ze / axisSampleCount); +// float3 color = [...]; +// +// sh2 sh = shEvaluate(rayDir); +// shR = shAdd(shR, shScale(sh, color.r)); +// shG = shAdd(shG, shScale(sh, color.g)); +// shB = shAdd(shB, shScale(sh, color.b)); +// } +// +// // integrating over a sphere so each sample has a weight of 4*PI/samplecount (uniform solid angle, for each sample) +// float shFactor = 4.0 * shPI / (axisSampleCount * axisSampleCount); +// shR = shScale(shR, shFactor ); +// shG = shScale(shG, shFactor ); +// shB = shScale(shB, shFactor ); +// +// +//**** HOW TO VIZUALISE A SPHERICAL FUNCTION REPRESENTED AS SH? +// +// sh2 shR = fromSomewhere.Load(...); +// sh2 shG = fromSomewhere.Load(...); +// sh2 shB = fromSomewhere.Load(...); +// float3 rayDir = compute(...); // the direction for which you want to know the color +// float3 rgbColor = max(0.0f, shUnproject(shR, shG, shB, rayDir)); // A "max" is usually recomended to avoid negative values (can happen with SH) +// + +#ifndef SPHERICAL_HARMONICS_HLSL +#define SPHERICAL_HARMONICS_HLSL + +#define shPI 3.1415926536f + +// Generates a uniform distribution of directions over a unit sphere. +// Adapted from http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#fragment-SamplingFunctionDefinitions-6 +// azimuthX and zenithY are both in [0, 1]. You can use random value, stratified, etc. +// Top and bottom sphere pole (+-zenith) are along the Y axis. +float3 shGetUniformSphereSample(float azimuthX, float zenithY) +{ + float phi = 2.0f * shPI * azimuthX; + float z = 1.0f - 2.0f * zenithY; + float r = sqrt(max(0.0f, 1.0f - z * z)); + return float3(r * cos(phi), z, r * sin(phi)); +} + +#define sh2 float4 +// TODO sh3 + +sh2 shZero() +{ + return float4(0.0f, 0.0f, 0.0f, 0.0f); +} + +// Evaluates spherical harmonics basis for a direction dir. +// This follows [2] Appendix A2 order when storing in x, y, z and w. +// (evaluating the associated Legendre polynomials using the polynomial forms) +sh2 shEvaluate(float3 dir) +{ + sh2 result; + result.x = 0.28209479177387814347403972578039f; // L=0 , M= 0 + result.y = -0.48860251190291992158638462283836f * dir.y; // L=1 , M=-1 + result.z = 0.48860251190291992158638462283836f * dir.z; // L=1 , M= 0 + result.w = -0.48860251190291992158638462283836f * dir.x; // L=1 , M= 1 + return result; +} + +// Recovers the value of a SH function in the direction dir. +float shUnproject(sh2 functionSh, float3 dir) +{ + sh2 sh = shEvaluate(dir); + return dot(functionSh, sh); +} + +float3 shUnproject(sh2 functionShX, sh2 functionShY, sh2 functionShZ, float3 dir) +{ + sh2 sh = shEvaluate(dir); + return float3(dot(functionShX, sh), dot(functionShY, sh), dot(functionShZ, sh)); +} + +// Projects a cosine lobe function, with peak value in direction dir, into SH. (from [4]) +// The integral over the unit sphere of the SH representation is PI. +sh2 shEvaluateCosineLobe(float3 dir) +{ + sh2 result; + result.x = 0.8862269254527580137f; // L=0 , M= 0 + result.y = -1.0233267079464884885f * dir.y; // L=1 , M=-1 + result.z = 1.0233267079464884885f * dir.z; // L=1 , M= 0 + result.w = -1.0233267079464884885f * dir.x; // L=1 , M= 1 + return result; +} + +// Projects a Henyey-Greenstein phase function, with peak value in direction dir, into SH. (from [11]) +// The integral over the unit sphere of the SH representation is 1. +sh2 shEvaluatePhaseHG(float3 dir, float g) +{ + sh2 result; + const float factor = 0.48860251190291992158638462283836 * g; + result.x = 0.28209479177387814347403972578039; // L=0 , M= 0 + result.y = -factor * dir.y; // L=1 , M=-1 + result.z = factor * dir.z; // L=1 , M= 0 + result.w = -factor * dir.x; // L=1 , M= 1 + return result; +} + +// Adds two SH functions together. +sh2 shAdd(sh2 shL, sh2 shR) +{ + return shL + shR; +} + +// Scales a SH function uniformly by v. +sh2 shScale(sh2 sh, float v) +{ + return sh * v; +} + +// Operates a rotation of a SH function. +sh2 shRotate(sh2 sh, float3x3 rotation) +{ + // TODO verify and optimize + sh2 result; + result.x = sh.x; + float3 tmp = float3(sh.w, sh.y, sh.z); // undo direction component shuffle to match source/function space + result.yzw = mul(tmp, rotation).yzx; // apply rotation and re-shuffle + return result; +} + +// Integrates the product of two SH functions over the unit sphere. +float shFuncProductIntegral(sh2 shL, sh2 shR) +{ + return dot(shL, shR); +} + +// Computes the SH coefficients of a SH function representing the result of the multiplication of two SH functions. (from [4]) +// If sources have N bands, this product will result in 2N*1 bands as signal multiplication can add frequencies (think about two lobes intersecting). +// To avoid that, the result can be truncated to N bands. It will just have a lower frequency, i.e. less details. (from [2], SH Products p.7) +// Note: - the code from [4] has been adapted to match the mapping from [2] we use. +// - !!! Be aware that this code has note yet be tested !!! +sh2 shProduct(sh2 shL, sh2 shR) +{ + const float factor = 1.0f / (2.0f * sqrt(shPI)); + return factor * sh2( + dot(shL, shR), + shL.y * shR.w + shL.w * shR.y, + shL.z * shR.w + shL.w * shR.z, + shL.w * shR.w + shL.w * shR.w); +} + +// Convolves a SH function using a Hanning filtering. This helps reducing ringing and negative values. (from [2], Windowing p.16) +// A lower value of w will reduce ringing (like the frequency of a filter) +sh2 shHanningConvolution(sh2 sh, float w) +{ + sh2 result = sh; + float invW = 1.0 / w; + float factorBand1 = (1.0 + cos(shPI * invW)) / 2.0f; + result.y *= factorBand1; + result.z *= factorBand1; + result.w *= factorBand1; + return result; +} + +// Convolves a SH function using a cosine lob. This is tipically used to transform radiance to irradiance. (from [3], eq.7 & eq.8) +sh2 shDiffuseConvolution(sh2 sh) +{ + sh2 result = sh; + // L0 + result.x *= shPI; + // L1 + result.yzw *= 2.0943951023931954923f; + return result; +} + +#endif // SPHERICAL_HARMONICS_HLSL diff --git a/package/Shaders/DeferredCompositeCS.hlsl b/package/Shaders/DeferredCompositeCS.hlsl index ea3ecff62..4d2381667 100644 --- a/package/Shaders/DeferredCompositeCS.hlsl +++ b/package/Shaders/DeferredCompositeCS.hlsl @@ -17,7 +17,7 @@ RWTexture2D SnowParametersRW : register(u2); #if defined(DYNAMIC_CUBEMAPS) Texture2D DepthTexture : register(t5); -Texture2D ReflectanceTexture : register(t6); +Texture2D ReflectanceTexture : register(t6); TextureCube EnvTexture : register(t7); TextureCube EnvReflectionsTexture : register(t8); @@ -25,7 +25,8 @@ SamplerState LinearSampler : register(s0); #endif #if defined(SKYLIGHTING) -Texture2D SkylightingTexture : register(t9); +# include "Common/Spherical Harmonics/SphericalHarmonics.hlsli" +Texture2D SkylightingTexture : register(t9); #endif [numthreads(8, 8, 1)] void main(uint3 dispatchID @@ -70,7 +71,7 @@ Texture2D SkylightingTexture : register(t9); half3 R = reflect(V, normalWS); half roughness = 1.0 - glossiness; - half level = roughness * 9.0; + half level = roughness * 7.0; # if defined(INTERIOR) half3 specularIrradiance = EnvTexture.SampleLevel(LinearSampler, R, level).xyz; @@ -78,15 +79,25 @@ Texture2D SkylightingTexture : register(t9); color += reflectance * specularIrradiance; # elif defined(SKYLIGHTING) - half skylightingSpecular = SkylightingTexture[dispatchID.xy].y; + sh2 skylightingSH = SkylightingTexture[dispatchID.xy]; - half3 specularIrradiance = EnvTexture.SampleLevel(LinearSampler, R, level).xyz; - specularIrradiance = sRGB2Lin(specularIrradiance); + half skylighting = saturate(shUnproject(skylightingSH, R)); - half3 specularIrradianceReflections = EnvReflectionsTexture.SampleLevel(LinearSampler, R, level).xyz; - specularIrradianceReflections = sRGB2Lin(specularIrradianceReflections); + half3 specularIrradiance = 1; + + if (skylighting < 1.0) { + specularIrradiance = EnvTexture.SampleLevel(LinearSampler, R, level).xyz; + specularIrradiance = sRGB2Lin(specularIrradiance); + } + + half3 specularIrradianceReflections = 1.0; + + if (skylighting > 0.0) { + specularIrradianceReflections = EnvReflectionsTexture.SampleLevel(LinearSampler, R, level).xyz; + specularIrradianceReflections = sRGB2Lin(specularIrradianceReflections); + } - color += reflectance * lerp(specularIrradiance, specularIrradianceReflections, skylightingSpecular); + color += reflectance * lerp(specularIrradiance, specularIrradianceReflections, skylighting); # else half3 specularIrradianceReflections = EnvReflectionsTexture.SampleLevel(LinearSampler, R, level).xyz; specularIrradianceReflections = sRGB2Lin(specularIrradianceReflections); @@ -117,7 +128,7 @@ Texture2D SkylightingTexture : register(t9); #endif - MainRW[dispatchID.xy] = color; - NormalTAAMaskSpecularMaskRW[dispatchID.xy] = half4(EncodeNormalVanilla(normalVS), 0.0, glossiness); + MainRW[dispatchID.xy] = min(color, 128); // Vanilla bloom fix + NormalTAAMaskSpecularMaskRW[dispatchID.xy] = half4(EncodeNormalVanilla(normalVS), 0.0, 0.0); SnowParametersRW[dispatchID.xy] = snowParameters; } \ No newline at end of file diff --git a/package/Shaders/DistantTree.hlsl b/package/Shaders/DistantTree.hlsl index 84293f39b..22f86e6b4 100644 --- a/package/Shaders/DistantTree.hlsl +++ b/package/Shaders/DistantTree.hlsl @@ -214,7 +214,7 @@ PS_OUTPUT main(PS_INPUT input) float dirShadow = 1; # if defined(SCREEN_SPACE_SHADOWS) - dirShadow = GetScreenSpaceShadow(screenUV, screenNoise, viewPosition, eyeIndex); + dirShadow = lerp(0.2, 1.0, GetScreenSpaceShadow(screenUV, screenNoise, viewPosition, eyeIndex)); # endif # if defined(TERRA_OCC) @@ -232,17 +232,23 @@ PS_OUTPUT main(PS_INPUT input) } # endif - psout.Diffuse.xyz = DirLightColorShared.xyz * baseColor.xyz * 0.5 * lerp(1.0, dirShadow, 0.8); + float3 diffuseColor = DirLightColorShared.xyz * dirShadow; + float3 ddx = ddx_coarse(input.WorldPosition); + float3 ddy = ddy_coarse(input.WorldPosition); + float3 normal = normalize(cross(ddx, ddy)); + +# if !defined(SSGI) + float3 directionalAmbientColor = mul(DirectionalAmbientShared, float4(normal, 1.0)); + diffuseColor += directionalAmbientColor; +# endif + + psout.Diffuse.xyz = diffuseColor * baseColor.xyz * 0.5; psout.Diffuse.w = 1; psout.MotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); - float3 ddx = ddx_coarse(input.ViewPosition); - float3 ddy = ddy_coarse(input.ViewPosition); - float3 normal = normalize(cross(ddx, ddy)); - - psout.Normal.xy = EncodeNormal(normal); + psout.Normal.xy = EncodeNormal(WorldToView(normal, false, eyeIndex)); psout.Normal.zw = 0; psout.Albedo = float4(baseColor.xyz * 0.5, 1); @@ -252,10 +258,7 @@ PS_OUTPUT main(PS_INPUT input) float3 ddy = ddy_coarse(input.WorldPosition); float3 normal = normalize(cross(ddx, ddy)); - float3 directionalAmbientColor = mul(DirectionalAmbientShared, float4(normal, 1.0)); - - float3 color = DirLightColorShared.xyz * baseColor.xyz * 0.5; - color += baseColor.xyz * 0.5 * directionalAmbientColor; + float3 color = baseColor.xyz * (DiffuseColor + AmbientColor); psout.Diffuse = float4(color, 1.0); # endif // DEFERRED # endif // RENDER_DEPTH diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index fd24f51f5..5d2fe8288 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -99,7 +99,9 @@ struct VS_OUTPUT #if defined(VR) float ClipDistance : SV_ClipDistance0; // o11 float CullDistance : SV_CullDistance0; // p11 -#endif // VR +#endif + + float3 ModelPosition : TEXCOORD12; }; #ifdef VSHADER @@ -225,24 +227,6 @@ VS_OUTPUT main(VS_INPUT input) float4 viewPos = mul(modelView, inputPosition); # endif // SKINNED -# if defined(OUTLINE) && !defined(MODELSPACENORMALS) - float3 normal = normalize(-1.0.xxx + 2.0.xxx * input.Normal.xyz); - float outlineShift = min(max(viewPos.z / 150, 1), 50); - inputPosition.xyz += outlineShift * normal.xyz; - previousInputPosition.xyz += outlineShift * normal.xyz; - -# if defined(SKINNED) - previousWorldPosition = - float4(mul(inputPosition, transpose(previousWorldMatrix)), 1); - worldPosition = float4(mul(inputPosition, transpose(worldMatrix)), 1); - viewPos = mul(ViewProj[eyeIndex], worldPosition); -# else // !SKINNED - previousWorldPosition = float4(mul(PreviousWorld[eyeIndex], inputPosition), 1); - worldPosition = float4(mul(World[eyeIndex], inputPosition), 1); - viewPos = mul(modelView, inputPosition); -# endif // SKINNED -# endif // defined(OUTLINE) && !defined(MODELSPACENORMALS) - vsout.Position = viewPos; # if defined(LODLANDNOISE) || defined(LODLANDSCAPE) @@ -387,6 +371,8 @@ VS_OUTPUT main(VS_INPUT input) vsout.CullDistance.x = VRout.CullDistance; # endif // VR + vsout.ModelPosition = input.Position.xyz; + return vsout; } #endif // VSHADER @@ -955,7 +941,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(SKINNED) || !defined(MODELSPACENORMALS) float3x3 tbn = float3x3(input.TBN0.xyz, input.TBN1.xyz, input.TBN2.xyz); -# if !defined(TREE_ANIM) +# if !defined(TREE_ANIM) && !defined(LOD) // Fix incorrect vertex normals on double-sided meshes if (!frontFace) tbn = -tbn; @@ -973,7 +959,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 viewPosition = mul(CameraView[eyeIndex], float4(input.WorldPosition.xyz, 1)).xyz; float2 screenUV = ViewToUV(viewPosition, true, eyeIndex); - float screenNoise = InterleavedGradientNoise(screenUV * BufferDim); + float screenNoise = InterleavedGradientNoise(input.Position.xy); # if defined(TERRAIN_BLENDING) float depthSampled = GetTerrainOffsetDepth(screenUV, eyeIndex); @@ -1400,8 +1386,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 dirLightColor = DirLightColor.xyz; # if defined(WATER_CAUSTICS) - if (perPassWaterCaustics[0].EnableWaterCaustics) - dirLightColor *= ComputeWaterCaustics(waterData, input.WorldPosition.xyz, worldSpaceNormal); + dirLightColor *= ComputeWaterCaustics(waterData, input.WorldPosition.xyz, worldSpaceNormal); # endif float selfShadowFactor = 1.0f; @@ -1419,11 +1404,19 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace dirLightColor *= shadowColor.x; } - bool inDirShadow = ((PixelShaderDescriptor & _DefShadow) && (PixelShaderDescriptor & _ShadowDir) && shadowColor.x == 0) || dirLightAngle <= 0.0; +# if defined(SOFT_LIGHTING) || defined(BACK_LIGHTING) || defined(RIM_LIGHTING) + bool inDirShadow = ((PixelShaderDescriptor & _DefShadow) && (PixelShaderDescriptor & _ShadowDir) && shadowColor.x == 0); +# else + bool inDirShadow = ((PixelShaderDescriptor & _DefShadow) && (PixelShaderDescriptor & _ShadowDir) && shadowColor.x == 0) && dirLightAngle > 0.0; +# endif float dirDetailShadow = 1.0; float dirShadow = 1.0; +# if defined(SOFT_LIGHTING) || defined(BACK_LIGHTING) || defined(RIM_LIGHTING) + if (!inDirShadow && dirLightAngle > 0.0) { +# else if (!inDirShadow) { +# endif # if defined(DEFERRED) && defined(SCREEN_SPACE_SHADOWS) dirDetailShadow = GetScreenSpaceShadow(screenUV, screenNoise, viewPosition, eyeIndex); # endif @@ -1470,16 +1463,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 dirDiffuseColor = dirLightColor * saturate(dirLightAngle) * dirDetailShadow; +# if defined(SOFT_LIGHTING) || defined(RIM_LIGHTING) || defined(BACK_LIGHTING) + float backlighting = 1.0 + saturate(dot(viewDirection, -DirLightDirection.xyz)); +# endif + # if defined(SOFT_LIGHTING) - lightsDiffuseColor += dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz * backlighting; # endif # if defined(RIM_LIGHTING) - lightsDiffuseColor += dirLightColor * GetRimLightMultiplier(DirLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirLightColor * GetRimLightMultiplier(DirLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz * backlighting; # endif # if defined(BACK_LIGHTING) - lightsDiffuseColor += dirLightColor * saturate(-dirLightAngle) * backLightColor.xyz; + lightsDiffuseColor += dirLightColor * saturate(-dirLightAngle) * backLightColor.xyz * backlighting; # endif if (useSnowSpecular && useSnowDecalSpecular) { @@ -1498,6 +1495,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float nearFactor = smoothstep(4096.0 * 2.5, 0.0, viewPosition.z); +# if defined(SKYLIGHTING) + float4 skylightingSH = SkylightingTexture.Load(int3(input.Position.xy, 0)); +# endif + # if defined(WETNESS_EFFECTS) float wetness = 0.0; @@ -1513,17 +1514,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float maxOcclusion = 1; float minWetnessAngle = 0; minWetnessAngle = saturate(max(minWetnessValue, worldSpaceNormal.z)); + # if defined(SKYLIGHTING) - float skylight = GetSkylightOcclusion(input.WorldPosition + worldSpaceNormal, screenNoise); -# else - float skylight = 1.0; -# endif // SKYLIGHTING + float wetnessOcclusion = saturate(shUnproject(skylightingSH, float3(0, 0, -1))); + wetnessOcclusion = saturate(wetnessOcclusion * 1.5); +# endif + + bool raindropOccluded = false; float4 raindropInfo = float4(0, 0, 1, 0); if (worldSpaceNormal.z > 0 && wetnessEffects.Raining > 0.0f && wetnessEffects.EnableRaindropFx && (dot(input.WorldPosition, input.WorldPosition) < wetnessEffects.RaindropFxRange * wetnessEffects.RaindropFxRange)) { - if (skylight > 0.0) - raindropInfo = GetRainDrops((input.WorldPosition + CameraPosAdjust[eyeIndex]).xyz, wetnessEffects.Time, worldSpaceNormal); +# if defined(SKYLIGHTING) + if (wetnessOcclusion > 0.0) +# endif +# if defined(SKINNED) + raindropInfo = GetRainDrops(input.ModelPosition, wetnessEffects.Time, worldSpaceNormal); +# elif defined(DEFERRED) + raindropInfo = GetRainDrops(input.WorldPosition + CameraPosAdjust[eyeIndex], wetnessEffects.Time, worldSpaceNormal); +# else + raindropInfo = GetRainDrops(!FrameParams.y ? input.ModelPosition : input.WorldPosition + CameraPosAdjust[eyeIndex], wetnessEffects.Time, worldSpaceNormal); +# endif } float rainWetness = wetnessEffects.Wetness * minWetnessAngle * wetnessEffects.MaxRainWetness; @@ -1537,8 +1548,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace rainWetness = wetnessEffects.SkinWetness * wetnessEffects.Wetness * 0.8f; # endif - rainWetness *= skylight; - puddleWetness *= skylight; +# if defined(SKYLIGHTING) + rainWetness *= wetnessOcclusion; + puddleWetness *= wetnessOcclusion; +# endif wetness = max(shoreFactor * wetnessEffects.MaxShoreWetness, rainWetness); @@ -1570,7 +1583,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace wetnessNormal = normalize(lerp(wetnessNormal, float3(0, 0, 1), saturate(flatnessAmount))); - float3 rippleNormal = normalize(lerp(float3(0, 0, 1), raindropInfo.xyz, clamp(flatnessAmount, .2, 1))); + float3 rippleNormal = normalize(lerp(float3(0, 0, 1), raindropInfo.xyz, clamp(flatnessAmount, 0.0, 1.0))); wetnessNormal = ReorientNormal(rippleNormal, wetnessNormal); float waterRoughnessSpecular = 1.0 - wetnessGlossinessSpecular; @@ -1757,7 +1770,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 directionalAmbientColor = mul(DirectionalAmbient, modelNormal); -# if !defined(DEFERRED) +# if defined(SKYLIGHTING) && !defined(SSGI) + // Will look incorrect on objects which have depth which deviates a lot + float skylighting = saturate(shUnproject(skylightingSH, worldSpaceNormal)); + directionalAmbientColor *= lerp(1.0 / 3.0, 1.0, skylighting); +# endif + +# if !(defined(DEFERRED) && defined(SSGI)) diffuseColor += directionalAmbientColor; # endif @@ -1821,10 +1840,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace baseColor.xyz = lerp(baseColor.xyz, pow(baseColor.xyz, 1.0 + wetnessDarkeningAmount), 0.8); # endif - float3 wetnessReflectance = 0.0; - - if (waterRoughnessSpecular < 1.0) - wetnessReflectance = GetWetnessAmbientSpecular(screenUV, wetnessNormal, worldSpaceVertexNormal, worldSpaceViewDirection, 1.0 - wetnessGlossinessSpecular); + // This also applies fresnel + float3 wetnessReflectance = GetWetnessAmbientSpecular(screenUV, wetnessNormal, worldSpaceVertexNormal, worldSpaceViewDirection, 1.0 - wetnessGlossinessSpecular); + ; # if !defined(DEFERRED) wetnessSpecular += wetnessReflectance; @@ -1909,12 +1927,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif - color.xyz = lerp(vertexColor.xyz, input.FogParam.xyz, input.FogParam.w); - color.xyz = vertexColor.xyz - color.xyz * FogColor.w; - - float3 tmpColor = color.xyz * FrameParams.yyy; - color.xyz = tmpColor.xyz + ColourOutputClamp.xxx; - color.xyz = min(vertexColor.xyz, color.xyz); + color.xyz = vertexColor.xyz; # if defined(EMAT) && defined(ENVMAP) specularColor *= complexSpecular; @@ -1932,14 +1945,10 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace color.xyz = Lin2sRGB(color.xyz); -# if defined(SPECULAR) || defined(SPARKLE) - float3 specularTmp = lerp(color.xyz, input.FogParam.xyz, input.FogParam.w); - specularTmp = color.xyz - specularTmp.xyz * FogColor.w; - - tmpColor = specularTmp.xyz * FrameParams.yyy; - specularTmp.xyz = tmpColor.xyz + ColourOutputClamp.zzz; - color.xyz = min(specularTmp.xyz, color.xyz); -# endif // defined (SPECULAR) || defined(SPARKLE) +# if !defined(DEFERRED) + if (FrameParams.y && FrameParams.z) + color.xyz = lerp(color.xyz, input.FogParam.xyz, input.FogParam.w); +# endif # if defined(TESTCUBEMAP) # if (defined(ENVMAP) || defined(MULTI_LAYER_PARALLAX) || defined(EYE)) @@ -2051,7 +2060,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(TERRAIN_BLENDING) psout.Diffuse.w = blendFactorTerrain; - psout.Depth = lerp(max(depthSampled, input.Position.z), input.Position.z, blendFactorTerrain > sqrt(screenNoise)); + psout.Depth = lerp(max(depthSampled, input.Position.z), input.Position.z, blendFactorTerrain > screenNoise); # endif psout.MotionVectors.zw = float2(0.0, psout.Diffuse.w); @@ -2062,7 +2071,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(WETNESS_EFFECTS) psout.Reflectance = float4(wetnessReflectance, psout.Diffuse.w); - psout.NormalGlossiness = float4(EncodeNormal(screenSpaceNormal), wetnessGlossinessSpecular, psout.Diffuse.w); + psout.NormalGlossiness = float4(EncodeNormal(screenSpaceNormal), lerp(outGlossiness, 1.0, wetnessGlossinessSpecular), psout.Diffuse.w); # else psout.Reflectance = float4(0.0.xxx, psout.Diffuse.w); psout.NormalGlossiness = float4(EncodeNormal(screenSpaceNormal), outGlossiness, psout.Diffuse.w); @@ -2075,8 +2084,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if (defined(ENVMAP) || defined(MULTI_LAYER_PARALLAX) || defined(EYE)) # if defined(DYNAMIC_CUBEMAPS) if (dynamicCubemap) { +# if defined(WETNESS_EFFECTS) + psout.Reflectance.xyz = max(envColor, wetnessReflectance); + psout.NormalGlossiness.z = lerp(1.0 - envRoughness, 1.0, wetnessGlossinessSpecular); +# else psout.Reflectance.xyz = envColor; psout.NormalGlossiness.z = 1.0 - envRoughness; +# endif } # endif # endif diff --git a/package/Shaders/RunGrass.hlsl b/package/Shaders/RunGrass.hlsl index 92b986f96..3e7a9de92 100644 --- a/package/Shaders/RunGrass.hlsl +++ b/package/Shaders/RunGrass.hlsl @@ -190,22 +190,28 @@ PS_OUTPUT main(PS_INPUT input) # else float sunShadowMask = TexShadowMaskSampler.Load(int3(input.HPosition.xy, 0)).x; + float3 diffuseColor = DirLightColorShared.xyz * sunShadowMask; + + float3 ddx = ddx_coarse(input.WorldPosition); + float3 ddy = ddy_coarse(input.WorldPosition); + float3 normal = normalize(cross(ddx, ddy)); + +# if !defined(SSGI) + float3 directionalAmbientColor = mul(DirectionalAmbientShared, float4(normal, 1.0)); + diffuseColor += directionalAmbientColor; +# endif + float3 albedo = baseColor.xyz * input.DiffuseColor.xyz * 0.5; - psout.Diffuse.xyz = DirLightColorShared.xyz * sunShadowMask * albedo; + psout.Diffuse.xyz = diffuseColor * albedo; psout.Diffuse.w = 1; psout.MotionVectors = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, 0); - - float3 ddx = ddx_coarse(input.ViewSpacePosition); - float3 ddy = ddy_coarse(input.ViewSpacePosition); - float3 normal = normalize(cross(ddx, ddy)); - - psout.Normal.xy = EncodeNormal(normal); - psout.Normal.zw = float2(0, 0); + psout.Normal.xy = EncodeNormal(WorldToView(normal, false, 0)); + psout.Normal.zw = 0; psout.Albedo = float4(albedo, 1); - psout.Masks = float4(0, 0, 1, 0); + psout.Masks = float4(0, 0, 0, 0); # endif return psout; diff --git a/package/Shaders/Utility.hlsl b/package/Shaders/Utility.hlsl index c4c977baa..f4e673220 100644 --- a/package/Shaders/Utility.hlsl +++ b/package/Shaders/Utility.hlsl @@ -1433,6 +1433,25 @@ PS_OUTPUT main(PS_INPUT input) } # endif +# if defined(FOLIAGE) + + // Randomly skips rendering foliage to depth to simulate transparency + float2 depthUV = (input.PositionCS.xy / 512.0); + + float4 positionCS = float4(2 * float2(depthUV.x, -depthUV.y + 1) - 1, input.PositionCS.z, 1); + float4 positionMS = mul(CameraViewProjInverse[eyeIndex], positionCS); + positionMS.xyz = positionMS.xyz / positionMS.w; + + positionMS.xyz += CameraPosAdjust[eyeIndex]; + + positionMS.xyz *= 0.000001; + + float checkerboard = frac(sin(dot(positionMS.xy, float2(12.9898, 78.233))) * 43758.5453); + + if (checkerboard > 0.5) + discard; +# endif + float2 baseTexCoord = 0; # if !(defined(RENDER_DEPTH) && defined(RENDER_SHADOWMASK_ANY)) && SHADOWFILTER != 2 # if (defined(RENDER_DEPTH) || defined(RENDER_SHADOWMAP)) && defined(ALPHA_TEST) && !defined(RENDER_SHADOWMAP_PB) diff --git a/src/Deferred.cpp b/src/Deferred.cpp index 8153a7d70..28cbdadaa 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -8,6 +8,7 @@ #include "Features/ScreenSpaceGI.h" #include "Features/Skylighting.h" #include "Features/SubsurfaceScattering.h" +#include "Features/TerrainBlending.h" struct DepthStates { @@ -140,10 +141,6 @@ void Deferred::SetupResources() copyShadowCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\ShadowTest\\CopyShadowData.hlsl", {}, "cs_5_0"); } - { - waterCB = new ConstantBuffer(ConstantBufferDesc()); - } - { D3D11_TEXTURE2D_DESC texDesc; auto mainTex = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; @@ -234,13 +231,19 @@ void Deferred::UpdateConstantBuffer() auto imageSpaceManager = RE::ImageSpaceManager::GetSingleton(); auto useTAA = !REL::Module::IsVR() ? imageSpaceManager->GetRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled : imageSpaceManager->GetVRRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled; - data.FrameCount = useTAA ? RE::BSGraphics::State::GetSingleton()->frameCount : 0; + data.FrameCount = useTAA ? RE::BSGraphics::State::GetSingleton()->uiFrameCount : 0; + data.FrameCountAlwaysActive = RE::BSGraphics::State::GetSingleton()->uiFrameCount; deferredCB->Update(data); } void Deferred::PrepassPasses() { + auto& shaderCache = SIE::ShaderCache::Instance(); + + if (!shaderCache.IsEnabled()) + return; + auto context = RE::BSGraphics::Renderer::GetSingleton()->GetRuntimeData().context; context->OMSetRenderTargets(0, nullptr, nullptr); // Unbind all bound render targets @@ -418,35 +421,32 @@ void Deferred::DeferredPasses() interior = sky->mode.get() != RE::Sky::Mode::kFull; auto skylighting = Skylighting::GetSingleton(); - - if (skylighting->loaded) - skylighting->Compute(); - auto ssgi = ScreenSpaceGI::GetSingleton(); - if (ssgi->loaded) - ssgi->DrawSSGI(prevDiffuseAmbientTexture); - auto dispatchCount = Util::GetScreenDispatchCount(); - // Ambient Composite - { - ID3D11ShaderResourceView* srvs[4]{ - albedo.SRV, - normalRoughness.SRV, - skylighting->loaded ? skylighting->skylightingTexture->srv.get() : nullptr, - ssgi->loaded ? ssgi->texGI[ssgi->outputGIIdx]->srv.get() : nullptr, - }; + if (ssgi->loaded) { + ssgi->DrawSSGI(prevDiffuseAmbientTexture); - context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); + // Ambient Composite + { + ID3D11ShaderResourceView* srvs[4]{ + albedo.SRV, + normalRoughness.SRV, + skylighting->loaded ? skylighting->skylightingTexture->srv.get() : nullptr, + ssgi->loaded ? ssgi->texGI[ssgi->outputGIIdx]->srv.get() : nullptr, + }; - ID3D11UnorderedAccessView* uavs[2]{ main.UAV, prevDiffuseAmbientTexture->uav.get() }; - context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); + context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); - auto shader = interior ? GetComputeAmbientCompositeInterior() : GetComputeAmbientComposite(); - context->CSSetShader(shader, nullptr, 0); + ID3D11UnorderedAccessView* uavs[2]{ main.UAV, prevDiffuseAmbientTexture->uav.get() }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); - context->Dispatch(dispatchCount.x, dispatchCount.y, 1); + auto shader = interior ? GetComputeAmbientCompositeInterior() : GetComputeAmbientComposite(); + context->CSSetShader(shader, nullptr, 0); + + context->Dispatch(dispatchCount.x, dispatchCount.y, 1); + } } auto sss = SubsurfaceScattering::GetSingleton(); @@ -457,6 +457,8 @@ void Deferred::DeferredPasses() if (dynamicCubemaps->loaded) dynamicCubemaps->UpdateCubemap(); + auto terrainBlending = TerrainBlending::GetSingleton(); + // Deferred Composite { ID3D11ShaderResourceView* srvs[10]{ @@ -465,7 +467,7 @@ void Deferred::DeferredPasses() normalRoughness.SRV, masks.SRV, masks2.SRV, - dynamicCubemaps->loaded ? depth.depthSRV : nullptr, + dynamicCubemaps->loaded ? (terrainBlending->loaded ? terrainBlending->blendedDepthTexture16->srv.get() : depth.depthSRV) : nullptr, dynamicCubemaps->loaded ? reflectance.SRV : nullptr, dynamicCubemaps->loaded ? dynamicCubemaps->envTexture->srv.get() : nullptr, dynamicCubemaps->loaded ? dynamicCubemaps->envReflectionsTexture->srv.get() : nullptr, @@ -535,11 +537,6 @@ void Deferred::EndDeferred() stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); // Run OMSetRenderTargets again deferredPass = false; - - { - ID3D11Buffer* buffer = waterCB->CB(); - context->PSSetConstantBuffers(7, 1, &buffer); - } } void Deferred::OverrideBlendStates() @@ -757,12 +754,4 @@ ID3D11ComputeShader* Deferred::GetComputeMainCompositeInterior() mainCompositeInteriorCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\DeferredCompositeCS.hlsl", defines, "cs_5_0"); } return mainCompositeInteriorCS; -} - -void Deferred::UpdateWaterMaterial(RE::BSWaterShaderMaterial* a_material) -{ - WaterCB updateData{}; - updateData.ShallowColor = { a_material->shallowWaterColor.red, a_material->shallowWaterColor.green, a_material->shallowWaterColor.blue }; - updateData.DeepColor = { a_material->deepWaterColor.red, a_material->deepWaterColor.green, a_material->deepWaterColor.blue }; - waterCB->Update(updateData); } \ No newline at end of file diff --git a/src/Deferred.h b/src/Deferred.h index bd1dd04ec..cd58fcf6b 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -2,8 +2,7 @@ #include "Buffer.h" #include "State.h" -#include -#include +#include "Util.h" #define ALBEDO RE::RENDER_TARGETS::kINDIRECT #define SPECULAR RE::RENDER_TARGETS::kINDIRECT_DOWNSCALED @@ -60,7 +59,8 @@ class Deferred float4 CameraData; DirectX::XMFLOAT3X4 DirectionalAmbient; uint FrameCount; - uint pad0[3]; + uint FrameCountAlwaysActive; + uint pad0[2]; }; ConstantBuffer* deferredCB = nullptr; @@ -88,18 +88,6 @@ class Deferred Buffer* perShadow = nullptr; ID3D11ShaderResourceView* shadowView = nullptr; - struct alignas(16) WaterCB - { - float3 ShallowColor; - uint pad0; - float3 DeepColor; - uint pad1; - }; - - ConstantBuffer* waterCB = nullptr; - - void UpdateWaterMaterial(RE::BSWaterShaderMaterial* a_material); - struct Hooks { struct Main_RenderWorld @@ -150,23 +138,12 @@ class Deferred static inline REL::Relocation func; }; - struct BSWaterShader_SetupMaterial - { - static void thunk(RE::BSShader* This, RE::BSWaterShaderMaterial* a_material) - { - GetSingleton()->UpdateWaterMaterial(a_material); - func(This, a_material); - } - static inline REL::Relocation func; - }; - static void Install() { stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x831, 0x841, 0x791)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x8E, 0x84)); stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x319, 0x308, 0x321)); //stl::write_thunk_call(REL::RelocationID(99938, 106583).address() + REL::Relocate(0x2F2, 0x2E1, 0x321)); - stl::write_vfunc<0x4, BSWaterShader_SetupMaterial>(RE::VTABLE_BSWaterShader[0]); logger::info("[Deferred] Installed hooks"); } diff --git a/src/Features/CloudShadows.cpp b/src/Features/CloudShadows.cpp index b75701c9a..aef7772ad 100644 --- a/src/Features/CloudShadows.cpp +++ b/src/Features/CloudShadows.cpp @@ -92,8 +92,6 @@ void CloudShadows::Prepass() auto& context = State::GetSingleton()->context; - context->GenerateMips(texCubemapCloudOcc->srv.get()); - ID3D11ShaderResourceView* srv = texCubemapCloudOcc->srv.get(); context->PSSetShaderResources(27, 1, &srv); } @@ -126,7 +124,7 @@ void CloudShadows::SetupResources() reflections.texture->GetDesc(&texDesc); reflections.SRV->GetDesc(&srvDesc); - texDesc.Format = srvDesc.Format = DXGI_FORMAT_R16G16B16A16_UNORM; + texDesc.Format = srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; texCubemapCloudOcc = new Texture2D(texDesc); texCubemapCloudOcc->CreateSRV(srvDesc); diff --git a/src/Features/DynamicCubemaps.cpp b/src/Features/DynamicCubemaps.cpp index a3df80d16..bb26c5d5e 100644 --- a/src/Features/DynamicCubemaps.cpp +++ b/src/Features/DynamicCubemaps.cpp @@ -6,7 +6,7 @@ #include #include -constexpr auto MIPLEVELS = 10; +constexpr auto MIPLEVELS = 8; void DynamicCubemaps::DrawSettings() { @@ -228,9 +228,9 @@ void DynamicCubemaps::UpdateCubemapCapture() auto& context = State::GetSingleton()->context; auto& depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; - auto& snowSwap = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kSNOW_SWAP]; + auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; - ID3D11ShaderResourceView* srvs[2] = { depth.depthSRV, snowSwap.SRV }; + ID3D11ShaderResourceView* srvs[2] = { depth.depthSRV, main.SRV }; context->CSSetShaderResources(0, 2, srvs); ID3D11UnorderedAccessView* uavs[3] = { envCaptureTexture->uav.get(), envCaptureRawTexture->uav.get(), envCapturePositionTexture->uav.get() }; @@ -240,7 +240,6 @@ void DynamicCubemaps::UpdateCubemapCapture() context->PSGetConstantBuffers(12, 1, buffers); UpdateCubemapCB updateData{}; - updateData.CameraData = Util::GetCameraData(); updateData.Reset = resetCapture; static float3 cameraPreviousPosAdjust = { 0, 0, 0 }; @@ -372,24 +371,34 @@ void DynamicCubemaps::Irradiance(bool a_reflections) void DynamicCubemaps::UpdateCubemap() { - if (nextTask == NextTask::kInferrence) { + switch (nextTask) { + case NextTask::kInferrence: nextTask = NextTask::kIrradiance; Inferrence(false); - } else if (nextTask == NextTask::kIrradiance) { + break; + + case NextTask::kIrradiance: if (activeReflections) nextTask = NextTask::kInferrence2; else nextTask = NextTask::kCapture; Irradiance(false); - } else if (nextTask == NextTask::kInferrence2) { + break; + + case NextTask::kInferrence2: Inferrence(true); nextTask = NextTask::kIrradiance2; - } else if (nextTask == NextTask::kIrradiance2) { + break; + + case NextTask::kIrradiance2: nextTask = NextTask::kCapture; Irradiance(true); - } else if (nextTask == NextTask::kCapture) { + break; + + case NextTask::kCapture: UpdateCubemapCapture(); nextTask = NextTask::kInferrence; + break; } } diff --git a/src/Features/DynamicCubemaps.h b/src/Features/DynamicCubemaps.h index 92b478dc1..044657fb8 100644 --- a/src/Features/DynamicCubemaps.h +++ b/src/Features/DynamicCubemaps.h @@ -33,14 +33,13 @@ struct DynamicCubemaps : Feature ConstantBuffer* spmapCB = nullptr; Texture2D* envTexture = nullptr; Texture2D* envReflectionsTexture = nullptr; - ID3D11UnorderedAccessView* uavArray[9]; - ID3D11UnorderedAccessView* uavReflectionsArray[9]; + ID3D11UnorderedAccessView* uavArray[7]; + ID3D11UnorderedAccessView* uavReflectionsArray[7]; // Reflection capture struct alignas(16) UpdateCubemapCB { - float4 CameraData; uint Reset; float3 CameraPreviousPosAdjust; }; diff --git a/src/Features/GrassCollision.cpp b/src/Features/GrassCollision.cpp index 3b99af1b5..73fa39832 100644 --- a/src/Features/GrassCollision.cpp +++ b/src/Features/GrassCollision.cpp @@ -182,9 +182,12 @@ void GrassCollision::Update() auto& context = State::GetSingleton()->context; - ID3D11Buffer* buffers[1]; - buffers[0] = perFrame->CB(); - context->VSSetConstantBuffers(5, ARRAYSIZE(buffers), buffers); + static Util::FrameChecker frameChecker; + if (frameChecker.isNewFrame()) { + ID3D11Buffer* buffers[1]; + buffers[0] = perFrame->CB(); + context->VSSetConstantBuffers(5, ARRAYSIZE(buffers), buffers); + } } void GrassCollision::Load(json& o_json) diff --git a/src/Features/ScreenSpaceShadows.cpp b/src/Features/ScreenSpaceShadows.cpp index 809afd0c9..5375703ae 100644 --- a/src/Features/ScreenSpaceShadows.cpp +++ b/src/Features/ScreenSpaceShadows.cpp @@ -274,18 +274,20 @@ void ScreenSpaceShadows::SetupResources() D3D11_TEXTURE2D_DESC texDesc{}; D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; shadowMask.texture->GetDesc(&texDesc); shadowMask.SRV->GetDesc(&srvDesc); - shadowMask.UAV->GetDesc(&uavDesc); texDesc.Format = DXGI_FORMAT_R8_UNORM; texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; srvDesc.Format = texDesc.Format; - uavDesc.Format = texDesc.Format; + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = { + .Format = texDesc.Format, + .ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D, + .Texture2D = { .MipSlice = 0 } + }; screenSpaceShadowsTexture = new Texture2D(texDesc); screenSpaceShadowsTexture->CreateSRV(srvDesc); screenSpaceShadowsTexture->CreateUAV(uavDesc); diff --git a/src/Features/Skylighting.cpp b/src/Features/Skylighting.cpp index 71f9d7b55..4e897af95 100644 --- a/src/Features/Skylighting.cpp +++ b/src/Features/Skylighting.cpp @@ -1,30 +1,21 @@ #include "Skylighting.h" #include #include -#include +#include NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( Skylighting::Settings, EnableSkylighting, HeightSkylighting, - AmbientDiffuseBlend, - AmbientMult, - SkyMult, MinimumBound, - RenderTrees, - RenderDistance) + RenderTrees) void Skylighting::DrawSettings() { ImGui::Checkbox("Enable Skylighting", &settings.EnableSkylighting); ImGui::Checkbox("Enable Height Map Rendering", &settings.HeightSkylighting); - ImGui::SliderFloat("Ambient Diffuse Blend", &settings.AmbientDiffuseBlend, 0, 1, "%.2f"); - ImGui::SliderFloat("Directional Pow", &settings.DirectionalPow, 1, 10, "%.0f"); - ImGui::SliderFloat("Ambient Mult", &settings.AmbientMult, 0, 1, "%.2f"); - ImGui::SliderFloat("Sky Mult", &settings.SkyMult, 0, 1, "%.2f"); ImGui::SliderFloat("Minimum Bound", &settings.MinimumBound, 1, 256, "%.0f"); ImGui::Checkbox("Render Trees", &settings.RenderTrees); - ImGui::SliderFloat("Render Distance", &settings.RenderDistance, 5000, 20000, "%.0f"); } void Skylighting::Draw(const RE::BSShader*, const uint32_t) @@ -49,13 +40,18 @@ void Skylighting::SetupResources() main.SRV->GetDesc(&srvDesc); main.UAV->GetDesc(&uavDesc); - texDesc.Format = DXGI_FORMAT_R16G16_FLOAT; + texDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + srvDesc.Format = texDesc.Format; uavDesc.Format = texDesc.Format; skylightingTexture = new Texture2D(texDesc); skylightingTexture->CreateSRV(srvDesc); skylightingTexture->CreateUAV(uavDesc); + + skylightingTempTexture = new Texture2D(texDesc); + skylightingTempTexture->CreateSRV(srvDesc); + skylightingTempTexture->CreateUAV(uavDesc); } { @@ -145,6 +141,53 @@ ID3D11ComputeShader* Skylighting::GetSkylightingShadowMapCS() return skylightingShadowMapCS; } +ID3D11ComputeShader* Skylighting::GetSkylightingBlurHorizontalCS() +{ + if (!skylightingBlurHorizontalCS) { + logger::debug("Compiling SkylightingBlurCS HORIZONTAL"); + skylightingBlurHorizontalCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\Skylighting\\SkylightingBlurCS.hlsl", { { "HORIZONTAL", nullptr } }, "cs_5_0"); + } + return skylightingBlurHorizontalCS; +} + +ID3D11ComputeShader* Skylighting::GetSkylightingBlurVerticalCS() +{ + if (!skylightingBlurVerticalCS) { + logger::debug("Compiling SkylightingVerticalCS"); + skylightingBlurVerticalCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\Skylighting\\SkylightingBlurCS.hlsl", {}, "cs_5_0"); + } + return skylightingBlurVerticalCS; +} + +ID3D11PixelShader* Skylighting::GetFoliagePS() +{ + if (!foliagePixelShader) { + logger::debug("Compiling Utility.hlsl"); + foliagePixelShader = (ID3D11PixelShader*)Util::CompileShader(L"Data\\Shaders\\Utility.hlsl", { { "RENDER_DEPTH", "" }, { "FOLIAGE", "" } }, "ps_5_0"); + } + return foliagePixelShader; +} + +void Skylighting::UpdateFoliage(RE::BSRenderPass* a_pass) +{ + if (inOcclusion) { + foliage = a_pass->shaderProperty->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kTreeAnim); + } +} + +void Skylighting::SkylightingShaderHacks() +{ + if (inOcclusion) { + auto& context = State::GetSingleton()->context; + + if (foliage) { + context->PSSetShader(GetFoliagePS(), NULL, NULL); + } else { + context->PSSetShader(nullptr, NULL, NULL); + } + } +} + void Skylighting::ClearShaderCache() { if (skylightingCS) { @@ -155,6 +198,18 @@ void Skylighting::ClearShaderCache() skylightingShadowMapCS->Release(); skylightingShadowMapCS = nullptr; } + if (skylightingBlurHorizontalCS) { + skylightingBlurHorizontalCS->Release(); + skylightingBlurHorizontalCS = nullptr; + } + if (skylightingBlurVerticalCS) { + skylightingBlurVerticalCS->Release(); + skylightingBlurVerticalCS = nullptr; + } + if (foliagePixelShader) { + foliagePixelShader->Release(); + foliagePixelShader = nullptr; + } } void Skylighting::Compute() @@ -172,11 +227,12 @@ void Skylighting::Compute() auto dispatchCount = Util::GetScreenDispatchCount(); + bool temporal = Util::GetTemporal(); + { PerFrameCB data{}; data.OcclusionViewProj = viewProjMat; - - data.Parameters = { settings.AmbientDiffuseBlend, settings.DirectionalPow, settings.AmbientMult, settings.SkyMult }; + data.EyePosition = { eyePosition.x, eyePosition.y, eyePosition.z, 0 }; auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; auto shadowDirLight = (RE::BSShadowDirectionalLight*)shadowSceneNode->GetRuntimeData().shadowDirLight; @@ -186,31 +242,46 @@ void Skylighting::Compute() data.ShadowDirection = float4(shadowDirLight->lightDirection.x, shadowDirLight->lightDirection.y, shadowDirLight->lightDirection.z, 0); } + data.BufferDim.x = state->screenWidth; + data.BufferDim.y = state->screenHeight; + data.BufferDim.z = 1.0f / data.BufferDim.x; + data.BufferDim.w = 1.0f / data.BufferDim.y; + + data.CameraData = Util::GetCameraData(); + + data.FrameCount = temporal ? RE::BSGraphics::State::GetSingleton()->uiFrameCount : 0; + perFrameCB->Update(data); } auto depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; - auto normalRoughness = renderer->GetRuntimeData().renderTargets[NORMALROUGHNESS]; + auto terrainBlending = TerrainBlending::GetSingleton(); - ID3D11ShaderResourceView* srvs[6]{ - depth.depthSRV, + ID3D11ShaderResourceView* srvs[5]{ + terrainBlending->loaded ? terrainBlending->blendedDepthTexture16->srv.get() : depth.depthSRV, Deferred::GetSingleton()->shadowView, Deferred::GetSingleton()->perShadow->srv.get(), noiseView, - occlusionTexture->srv.get(), - normalRoughness.SRV + occlusionTexture->srv.get() }; - context->CSSetShaderResources(0, 6, srvs); + context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); ID3D11UnorderedAccessView* uavs[1]{ skylightingTexture->uav.get() }; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); auto buffer = perFrameCB->CB(); context->CSSetConstantBuffers(0, 1, &buffer); ID3D11SamplerState* samplers[2] = { Deferred::GetSingleton()->linearSampler, comparisonSampler }; - context->CSSetSamplers(0, 2, samplers); + context->CSSetSamplers(0, ARRAYSIZE(samplers), samplers); + + { + REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; + ID3D11Buffer* buffers[1] = { *perFrame.get() }; + + context->CSSetConstantBuffers(12, ARRAYSIZE(buffers), buffers); + } context->CSSetShader(settings.HeightSkylighting ? GetSkylightingCS() : GetSkylightingShadowMapCS(), nullptr, 0); @@ -221,56 +292,104 @@ void Skylighting::Compute() srvs[2] = nullptr; srvs[3] = nullptr; srvs[4] = nullptr; - srvs[5] = nullptr; - - context->CSSetShaderResources(0, 6, srvs); + context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); uavs[0] = nullptr; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); buffer = nullptr; context->CSSetConstantBuffers(0, 1, &buffer); samplers[0] = nullptr; samplers[1] = nullptr; - context->CSSetSamplers(0, 2, samplers); + context->CSSetSamplers(0, ARRAYSIZE(samplers), samplers); context->CSSetShader(nullptr, nullptr, 0); } -void Skylighting::Prepass() -{ - Bind(); -} - -void Skylighting::Bind() +void Skylighting::ComputeBlur(bool a_horizontal) { auto state = State::GetSingleton(); auto& context = state->context; - { - PerFrameCB data{}; - data.OcclusionViewProj = viewProjMat; + if (!settings.EnableSkylighting) { + return; + } - data.Parameters = { settings.AmbientDiffuseBlend, settings.DirectionalPow, settings.AmbientMult, settings.SkyMult }; + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; - auto shadowDirLight = (RE::BSShadowDirectionalLight*)shadowSceneNode->GetRuntimeData().shadowDirLight; - bool dirShadow = shadowDirLight && shadowDirLight->shadowLightIndex == 0; + auto dispatchCount = Util::GetScreenDispatchCount(); - if (dirShadow) { - data.ShadowDirection = float4(shadowDirLight->lightDirection.x, shadowDirLight->lightDirection.y, shadowDirLight->lightDirection.z, 0); - } + auto depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; - perFrameCB->Update(data); + auto terrainBlending = TerrainBlending::GetSingleton(); + + ID3D11ShaderResourceView* srvs[2]{ + terrainBlending->loaded ? terrainBlending->blendedDepthTexture16->srv.get() : depth.depthSRV, + (a_horizontal ? skylightingTexture : skylightingTempTexture)->srv.get() + }; + + context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); + + ID3D11UnorderedAccessView* uavs[1]{ + (!a_horizontal ? skylightingTexture : skylightingTempTexture)->uav.get() + }; + + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); + + auto buffer = perFrameCB->CB(); + context->CSSetConstantBuffers(0, 1, &buffer); + + ID3D11SamplerState* samplers[1] = { Deferred::GetSingleton()->linearSampler }; + context->CSSetSamplers(0, ARRAYSIZE(samplers), samplers); + + { + REL::Relocation perFrame{ REL::RelocationID(524768, 411384) }; + ID3D11Buffer* buffers[1] = { *perFrame.get() }; + + context->CSSetConstantBuffers(12, ARRAYSIZE(buffers), buffers); } + context->CSSetShader(a_horizontal ? GetSkylightingBlurHorizontalCS() : GetSkylightingBlurVerticalCS(), nullptr, 0); + + context->Dispatch(dispatchCount.x, dispatchCount.y, 1); + + srvs[0] = nullptr; + srvs[1] = nullptr; + context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); + + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); + + buffer = nullptr; + context->CSSetConstantBuffers(0, 1, &buffer); + + samplers[0] = nullptr; + context->CSSetSamplers(0, ARRAYSIZE(samplers), samplers); + + context->CSSetShader(nullptr, nullptr, 0); +} + +void Skylighting::Prepass() +{ + Compute(); + ComputeBlur(true); + ComputeBlur(false); + Bind(); +} + +void Skylighting::Bind() +{ + auto state = State::GetSingleton(); + auto& context = state->context; + auto buffer = perFrameCB->CB(); context->PSSetConstantBuffers(8, 1, &buffer); - ID3D11ShaderResourceView* srvs[1]{ - occlusionTexture->srv.get() + ID3D11ShaderResourceView* srvs[2]{ + occlusionTexture->srv.get(), + skylightingTexture->srv.get(), }; - context->PSSetShaderResources(29, 1, srvs); + context->PSSetShaderResources(29, ARRAYSIZE(srvs), srvs); } diff --git a/src/Features/Skylighting.h b/src/Features/Skylighting.h index 62d71c0ba..83124bb3a 100644 --- a/src/Features/Skylighting.h +++ b/src/Features/Skylighting.h @@ -3,6 +3,7 @@ #include "Buffer.h" #include "Feature.h" #include "State.h" +#include "Util.h" struct Skylighting : Feature { @@ -37,29 +38,41 @@ struct Skylighting : Feature ID3D11ComputeShader* skylightingCS = nullptr; ID3D11ComputeShader* skylightingShadowMapCS = nullptr; + ID3D11ComputeShader* skylightingBlurHorizontalCS = nullptr; + ID3D11ComputeShader* skylightingBlurVerticalCS = nullptr; + ID3D11ComputeShader* GetSkylightingCS(); ID3D11ComputeShader* GetSkylightingShadowMapCS(); + ID3D11ComputeShader* GetSkylightingBlurHorizontalCS(); + ID3D11ComputeShader* GetSkylightingBlurVerticalCS(); ID3D11SamplerState* comparisonSampler; + ID3D11PixelShader* GetFoliagePS(); + ID3D11PixelShader* foliagePixelShader = nullptr; + + bool foliage = false; + void UpdateFoliage(RE::BSRenderPass* a_pass); + + void SkylightingShaderHacks(); + struct alignas(16) PerFrameCB { REX::W32::XMFLOAT4X4 OcclusionViewProj; + float4 EyePosition; float4 ShadowDirection; - float4 Parameters; + float4 BufferDim; + float4 CameraData; + uint FrameCount; + uint pad0[3]; }; struct Settings { bool EnableSkylighting = true; bool HeightSkylighting = true; - float AmbientDiffuseBlend = 0.5; - float DirectionalPow = 5.0; - float AmbientMult = 1.0; - float SkyMult = 1.0; float MinimumBound = 128; bool RenderTrees = false; - float RenderDistance = 10000; }; Settings settings; @@ -69,11 +82,15 @@ struct Skylighting : Feature virtual void ClearShaderCache() override; Texture2D* skylightingTexture = nullptr; + Texture2D* skylightingTempTexture = nullptr; ID3D11ShaderResourceView* noiseView = nullptr; Texture2D* occlusionTexture = nullptr; + RE::NiPoint3 eyePosition; + std::chrono::time_point lastUpdateTimer = std::chrono::system_clock::now(); + struct BSParticleShaderRainEmitter { void* vftable_BSParticleShaderRainEmitter_0; @@ -95,6 +112,7 @@ struct Skylighting : Feature } void Compute(); + void ComputeBlur(bool a_horizontal); enum class ShaderTechnique { @@ -325,7 +343,7 @@ struct Skylighting : Feature precipitationOcclusionMapRenderPassList->Clear(); - if (!GetSingleton()->inOcclusion && property->flags.any(kSkinned, kTreeAnim)) + if (!GetSingleton()->inOcclusion && property->flags.any(kSkinned, kTreeAnim) && !GetSingleton()->settings.RenderTrees) return precipitationOcclusionMapRenderPassList; if (property->flags.any(kSkinned) && !property->flags.any(kTreeAnim)) @@ -387,46 +405,59 @@ struct Skylighting : Feature } else { doPrecip = true; - auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - auto& precipitation = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; - RE::BSGraphics::DepthStencilData precipitationCopy = precipitation; + auto singleton = GetSingleton(); + + std::chrono::time_point currentTimer = std::chrono::system_clock::now(); + auto timePassed = std::chrono::duration_cast(currentTimer - singleton->lastUpdateTimer).count(); + + if (timePassed >= (1000.0f / 30.0f)) { + singleton->lastUpdateTimer = currentTimer; - precipitation.depthSRV = GetSingleton()->occlusionTexture->srv.get(); - precipitation.texture = GetSingleton()->occlusionTexture->resource.get(); - precipitation.views[0] = GetSingleton()->occlusionTexture->dsv.get(); + singleton->eyePosition = Util::GetEyePosition(0); - static float& PrecipitationShaderCubeSize = (*(float*)REL::RelocationID(515451, 401590).address()); - float originalPrecipitationShaderCubeSize = PrecipitationShaderCubeSize; + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto& precipitation = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + RE::BSGraphics::DepthStencilData precipitationCopy = precipitation; - static RE::NiPoint3& PrecipitationShaderDirection = (*(RE::NiPoint3*)REL::RelocationID(515509, 401648).address()); - RE::NiPoint3 originalParticleShaderDirection = PrecipitationShaderDirection; + precipitation.depthSRV = singleton->occlusionTexture->srv.get(); + precipitation.texture = singleton->occlusionTexture->resource.get(); + precipitation.views[0] = singleton->occlusionTexture->dsv.get(); - GetSingleton()->inOcclusion = true; - PrecipitationShaderCubeSize = GetSingleton()->settings.RenderDistance; + static float& PrecipitationShaderCubeSize = (*(float*)REL::RelocationID(515451, 401590).address()); + float originalPrecipitationShaderCubeSize = PrecipitationShaderCubeSize; - float originaLastCubeSize = precip->lastCubeSize; - precip->lastCubeSize = PrecipitationShaderCubeSize; + static RE::NiPoint3& PrecipitationShaderDirection = (*(RE::NiPoint3*)REL::RelocationID(515509, 401648).address()); + RE::NiPoint3 originalParticleShaderDirection = PrecipitationShaderDirection; - PrecipitationShaderDirection = { 0, 0, -1 }; + singleton->inOcclusion = true; + PrecipitationShaderCubeSize = 10000; - Precipitation_SetupMask(precip); - Precipitation_SetupMask(precip); // Calling setup twice fixes an issue when it is raining + float originaLastCubeSize = precip->lastCubeSize; + precip->lastCubeSize = PrecipitationShaderCubeSize; - BSParticleShaderRainEmitter* rain = new BSParticleShaderRainEmitter; - Precipitation_RenderMask(precip, rain); - GetSingleton()->inOcclusion = false; - RE::BSParticleShaderCubeEmitter* cube = (RE::BSParticleShaderCubeEmitter*)rain; - GetSingleton()->viewProjMat = cube->occlusionProjection; + PrecipitationShaderDirection = { 0, 0, -1 }; - cube = nullptr; - delete rain; + Precipitation_SetupMask(precip); + Precipitation_SetupMask(precip); // Calling setup twice fixes an issue when it is raining + + BSParticleShaderRainEmitter* rain = new BSParticleShaderRainEmitter; + Precipitation_RenderMask(precip, rain); + singleton->inOcclusion = false; + RE::BSParticleShaderCubeEmitter* cube = (RE::BSParticleShaderCubeEmitter*)rain; + singleton->viewProjMat = cube->occlusionProjection; - PrecipitationShaderCubeSize = originalPrecipitationShaderCubeSize; - precip->lastCubeSize = originaLastCubeSize; + cube = nullptr; + delete rain; - PrecipitationShaderDirection = originalParticleShaderDirection; + PrecipitationShaderCubeSize = originalPrecipitationShaderCubeSize; + precip->lastCubeSize = originaLastCubeSize; - precipitation = precipitationCopy; + PrecipitationShaderDirection = originalParticleShaderDirection; + + precipitation = precipitationCopy; + + singleton->foliage = false; + } } } else { func(); @@ -436,12 +467,12 @@ struct Skylighting : Feature static inline REL::Relocation func; }; - struct BSWaterShader_SetupMaterial + struct BSUtilityShader_SetupGeometry { - static void thunk(RE::BSShader* This, RE::BSWaterShaderMaterial* a_material) + static void thunk(RE::BSShader* This, RE::BSRenderPass* Pass, uint32_t RenderFlags) { - //GetSingleton()->Bind(); - func(This, a_material); + GetSingleton()->UpdateFoliage(Pass); + func(This, Pass, RenderFlags); } static inline REL::Relocation func; }; @@ -453,7 +484,7 @@ struct Skylighting : Feature logger::info("[SKYLIGHTING] Hooking BSLightingShaderProperty::GetPrecipitationOcclusionMapRenderPassesImp"); stl::write_vfunc<0x2D, BSLightingShaderProperty_GetPrecipitationOcclusionMapRenderPassesImpl>(RE::VTABLE_BSLightingShaderProperty[0]); stl::write_thunk_call(REL::RelocationID(35560, 36559).address() + REL::Relocate(0x3A1, 0x3A1, 0x2FA)); - stl::write_vfunc<0x4, BSWaterShader_SetupMaterial>(RE::VTABLE_BSWaterShader[0]); + stl::write_vfunc<0x6, BSUtilityShader_SetupGeometry>(RE::VTABLE_BSUtilityShader[0]); } }; diff --git a/src/Features/SubsurfaceScattering.cpp b/src/Features/SubsurfaceScattering.cpp index ea131c6f0..924a0451a 100644 --- a/src/Features/SubsurfaceScattering.cpp +++ b/src/Features/SubsurfaceScattering.cpp @@ -1,9 +1,10 @@ #include "SubsurfaceScattering.h" -#include +#include "Deferred.h" +#include "Features/TerrainBlending.h" +#include "ShaderCache.h" #include "State.h" -#include -#include +#include "Util.h" NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(SubsurfaceScattering::DiffusionProfile, BlurRadius, Thickness, Strength, Falloff) @@ -184,15 +185,18 @@ void SubsurfaceScattering::DrawSSS() context->CSSetConstantBuffers(1, 1, buffer); auto main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; + auto depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; auto mask = renderer->GetRuntimeData().renderTargets[MASKS]; ID3D11UnorderedAccessView* uav = blurHorizontalTemp->uav.get(); context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + auto terrainBlending = TerrainBlending::GetSingleton(); + ID3D11ShaderResourceView* views[3]; views[0] = main.SRV; - views[1] = depth.depthSRV; + views[1] = terrainBlending->loaded ? terrainBlending->blendedDepthTexture16->srv.get() : depth.depthSRV, views[2] = mask.SRV; context->CSSetShaderResources(0, 3, views); @@ -236,15 +240,8 @@ void SubsurfaceScattering::DrawSSS() context->CSSetShader(shader, nullptr, 0); } -void SubsurfaceScattering::Draw(const RE::BSShader* a_shader, const uint32_t) +void SubsurfaceScattering::Draw(const RE::BSShader*, const uint32_t) { - if (a_shader->shaderType.get() == RE::BSShader::Type::Lighting) { - if (normalsMode == RE::RENDER_TARGET::kNONE) { - auto shadowState = RE::BSGraphics::RendererShadowState::GetSingleton(); - GET_INSTANCE_MEMBER(renderTargets, shadowState) - normalsMode = renderTargets[2]; - } - } } void SubsurfaceScattering::SetupResources() @@ -293,8 +290,6 @@ void SubsurfaceScattering::SetupResources() void SubsurfaceScattering::Reset() { - normalsMode = RE::RENDER_TARGET::kNONE; - auto& shaderManager = RE::BSShaderManager::State::GetSingleton(); shaderManager.characterLightEnabled = SIE::ShaderCache::Instance().IsEnabled() ? settings.EnableCharacterLighting : true; diff --git a/src/Features/SubsurfaceScattering.h b/src/Features/SubsurfaceScattering.h index 0118ca5c2..f9c2a978c 100644 --- a/src/Features/SubsurfaceScattering.h +++ b/src/Features/SubsurfaceScattering.h @@ -65,8 +65,6 @@ struct SubsurfaceScattering : Feature ID3D11ComputeShader* horizontalSSBlur = nullptr; ID3D11ComputeShader* verticalSSBlur = nullptr; - RE::RENDER_TARGET normalsMode = RE::RENDER_TARGET::kNONE; - virtual inline std::string GetName() { return "Subsurface Scattering"; } virtual inline std::string GetShortName() { return "SubsurfaceScattering"; } inline std::string_view GetShaderDefineName() override { return "SSS"; } diff --git a/src/Features/TerrainBlending.cpp b/src/Features/TerrainBlending.cpp index ca68bc4d4..04b754d49 100644 --- a/src/Features/TerrainBlending.cpp +++ b/src/Features/TerrainBlending.cpp @@ -111,6 +111,16 @@ void TerrainBlending::SetupResources() blendedDepthTexture->CreateUAV(uavDesc); terrainOffsetTexture->CreateUAV(uavDesc); + texDesc.Format = DXGI_FORMAT_R16_UNORM; + srvDesc.Format = texDesc.Format; + rtvDesc.Format = texDesc.Format; + uavDesc.Format = texDesc.Format; + + blendedDepthTexture16 = new Texture2D(texDesc); + blendedDepthTexture16->CreateSRV(srvDesc); + blendedDepthTexture16->CreateRTV(rtvDesc); + blendedDepthTexture16->CreateUAV(uavDesc); + auto& mainDepth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kMAIN]; depthSRVBackup = mainDepth.depthSRV; @@ -256,10 +266,10 @@ void TerrainBlending::BlendPrepassDepths() { ID3D11ShaderResourceView* views[2] = { depthSRVBackup, terrainDepth.depthSRV }; - context->CSSetShaderResources(0, 2, views); + context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uav = blendedDepthTexture->uav.get(); - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + ID3D11UnorderedAccessView* uavs[2] = { blendedDepthTexture->uav.get(), blendedDepthTexture16->uav.get() }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetShader(GetDepthBlendShader(), nullptr, 0); @@ -268,10 +278,10 @@ void TerrainBlending::BlendPrepassDepths() { ID3D11ShaderResourceView* views[2] = { depthSRVBackup, terrainDepthTexture->srv.get() }; - context->CSSetShaderResources(0, 2, views); + context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uav = terrainOffsetTexture->uav.get(); - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + ID3D11UnorderedAccessView* uavs[2] = { terrainOffsetTexture->uav.get(), nullptr }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetShader(GetDepthFixShader(), nullptr, 0); @@ -279,10 +289,10 @@ void TerrainBlending::BlendPrepassDepths() } ID3D11ShaderResourceView* views[2] = { nullptr, nullptr }; - context->CSSetShaderResources(0, 2, views); + context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uav = nullptr; - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + ID3D11UnorderedAccessView* uavs[2] = { nullptr, nullptr }; + context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); ID3D11ComputeShader* shader = nullptr; context->CSSetShader(shader, nullptr, 0); diff --git a/src/Features/TerrainBlending.h b/src/Features/TerrainBlending.h index ff930900e..fb2b494fb 100644 --- a/src/Features/TerrainBlending.h +++ b/src/Features/TerrainBlending.h @@ -59,6 +59,8 @@ struct TerrainBlending : Feature Texture2D* terrainDepthTexture = nullptr; Texture2D* blendedDepthTexture = nullptr; + Texture2D* blendedDepthTexture16 = nullptr; + Texture2D* terrainOffsetTexture = nullptr; RE::BSGraphics::DepthStencilData terrainDepth; diff --git a/src/Features/WaterCaustics.cpp b/src/Features/WaterCaustics.cpp index b27f3ccf1..dd49e107e 100644 --- a/src/Features/WaterCaustics.cpp +++ b/src/Features/WaterCaustics.cpp @@ -1,23 +1,12 @@ #include "WaterCaustics.h" + +#include "State.h" #include "Util.h" -#include -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( - WaterCaustics::Settings, - EnableWaterCaustics) +#include void WaterCaustics::DrawSettings() { - if (ImGui::TreeNodeEx("Water Caustics", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("Enable Water Caustics", (bool*)&settings.EnableWaterCaustics); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Enables water caustics. " - "Water caustics are the way light bends to create dancing patterns at the bottom of bodies of water."); - } - - ImGui::TreePop(); - } } void WaterCaustics::SetupResources() @@ -26,57 +15,25 @@ void WaterCaustics::SetupResources() auto& context = State::GetSingleton()->context; DirectX::CreateDDSTextureFromFile(device, context, L"Data\\Shaders\\WaterCaustics\\watercaustics.dds", nullptr, &causticsView); - 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(PerPass); - sbDesc.ByteWidth = sizeof(PerPass); - perPass = 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; - perPass->CreateSRV(srvDesc); } void WaterCaustics::Prepass() { auto& context = State::GetSingleton()->context; context->PSSetShaderResources(70, 1, &causticsView); - PerPass data{}; - data.settings = settings; - - D3D11_MAPPED_SUBRESOURCE mapped; - DX::ThrowIfFailed(context->Map(perPass->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); - size_t bytes = sizeof(PerPass); - memcpy_s(mapped.pData, bytes, &data, bytes); - context->Unmap(perPass->resource.get(), 0); - - ID3D11ShaderResourceView* views[1]{}; - views[0] = perPass->srv.get(); - context->PSSetShaderResources(71, ARRAYSIZE(views), views); } void WaterCaustics::Load(json& o_json) { - if (o_json[GetName()].is_object()) - settings = o_json[GetName()]; - Feature::Load(o_json); } -void WaterCaustics::Save(json& o_json) +void WaterCaustics::Save(json&) { - o_json[GetName()] = settings; } void WaterCaustics::RestoreDefaultSettings() { - settings = {}; } bool WaterCaustics::HasShaderDefine(RE::BSShader::Type) diff --git a/src/Features/WaterCaustics.h b/src/Features/WaterCaustics.h index 28dae3010..3aabc66dd 100644 --- a/src/Features/WaterCaustics.h +++ b/src/Features/WaterCaustics.h @@ -1,7 +1,7 @@ #pragma once #include "Feature.h" -#include "State.h" + struct WaterCaustics : Feature { public: @@ -11,20 +11,6 @@ struct WaterCaustics : Feature return &singleton; } - struct Settings - { - uint32_t EnableWaterCaustics = 1; - }; - - struct PerPass - { - Settings settings; - }; - - Settings settings; - - std::unique_ptr perPass = nullptr; - ID3D11ShaderResourceView* causticsView; virtual inline std::string GetName() { return "Water Caustics"; } diff --git a/src/Features/WaterParallax.cpp b/src/Features/WaterParallax.cpp index 2398f298d..a9b55baaa 100644 --- a/src/Features/WaterParallax.cpp +++ b/src/Features/WaterParallax.cpp @@ -1,76 +1,31 @@ #include "WaterParallax.h" + #include "State.h" #include "Util.h" -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( - WaterParallax::Settings, - EnableWaterParallax) - void WaterParallax::DrawSettings() { - if (ImGui::TreeNodeEx("Water Parallax", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("Enable Water Parallax", (bool*)&settings.EnableWaterParallax); - if (auto _tt = Util::HoverTooltipWrapper()) { - ImGui::Text( - "Enables water parallax. " - "Parallax adds depth to the water surface to simulate greater detail."); - } - - ImGui::TreePop(); - } } void WaterParallax::Draw(const RE::BSShader*, const uint32_t) { - auto& context = State::GetSingleton()->context; - PerPass data{}; - data.settings = settings; - - D3D11_MAPPED_SUBRESOURCE mapped; - DX::ThrowIfFailed(context->Map(perPass->resource.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); - size_t bytes = sizeof(PerPass); - memcpy_s(mapped.pData, bytes, &data, bytes); - context->Unmap(perPass->resource.get(), 0); - - ID3D11ShaderResourceView* views[1]{}; - views[0] = perPass->srv.get(); - context->PSSetShaderResources(72, ARRAYSIZE(views), views); } void WaterParallax::SetupResources() { - 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(PerPass); - sbDesc.ByteWidth = sizeof(PerPass); - perPass = 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; - perPass->CreateSRV(srvDesc); } void WaterParallax::Load(json& o_json) { - if (o_json[GetName()].is_object()) - settings = o_json[GetName()]; Feature::Load(o_json); } -void WaterParallax::Save(json& o_json) +void WaterParallax::Save(json&) { - o_json[GetName()] = settings; } void WaterParallax::RestoreDefaultSettings() { - settings = {}; } bool WaterParallax::HasShaderDefine(RE::BSShader::Type) diff --git a/src/Features/WaterParallax.h b/src/Features/WaterParallax.h index d1cf6cf7a..772e3d9c2 100644 --- a/src/Features/WaterParallax.h +++ b/src/Features/WaterParallax.h @@ -11,20 +11,6 @@ struct WaterParallax : Feature return &singleton; } - struct Settings - { - uint32_t EnableWaterParallax = 1; - }; - - struct PerPass - { - Settings settings; - }; - - Settings settings; - - std::unique_ptr perPass = nullptr; - virtual inline std::string GetName() { return "Water Parallax"; } virtual inline std::string GetShortName() { return "WaterParallax"; } inline std::string_view GetShaderDefineName() override { return "WATER_PARALLAX"; } diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 254d0d261..91391a713 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -370,16 +370,6 @@ namespace Hooks static inline REL::Relocation func; }; - struct CreateRenderTarget_ShadowMask - { - static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties) - { - State::GetSingleton()->ModifyRenderTarget(a_target, a_properties); - func(This, a_target, a_properties); - } - static inline REL::Relocation func; - }; - struct BSShader__BeginTechnique_SetVertexShader { static void thunk(RE::BSGraphics::Renderer* This, RE::BSGraphics::VertexShader* a_vertexShader) @@ -445,8 +435,6 @@ namespace Hooks { static void thunk(RE::BSGraphics::Renderer* This, uint32_t a_target, RE::BSGraphics::DepthStencilTargetProperties* a_properties) { - a_properties->height = 256; - a_properties->width = 256; a_properties->use16BitsDepth = true; a_properties->stencil = false; func(This, a_target, a_properties); @@ -454,6 +442,17 @@ namespace Hooks static inline REL::Relocation func; }; + struct CreateCubemapRenderTarget_Reflections + { + static void thunk(RE::BSGraphics::Renderer* This, uint32_t a_target, RE::BSGraphics::CubeMapRenderTargetProperties* a_properties) + { + a_properties->height = 128; + a_properties->width = 128; + func(This, a_target, a_properties); + } + static inline REL::Relocation func; + }; + void Install() { SKSE::AllocTrampoline(14); @@ -491,8 +490,7 @@ namespace Hooks stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x46B, 0x46E, 0x5C3)); if (!REL::Module::IsVR()) stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x406, 0x409)); - stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x555, 0x554, 0x6b9)); - stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x1245, 0x123B, 0x1917)); + stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0xA25, 0xA25, 0xCD2)); } } \ No newline at end of file diff --git a/src/Menu.cpp b/src/Menu.cpp index f832cfde4..837514521 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -446,8 +446,6 @@ void Menu::DrawSettings() ImGui::Separator(); - VariableRateShading::GetSingleton()->DrawSettings(); - if (ImGui::BeginTable("Feature Table", 2, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Resizable)) { ImGui::TableSetupColumn("##ListOfFeatures", 0, 3); ImGui::TableSetupColumn("##FeatureConfig", 0, 7); diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index 1cee4fbed..61e6ff5df 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -11,6 +11,8 @@ #include "Feature.h" #include "State.h" +#include "Features/DynamicCubemaps.h" + namespace SIE { namespace SShaderCache @@ -2022,6 +2024,7 @@ namespace SIE processedTasks.insert(task); tasksInProgress.erase(task); conditionVariable.notify_one(); + DynamicCubemaps::GetSingleton()->resetCapture = true; } void CompilationSet::Clear() diff --git a/src/State.cpp b/src/State.cpp index 41de136d6..fab2412f6 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -10,25 +10,31 @@ #include "Util.h" #include "Deferred.h" +#include "Features/Skylighting.h" #include "Features/TerrainBlending.h" #include "VariableRateShading.h" void State::Draw() { - auto terrainBlending = TerrainBlending::GetSingleton(); - if (terrainBlending->loaded) - terrainBlending->TerrainShaderHacks(); - - if (currentShader && updateShader) { - auto type = currentShader->shaderType.get(); - if (type == RE::BSShader::Type::Utility) { - if (currentPixelDescriptor & static_cast(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { - Deferred::GetSingleton()->CopyShadowData(); + auto& shaderCache = SIE::ShaderCache::Instance(); + if (shaderCache.IsEnabled()) { + auto terrainBlending = TerrainBlending::GetSingleton(); + if (terrainBlending->loaded) + terrainBlending->TerrainShaderHacks(); + + auto skylighting = Skylighting::GetSingleton(); + if (skylighting->loaded) + skylighting->SkylightingShaderHacks(); + + if (currentShader && updateShader) { + auto type = currentShader->shaderType.get(); + if (type == RE::BSShader::Type::Utility) { + if (currentPixelDescriptor & static_cast(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { + Deferred::GetSingleton()->CopyShadowData(); + } } - } - auto& shaderCache = SIE::ShaderCache::Instance(); - if (shaderCache.IsEnabled()) { + VariableRateShading::GetSingleton()->UpdateViews(type != RE::BSShader::Type::ImageSpace && type != RE::BSShader::Type::Sky && type != RE::BSShader::Type::Water); if (type > 0 && type < RE::BSShader::Type::Total) { if (enabledClasses[type - 1]) { @@ -44,8 +50,11 @@ void State::Draw() lastVertexDescriptor = currentVertexDescriptor; lastPixelDescriptor = currentPixelDescriptor; - ID3D11Buffer* buffers[3] = { permutationCB->CB(), sharedDataCB->CB(), featureDataCB->CB() }; - context->PSSetConstantBuffers(4, 3, buffers); + static Util::FrameChecker frameChecker; + if (frameChecker.isNewFrame()) { + ID3D11Buffer* buffers[3] = { permutationCB->CB(), sharedDataCB->CB(), featureDataCB->CB() }; + context->PSSetConstantBuffers(4, 3, buffers); + } } if (IsDeveloperMode()) { @@ -56,8 +65,8 @@ void State::Draw() } } } + updateShader = false; } - updateShader = false; } void State::Reset() @@ -510,6 +519,9 @@ void State::UpdateSharedData() delete[] data; } - auto depth = RE::BSGraphics::Renderer::GetSingleton()->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY].depthSRV; - context->PSSetShaderResources(20, 1, &depth); + auto& depth = RE::BSGraphics::Renderer::GetSingleton()->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; + auto terrainBlending = TerrainBlending::GetSingleton(); + auto srv = (terrainBlending->loaded ? terrainBlending->blendedDepthTexture16->srv.get() : depth.depthSRV); + + context->PSSetShaderResources(20, 1, &srv); } diff --git a/src/Util.cpp b/src/Util.cpp index f1fdc55b0..c66814338 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -320,6 +320,7 @@ namespace Util logger::info("Game Setting {} {}", set.first, set.second->GetName()); } } + float4 GetCameraData() { float4 cameraData{}; @@ -352,6 +353,12 @@ namespace Util return { dispatchX, dispatchY }; } + bool GetTemporal() + { + auto imageSpaceManager = RE::ImageSpaceManager::GetSingleton(); + return (!REL::Module::IsVR() ? imageSpaceManager->GetRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled : imageSpaceManager->GetVRRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled) || State::GetSingleton()->upscalerLoaded; + } + HoverTooltipWrapper::HoverTooltipWrapper() { hovered = ImGui::IsItemHovered(); diff --git a/src/Util.h b/src/Util.h index 273a8a85b..694efe8b1 100644 --- a/src/Util.h +++ b/src/Util.h @@ -27,6 +27,7 @@ namespace Util float4 TryGetWaterData(float offsetX, float offsetY); void DumpSettingsOptions(); float4 GetCameraData(); + bool GetTemporal(); inline RE::NiPoint3 GetAverageEyePosition() { diff --git a/src/VariableRateShading.h b/src/VariableRateShading.h index 76bd91264..748b56b2a 100644 --- a/src/VariableRateShading.h +++ b/src/VariableRateShading.h @@ -12,7 +12,7 @@ class VariableRateShading return &singleton; } - bool enableVRS = true; + bool enableVRS = false; bool nvapiLoaded = false; bool vrsActive = false;