diff --git a/features/Cloud Shadows/Shaders/CloudShadows/output.cs.hlsl b/features/Cloud Shadows/Shaders/CloudShadows/output.cs.hlsl index 774f097ba..c9a778b5e 100644 --- a/features/Cloud Shadows/Shaders/CloudShadows/output.cs.hlsl +++ b/features/Cloud Shadows/Shaders/CloudShadows/output.cs.hlsl @@ -55,13 +55,9 @@ float3 getCloudShadowMult(float3 rel_pos, float3 eye_to_sun) [numthreads(32, 32, 1)] void main(uint2 dtid : SV_DispatchThreadID) { float2 uv = (dtid + .5) * RcpBufferDim; -#ifdef VR - const uint eyeIndex = uv > .5; -#else - const uint eyeIndex = 0; -#endif + uint eyeIndex = GetEyeIndexFromTexCoord(uv); - float3 ndc = float3(ConvertToStereoUV(uv, eyeIndex), 1); + float3 ndc = float3(ConvertFromStereoUV(uv, eyeIndex), 1); ndc = ndc * 2 - 1; ndc.y = -ndc.y; ndc.z = TexDepth[dtid]; diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli index f2fa58d20..c95c66b27 100644 --- a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/DynamicCubemaps.hlsli @@ -31,23 +31,26 @@ float3 GetDynamicCubemap(float2 uv, float3 N, float3 VN, float3 V, float roughne float level = roughness * 9.0; - float3 specularIrradiance = specularTexture.SampleLevel(SampColorSampler, R, level).xyz; - specularIrradiance = sRGB2Lin(specularIrradiance); - diffuseColor = sRGB2Lin(diffuseColor); - float2 specularBRDF = EnvBRDFApprox(roughness, NoV); // Horizon specular occlusion // https://marmosetco.tumblr.com/post/81245981087 float horizon = min(1.0 + dot(R, VN), 1.0); - specularIrradiance *= horizon * horizon; + horizon *= horizon * horizon; // Roughness dependent fresnel // https://www.jcgt.org/published/0008/01/03/paper.pdf float3 Fr = max(1.0.xxx - roughness.xxx, F0) - F0; float3 S = Fr * pow(1.0 - NoV, 5.0); +# if defined(DEFERRED) + return horizon * ((F0 + S) * specularBRDF.x + specularBRDF.y); +# else + float3 specularIrradiance = specularTexture.SampleLevel(SampColorSampler, R, level).xyz; + specularIrradiance = sRGB2Lin(specularIrradiance); + return specularIrradiance * ((F0 + S) * specularBRDF.x + specularBRDF.y); +# endif } float3 GetDynamicCubemapFresnel(float2 uv, float3 N, float3 VN, float3 V, float roughness, float level, float3 diffuseColor, float distance) diff --git a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl index c3786b002..9920693aa 100644 --- a/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl +++ b/features/Dynamic Cubemaps/Shaders/DynamicCubemaps/InferCubemapCS.hlsl @@ -1,9 +1,7 @@ TextureCube EnvCaptureTexture : register(t0); -#if defined(REFLECTIONS) TextureCube ReflectionsTexture : register(t1); -#else -TextureCube DefaultCubemap : register(t1); -#endif +TextureCube DefaultCubemap : register(t2); + RWTexture2DArray EnvInferredTexture : register(u0); SamplerState LinearSampler : register(s0); @@ -102,7 +100,7 @@ float3 Lin2sRGB(float3 color) #if defined(REFLECTIONS) color.rgb = lerp(color.rgb, sRGB2Lin(ReflectionsTexture.SampleLevel(LinearSampler, uv, 0)), saturate(mipLevel * (1.0 / 10.0))); #else - color.rgb = lerp(color.rgb, color.rgb * sRGB2Lin(DefaultCubemap.SampleLevel(LinearSampler, uv, 0).x) * 10.0, saturate(mipLevel * (1.0 / 10.0))); + color.rgb = lerp(color.rgb, color.rgb * sRGB2Lin(DefaultCubemap.SampleLevel(LinearSampler, uv, 0).x), saturate(mipLevel * (1.0 / 10.0))); #endif color.rgb = Lin2sRGB(color.rgb); diff --git a/features/Grass Lighting/Shaders/RunGrass.hlsl b/features/Grass Lighting/Shaders/RunGrass.hlsl index d51b9c9c9..4731cd023 100644 --- a/features/Grass Lighting/Shaders/RunGrass.hlsl +++ b/features/Grass Lighting/Shaders/RunGrass.hlsl @@ -344,7 +344,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace if (!frontFace) normal = -normal; - normal = normalize(lerp(normal, normalize(input.SphereNormal.xyz), input.SphereNormal.w)); + normal = normalize(lerp(normal, normalize(input.SphereNormal.xyz), sqrt(input.SphereNormal.w))); if (complex) { float3 normalColor = TransformNormal(specColor.xyz); @@ -367,12 +367,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float dirLightAngle = dot(normal, DirLightDirection.xyz); + float3 albedo = max(0, baseColor.xyz * input.VertexColor.xyz); + // Generated texture to simulate light transport. - // Numerous attempts were made to use a more interesting algorithm however they were mostly fruitless. - float3 subsurfaceColor = baseColor.xyz * sqrt(input.SphereNormal.w); + float3 subsurfaceColor = pow(lerp(RGBToLuminance(albedo.xyz), albedo.xyz, 2.0), 1.5) * input.SphereNormal.w; - // Applies lighting from the opposite direction. Does not account for normals perpendicular to the light source. - lightsDiffuseColor += subsurfaceColor * dirLightColor * saturate(-dirLightAngle) * SubsurfaceScatteringAmount; + float3 sss = dirLightColor * sqrt(-dirLightAngle * 0.5 + 0.5); if (complex) lightsSpecularColor += GetLightSpecularInput(DirLightDirection, viewDirection, normal, dirLightColor, Glossiness); @@ -417,7 +417,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 lightDiffuseColor = lightColor * saturate(lightAngle.xxx); - lightDiffuseColor += subsurfaceColor * lightColor * saturate(-lightAngle) * SubsurfaceScatteringAmount; + sss += lightColor * sqrt(-lightAngle * 0.5 + 0.5); + lightsDiffuseColor += lightDiffuseColor * intensityMultiplier; if (complex) @@ -429,8 +430,8 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace diffuseColor += lightsDiffuseColor; - float3 albedo = max(0, baseColor.xyz * input.VertexColor.xyz); diffuseColor *= albedo; + diffuseColor += max(0, sss * subsurfaceColor * SubsurfaceScatteringAmount); specularColor += lightsSpecularColor; specularColor *= specColor.w * SpecularStrength; diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/blur.cs.hlsl b/features/Screen Space GI/Shaders/ScreenSpaceGI/blur.cs.hlsl new file mode 100644 index 000000000..de1f5f2e1 --- /dev/null +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/blur.cs.hlsl @@ -0,0 +1,94 @@ +// FAST DENOISING WITH SELF-STABILIZING RECURRENT BLURS +// https://developer.download.nvidia.com/video/gputechconf/gtc/2020/presentations/s22699-fast-denoising-with-self-stabilizing-recurrent-blurs.pdf + +#include "../Common/FastMath.hlsli" +#include "../Common/GBuffer.hlsli" +#include "../Common/VR.hlsli" +#include "common.hlsli" + +Texture2D srcGI : register(t0); // maybe half-res +Texture2D srcAccumFrames : register(t1); // maybe half-res +Texture2D srcDepth : register(t2); +Texture2D srcNormal : register(t3); + +RWTexture2D outGI : register(u0); +RWTexture2D outAccumFrames : register(u1); + +// 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) +}; + +float HistoryRadiusScaling(float accumFrames) +{ + return lerp(1, 0.5, accumFrames / MaxAccumFrames); +}; + +[numthreads(8, 8, 1)] void main(const uint2 dtid + : SV_DispatchThreadID) { + const float srcScale = SrcFrameDim * RcpTexDim; + const float outScale = OutFrameDim * RcpTexDim; + + float radius = BlurRadius; +#ifdef TEMPORAL_DENOISER + float accumFrames = srcAccumFrames[dtid]; + radius *= HistoryRadiusScaling(accumFrames * 255); + radius = max(radius, 2); +#endif + const uint numSamples = 8; + + const float2 uv = (dtid + .5) * RcpOutFrameDim; + uint eyeIndex = GET_EYE_IDX(uv); + const float2 screenPos = ConvertToStereoUV(uv, eyeIndex); + + float depth = READ_DEPTH(srcDepth, dtid); + float3 pos = ScreenToViewPosition(screenPos, depth, eyeIndex); + float3 normal = DecodeNormal(FULLRES_LOAD(srcNormal, dtid, uv, samplerLinearClamp).xy); + + lpfloat4 sum = srcGI[dtid]; +#ifdef TEMPORAL_DENOISER + lpfloat4 fsum = accumFrames; +#endif + float4 wsum = 1; + for (uint i = 0; i < numSamples; i++) { + float w = g_Poisson8[i].z; + + float2 pxOffset = radius * g_Poisson8[i].xy; + float2 pxSample = dtid + .5 + pxOffset; + float2 uvSample = pxSample * RcpOutFrameDim; + float2 screenPosSample = ConvertToStereoUV(uvSample, eyeIndex); + + if (any(screenPosSample < 0) || any(screenPosSample > 1)) + continue; + + float depthSample = srcDepth.SampleLevel(samplerLinearClamp, uvSample * srcScale, 0); + float3 posSample = ScreenToViewPosition(screenPosSample, depthSample, eyeIndex); + + float3 normalSample = DecodeNormal(srcNormal.SampleLevel(samplerLinearClamp, uvSample * srcScale, 0).xy); + + // geometry weight + w *= saturate(1 - abs(dot(normal, posSample - pos)) * DistanceNormalisation); + // normal weight + w *= 1 - saturate(acosFast4(saturate(dot(normalSample, normal))) / fsl_HALF_PI * 2); + + lpfloat4 gi = srcGI.SampleLevel(samplerLinearClamp, uvSample * outScale, 0); + + sum += gi * w; +#ifdef TEMPORAL_DENOISER + fsum += srcAccumFrames.SampleLevel(samplerLinearClamp, uvSample * outScale, 0); +#endif + wsum += w; + } + + outGI[dtid] = sum / wsum; +#ifdef TEMPORAL_DENOISER + outAccumFrames[dtid] = fsum / wsum; +#endif +} \ No newline at end of file diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/common.hlsli b/features/Screen Space GI/Shaders/ScreenSpaceGI/common.hlsli index 95c5dea83..042b93b6f 100644 --- a/features/Screen Space GI/Shaders/ScreenSpaceGI/common.hlsli +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/common.hlsli @@ -53,10 +53,14 @@ cbuffer SSGICB : register(b1) float4x4 PrevInvViewMat[2]; float4 NDCToViewMul; float4 NDCToViewAdd; - float4 NDCToViewMul_x_PixelSize; - float2 FrameDim; - float2 RcpFrameDim; + float2 TexDim; + float2 RcpTexDim; + float2 SrcFrameDim; + float2 RcpSrcFrameDim; + float2 OutFrameDim; + float2 RcpOutFrameDim; + uint FrameIndex; uint NumSlices; @@ -79,9 +83,12 @@ cbuffer SSGICB : register(b1) float GIStrength; float DepthDisocclusion; + float NormalDisocclusion; uint MaxAccumFrames; - float pad; + float BlurRadius; + float DistanceNormalisation; + float2 pad; }; SamplerState samplerPointClamp : register(s0); @@ -89,14 +96,16 @@ SamplerState samplerLinearClamp : register(s1); /////////////////////////////////////////////////////////////////////////////// +// screenPos - normalised position in FrameDim, one eye only +// uv - normalised position in FrameDim, both eye +// texCoord - texture coordinate + #ifdef HALF_RES -const static float res_scale = .5; # define READ_DEPTH(tex, px) tex.Load(int3(px, 1)) -# define FULLRES_LOAD(tex, px, uv, samp) tex.SampleLevel(samp, uv, 0) +# define FULLRES_LOAD(tex, px, texCoord, samp) tex.SampleLevel(samp, texCoord, 0) #else -const static float res_scale = 1.; # define READ_DEPTH(tex, px) tex[px] -# define FULLRES_LOAD(tex, px, uv, samp) tex[px] +# define FULLRES_LOAD(tex, px, texCoord, samp) tex[px] #endif #ifdef VR diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/gi.cs.hlsl b/features/Screen Space GI/Shaders/ScreenSpaceGI/gi.cs.hlsl index e76b0ba2c..097c906c3 100644 --- a/features/Screen Space GI/Shaders/ScreenSpaceGI/gi.cs.hlsl +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/gi.cs.hlsl @@ -20,9 +20,6 @@ // Screen Space Indirect Lighting with Visibility Bitmask // https://arxiv.org/abs/2301.11376 // -// HBIL -// https://github.com/Patapom/GodComplex/blob/master/Tests/TestHBIL/2018%20Mayaux%20-%20Horizon-Based%20Indirect%20Lighting%20(HBIL).pdf -// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "../Common/FastMath.hlsli" @@ -44,25 +41,27 @@ Texture2D srcWorkingDepth : register(t0); Texture2D srcNormal : register(t1); Texture2D srcRadiance : register(t2); // maybe half-res Texture2D srcHilbertLUT : register(t3); -Texture2D srcAccumFrames : register(t4); // maybe half-res -Texture2D srcPrevGI : register(t5); // maybe half-res +Texture2D srcAccumFrames : register(t4); // maybe half-res +Texture2D srcPrevGI : register(t5); // maybe half-res RWTexture2D outGI : register(u0); RWTexture2D outBentNormal : register(u1); -RWTexture2D outPrevDepth : register(u2); +RWTexture2D outPrevGeo : register(u2); lpfloat GetDepthFade(lpfloat depth) { return (lpfloat)saturate((depth - DepthFadeRange.x) * DepthFadeScaleConst); } +// Engine-specific screen & temporal noise loader lpfloat2 SpatioTemporalNoise(uint2 pixCoord, uint temporalIndex) // without TAA, temporalIndex is always 0 { float2 noise; uint index = srcHilbertLUT.Load(uint3(pixCoord % 64, 0)).x; index += 288 * (temporalIndex % 64); // why 288? tried out a few and that's the best so far (with XE_HILBERT_LEVEL 6U) - but there's probably better :) // R2 sequence - see http://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/ - return lpfloat2(frac(0.5 + index * float2(0.75487766624669276005, 0.5698402909980532659114))); + // https://www.shadertoy.com/view/mts3zN + return lpfloat2(frac(0.5 + index * float2(0.245122333753, 0.430159709002))); } // HBIL pp.29 @@ -80,6 +79,9 @@ void CalculateGI( uint2 dtid, float2 uv, float viewspaceZ, lpfloat3 viewspaceNormal, out lpfloat4 o_currGIAO, out lpfloat3 o_bentNormal) { + const float srcScale = SrcFrameDim * RcpTexDim; + const float outScale = OutFrameDim * RcpTexDim; + uint eyeIndex = GET_EYE_IDX(uv); float2 normalizedScreenPos = ConvertToStereoUV(uv, eyeIndex); @@ -96,7 +98,7 @@ void CalculateGI( // if the offset is under approx pixel size (pixelTooCloseThreshold), push it out to the minimum distance const lpfloat pixelTooCloseThreshold = 1.3; // approx viewspace pixel size at pixCoord; approximation of NDCToViewspace( uv.xy + ViewportSize.xy, pixCenterPos.z ).xy - pixCenterPos.xy; - const float2 pixelDirRBViewspaceSizeAtCenterZ = viewspaceZ.xx * (eyeIndex == 0 ? NDCToViewMul_x_PixelSize.xy : NDCToViewMul_x_PixelSize.zw); + const float2 pixelDirRBViewspaceSizeAtCenterZ = viewspaceZ.xx * (eyeIndex == 0 ? NDCToViewMul.xy : NDCToViewMul.zw) * RcpOutFrameDim; lpfloat screenspaceRadius = (lpfloat)EffectRadius / (lpfloat)pixelDirRBViewspaceSizeAtCenterZ.x; // this is the min distance to start sampling from to avoid sampling from the center pixel (no useful data obtained from sampling center pixel) @@ -122,11 +124,8 @@ void CalculateGI( lpfloat3 directionVec = 0; sincos(phi, directionVec.y, directionVec.x); - // convert to screen units for later use - lpfloat2 omega = lpfloat2(directionVec.x, -directionVec.y) * screenspaceRadius * RcpFrameDim; -#ifdef VR - omega.x *= 2; -#endif + // convert to px units for later use + lpfloat2 omega = lpfloat2(directionVec.x, -directionVec.y) * screenspaceRadius; const lpfloat3 orthoDirectionVec = directionVec - (dot(directionVec, viewVec) * viewVec); const lpfloat3 axisVec = normalize(cross(orthoDirectionVec, viewVec)); @@ -164,11 +163,12 @@ void CalculateGI( s *= s; // default 2 is fine s += minS; // avoid sampling center pixel - lpfloat2 sampleOffset = s * omega; // no pixel alignment from original xegtao + lpfloat2 sampleOffset = s * omega; - float2 sampleScreenPos = normalizedScreenPos + sampleOffset * sideSign; + float2 samplePxCoord = dtid + .5 + sampleOffset * sideSign; + float2 sampleUV = samplePxCoord * RcpOutFrameDim; + float2 sampleScreenPos = ConvertToStereoUV(sampleUV, eyeIndex); [branch] if (any(sampleScreenPos > 1.0) || any(sampleScreenPos < 0.0)) break; - float2 sampleUV = ConvertFromStereoUV(sampleScreenPos, eyeIndex); lpfloat sampleOffsetLength = length(sampleOffset); lpfloat mipLevel = (lpfloat)clamp(log2(sampleOffsetLength) - DepthMIPSamplingOffset, 0, 5); @@ -176,7 +176,7 @@ void CalculateGI( mipLevel = max(mipLevel, 1); #endif - float SZ = srcWorkingDepth.SampleLevel(samplerPointClamp, sampleUV, mipLevel); + float SZ = srcWorkingDepth.SampleLevel(samplerPointClamp, sampleUV * srcScale, mipLevel); [branch] if (SZ > DepthFadeRange.y) continue; float3 samplePos = ScreenToViewPosition(sampleScreenPos, SZ, eyeIndex); @@ -222,13 +222,13 @@ void CalculateGI( // IL lpfloat frontBackMult = 1.f; # ifdef BACKFACE - if (dot(DecodeNormal(srcNormal.SampleLevel(samplerPointClamp, sampleUV, 0).xy), sampleHorizonVec) > 0) // backface + if (dot(DecodeNormal(srcNormal.SampleLevel(samplerPointClamp, sampleUV * srcScale, 0).xy), sampleHorizonVec) > 0) // backface frontBackMult = BackfaceStrength; # endif if (frontBackMult > 0.f) { # ifdef BITMASK - lpfloat3 sampleRadiance = srcRadiance.SampleLevel(samplerPointClamp, sampleUV * res_scale, mipLevel).rgb * frontBackMult * giBoost; + lpfloat3 sampleRadiance = srcRadiance.SampleLevel(samplerPointClamp, sampleUV * outScale, mipLevel).rgb * frontBackMult * giBoost; sampleRadiance *= countbits(maskedBits & ~bitmask) * (lpfloat)0.03125; // 1/32 sampleRadiance *= dot(viewspaceNormal, sampleHorizonVec); @@ -237,7 +237,7 @@ void CalculateGI( radiance += sampleRadiance; # else lpfloat3 newSampleRadiance = 0; - newSampleRadiance = srcRadiance.SampleLevel(samplerPointClamp, sampleUV * res_scale, mipLevel).rgb * frontBackMult * giBoost; + newSampleRadiance = srcRadiance.SampleLevel(samplerPointClamp, sampleUV * outScale, mipLevel).rgb * frontBackMult * giBoost; lpfloat anglePrev = n + sideSign * HALF_PI - FastACos(horizonCos); // lpfloat version is closest acos lpfloat angleCurr = n + sideSign * HALF_PI - FastACos(shc); @@ -341,15 +341,20 @@ void CalculateGI( [numthreads(8, 8, 1)] void main(const uint2 dtid : SV_DispatchThreadID) { - float2 uv = (dtid + .5f) * RcpFrameDim; + const float srcScale = SrcFrameDim * RcpTexDim; + const float outScale = OutFrameDim * RcpTexDim; - float viewspaceZ = READ_DEPTH(srcWorkingDepth, dtid); + float2 uv = (dtid + .5f) * RcpOutFrameDim; + uint eyeIndex = GET_EYE_IDX(uv); - outPrevDepth[dtid] = viewspaceZ; + float viewspaceZ = READ_DEPTH(srcWorkingDepth, dtid); - lpfloat2 normalSample = FULLRES_LOAD(srcNormal, dtid, uv, samplerLinearClamp).xy; + lpfloat2 normalSample = FULLRES_LOAD(srcNormal, dtid, uv * srcScale, samplerLinearClamp).xy; lpfloat3 viewspaceNormal = (lpfloat3)DecodeNormal(normalSample); + half2 encodedWorldNormal = EncodeNormal(ViewToWorldVector(viewspaceNormal, InvViewMatrix[eyeIndex])); + outPrevGeo[dtid] = half3(viewspaceZ, encodedWorldNormal); + // Move center pixel slightly towards camera to avoid imprecision artifacts due to depth buffer imprecision; offset depends on depth texture format used #if USE_HALF_FLOAT_PRECISION == 1 viewspaceZ *= 0.99920h; // this is good for FP16 depth buffer @@ -371,9 +376,9 @@ void CalculateGI( #ifdef TEMPORAL_DENOISER if (viewspaceZ < DepthFadeRange.y) { lpfloat4 prevGIAO = srcPrevGI[dtid]; - uint accumFrames = srcAccumFrames[dtid]; + uint accumFrames = srcAccumFrames[dtid] * 255; - currGIAO = lerp(prevGIAO, currGIAO, fastRcpNR0(accumFrames)); + currGIAO = lerp(prevGIAO, currGIAO, rcp(accumFrames)); } #endif diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/prefilterDepths.cs.hlsl b/features/Screen Space GI/Shaders/ScreenSpaceGI/prefilterDepths.cs.hlsl index 930d33884..d6668f525 100644 --- a/features/Screen Space GI/Shaders/ScreenSpaceGI/prefilterDepths.cs.hlsl +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/prefilterDepths.cs.hlsl @@ -60,13 +60,15 @@ groupshared lpfloat g_scratchDepths[8][8]; [numthreads(8, 8, 1)] void main(uint2 dispatchThreadID : SV_DispatchThreadID, uint2 groupThreadID : SV_GroupThreadID) { + const float srcScale = SrcFrameDim * RcpTexDim; + const float outScale = OutFrameDim * RcpTexDim; + // MIP 0 const uint2 baseCoord = dispatchThreadID; const uint2 pixCoord = baseCoord * 2; - const float2 uv = (pixCoord + .5) * RcpFrameDim * res_scale; - const uint eyeIndex = GET_EYE_IDX(uv); + const float2 uv = (pixCoord + .5) * RcpSrcFrameDim; - float4 depths4 = srcNDCDepth.GatherRed(samplerPointClamp, uv, int2(1, 1)); + float4 depths4 = srcNDCDepth.GatherRed(samplerPointClamp, uv * srcScale, int2(1, 1)); lpfloat depth0 = ClampDepth(ScreenToViewDepth(depths4.w)); lpfloat depth1 = ClampDepth(ScreenToViewDepth(depths4.z)); lpfloat depth2 = ClampDepth(ScreenToViewDepth(depths4.x)); diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/radianceDisocc.cs.hlsl b/features/Screen Space GI/Shaders/ScreenSpaceGI/radianceDisocc.cs.hlsl index a837d3ad9..41a6da867 100644 --- a/features/Screen Space GI/Shaders/ScreenSpaceGI/radianceDisocc.cs.hlsl +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/radianceDisocc.cs.hlsl @@ -6,67 +6,123 @@ Texture2D srcDiffuse : register(t0); Texture2D srcPrevGI : register(t1); // maybe half-res Texture2D srcCurrDepth : register(t2); Texture2D srcCurrNormal : register(t3); -Texture2D srcPrevDepth : register(t4); // maybe half-res +Texture2D srcPrevGeo : register(t4); // maybe half-res Texture2D srcMotionVec : register(t5); -Texture2D srcPrevGIAlbedo : register(t6); +Texture2D srcPrevGIAlbedo : register(t6); // maybe half-res +Texture2D srcAccumFrames : register(t7); // maybe half-res RWTexture2D outRadianceDisocc : register(u0); -RWTexture2D outAccumFrames : register(u1); +RWTexture2D outAccumFrames : register(u1); RWTexture2D outRemappedPrevGI : register(u2); #if (defined(GI) && defined(GI_BOUNCE)) || defined(TEMPORAL_DENOISER) # define REPROJECTION #endif +void readHistory( + uint eyeIndex, float3 curr_pos, float3 curr_normal, int2 pixCoord, float bilinear_weight, + inout half4 prev_gi, inout half4 prev_gi_albedo, inout float accum_frames, inout float wsum) +{ + const float2 uv = (pixCoord + .5) * RcpOutFrameDim; + const float2 screen_pos = ConvertToStereoUV(uv, eyeIndex); + if (any(screen_pos < 0) || any(screen_pos > 1)) + return; + + const half3 prev_geo = srcPrevGeo[pixCoord]; + const float prev_depth = prev_geo.x; + const float3 prev_normal = DecodeNormal(prev_geo.yz); // prev normal is already world + float3 prev_pos = ScreenToViewPosition(screen_pos, prev_depth, eyeIndex); + prev_pos = ViewToWorldPosition(prev_pos, PrevInvViewMat[eyeIndex]); + + float3 delta_pos = curr_pos - prev_pos; + float normal_prod = dot(curr_normal, prev_normal); + + bool depth_pass = dot(delta_pos, delta_pos) < DepthDisocclusion * DepthDisocclusion; + bool normal_pass = normal_prod * normal_prod > NormalDisocclusion; + if (depth_pass && normal_pass) { +#if defined(GI) && defined(GI_BOUNCE) + prev_gi_albedo += srcPrevGIAlbedo[pixCoord] * bilinear_weight; +#endif +#ifdef TEMPORAL_DENOISER + prev_gi += srcPrevGI[pixCoord] * bilinear_weight; + accum_frames += srcAccumFrames[pixCoord] * bilinear_weight; +#endif + wsum += bilinear_weight; + } +}; + [numthreads(8, 8, 1)] void main(const uint2 pixCoord : SV_DispatchThreadID) { - const float2 uv = (pixCoord + .5) * RcpFrameDim; + const float srcScale = SrcFrameDim * RcpTexDim; + const float outScale = OutFrameDim * RcpTexDim; + + const float2 uv = (pixCoord + .5) * RcpOutFrameDim; uint eyeIndex = GET_EYE_IDX(uv); const float2 screen_pos = ConvertToStereoUV(uv, eyeIndex); float2 prev_uv = uv; #ifdef REPROJECTION - prev_uv += FULLRES_LOAD(srcMotionVec, pixCoord, uv, samplerLinearClamp); + prev_uv += FULLRES_LOAD(srcMotionVec, pixCoord, uv * srcScale, samplerLinearClamp).xy; #endif float2 prev_screen_pos = ConvertToStereoUV(prev_uv, eyeIndex); - const float curr_depth = READ_DEPTH(srcCurrDepth, pixCoord); - - bool valid_history = false; + half4 prev_gi_albedo = 0; + half4 prev_gi = 0; + float accum_frames = 0; + float wsum = 0; + const float curr_depth = READ_DEPTH(srcCurrDepth, pixCoord); #ifdef REPROJECTION if ((curr_depth <= DepthFadeRange.y) && !(any(prev_screen_pos < 0) || any(prev_screen_pos > 1))) { + float3 curr_normal = DecodeNormal(FULLRES_LOAD(srcCurrNormal, pixCoord, uv * srcScale, samplerLinearClamp).xy); + curr_normal = ViewToWorldVector(curr_normal, InvViewMatrix[eyeIndex]); float3 curr_pos = ScreenToViewPosition(screen_pos, curr_depth, eyeIndex); curr_pos = ViewToWorldPosition(curr_pos, InvViewMatrix[eyeIndex]); - const float prev_depth = srcPrevDepth.SampleLevel(samplerPointClamp, prev_uv * res_scale, 0); - float3 prev_pos = ScreenToViewPosition(prev_screen_pos, prev_depth, eyeIndex); - prev_pos = ViewToWorldPosition(prev_pos, PrevInvViewMat[eyeIndex]); - - float3 delta_pos = curr_pos - prev_pos; - bool depth_pass = dot(delta_pos, delta_pos) < DepthDisocclusion * DepthDisocclusion; - valid_history = depth_pass; - } -#endif - - half4 prev_gi_albedo = 0; - half4 prev_gi = 0; + float2 prev_px_coord = prev_uv * OutFrameDim; + int2 prev_px_lu = floor(prev_px_coord - 0.5); + float2 bilinear_weights = prev_px_coord - 0.5 - prev_px_lu; + { + int2 px = prev_px_lu; + float w = (1 - bilinear_weights.x) * (1 - bilinear_weights.y); + readHistory(eyeIndex, curr_pos, curr_normal, px, w, + prev_gi, prev_gi_albedo, accum_frames, wsum); + } + { + int2 px = prev_px_lu + uint2(1, 0); + float w = bilinear_weights.x * (1 - bilinear_weights.y); + readHistory(eyeIndex, curr_pos, curr_normal, px, w, + prev_gi, prev_gi_albedo, accum_frames, wsum); + } + { + int2 px = prev_px_lu + uint2(0, 1); + float w = (1 - bilinear_weights.x) * bilinear_weights.y; + readHistory(eyeIndex, curr_pos, curr_normal, px, w, + prev_gi, prev_gi_albedo, accum_frames, wsum); + } + { + int2 px = prev_px_lu + uint2(1, 1); + float w = bilinear_weights.x * bilinear_weights.y; + readHistory(eyeIndex, curr_pos, curr_normal, px, w, + prev_gi, prev_gi_albedo, accum_frames, wsum); + } -#ifdef REPROJECTION - [branch] if (valid_history) - { -# if defined(GI) && defined(GI_BOUNCE) - prev_gi_albedo = srcPrevGIAlbedo.SampleLevel(samplerLinearClamp, prev_uv, 0); -# endif + if (wsum > 1e-2) { + float rcpWsum = rcp(wsum + 1e-2); # ifdef TEMPORAL_DENOISER - prev_gi = srcPrevGI.SampleLevel(samplerLinearClamp, prev_uv * res_scale, 0); + prev_gi *= rcpWsum; + accum_frames *= rcpWsum; # endif +# if defined(GI) && defined(GI_BOUNCE) + prev_gi_albedo *= rcpWsum; +# endif + } } #endif half3 radiance = 0; #ifdef GI - radiance = FULLRES_LOAD(srcDiffuse, pixCoord, uv, samplerLinearClamp); + radiance = FULLRES_LOAD(srcDiffuse, pixCoord, uv * srcScale, samplerLinearClamp).rgb; # ifdef GI_BOUNCE radiance += prev_gi_albedo.rgb * GIBounceFade; # endif @@ -74,12 +130,8 @@ RWTexture2D outRemappedPrevGI : register(u2); #endif #ifdef TEMPORAL_DENOISER - uint accum_frames = 0; - [branch] if (valid_history) - accum_frames = outAccumFrames[pixCoord]; - accum_frames = min(accum_frames + 1, MaxAccumFrames); - - outAccumFrames[pixCoord] = accum_frames; + accum_frames = min(accum_frames * 255 + 1, MaxAccumFrames); + outAccumFrames[pixCoord] = accum_frames / 255.0; outRemappedPrevGI[pixCoord] = prev_gi; #endif } \ No newline at end of file diff --git a/features/Screen Space GI/Shaders/ScreenSpaceGI/upsample.cs.hlsl b/features/Screen Space GI/Shaders/ScreenSpaceGI/upsample.cs.hlsl index f483f6338..86a5f6321 100644 --- a/features/Screen Space GI/Shaders/ScreenSpaceGI/upsample.cs.hlsl +++ b/features/Screen Space GI/Shaders/ScreenSpaceGI/upsample.cs.hlsl @@ -1,4 +1,5 @@ // depth-aware upsampling: https://gist.github.com/pixelmager/a4364ea18305ed5ca707d89ddc5f8743 +// blue noise texture from http://momentsingraphics.de/BlueNoise.html #include "../Common/FastMath.hlsli" #include "common.hlsli" @@ -51,7 +52,7 @@ RWTexture2D outGI : register(u0); } else { - atten = srcGI.SampleLevel(samplerLinearClamp, (dtid + .5) * RcpFrameDim * .25, 0); + atten = srcGI.SampleLevel(samplerLinearClamp, (dtid + .5) * RcpSrcFrameDim * OutFrameDim * RcpTexDim, 0); } outGI[dtid] = atten; diff --git a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/NormalMappingShadowsCS.hlsl b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/NormalMappingShadowsCS.hlsl index e88e4239c..18ede2b02 100644 --- a/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/NormalMappingShadowsCS.hlsl +++ b/features/Screen-Space Shadows/Shaders/ScreenSpaceShadows/NormalMappingShadowsCS.hlsl @@ -39,10 +39,10 @@ half2 ViewToUV(half3 position, bool is_position, uint a_eyeIndex) return (uv.xy / uv.w) * half2(0.5f, -0.5f) + 0.5f; } -[numthreads(32, 32, 1)] void main(uint3 globalId - : SV_DispatchThreadID, uint3 localId - : SV_GroupThreadID, uint3 groupId - : SV_GroupID) { +[numthreads(8, 8, 1)] void main(uint3 globalId + : SV_DispatchThreadID, uint3 localId + : SV_GroupThreadID, uint3 groupId + : SV_GroupID) { half2 uv = half2(globalId.xy + 0.5) * RcpBufferDim; half3 normalVS = DecodeNormal(NormalRoughnessTexture[globalId.xy].xy); diff --git a/features/Skylighting/Shaders/Features/Skylighting.ini b/features/Skylighting/Shaders/Features/Skylighting.ini new file mode 100644 index 000000000..19f01444d --- /dev/null +++ b/features/Skylighting/Shaders/Features/Skylighting.ini @@ -0,0 +1,2 @@ +[Info] +Version = 1-0-0 \ No newline at end of file diff --git a/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli new file mode 100644 index 000000000..488f47132 --- /dev/null +++ b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli @@ -0,0 +1,156 @@ +struct PerGeometry +{ + float4 VPOSOffset; + float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam; + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + float4x3 FocusShadowMapProj[4]; + float4x3 ShadowMapProj[4]; + float4x4 CameraViewProjInverse; +}; + +Texture2DArray TexShadowMapSampler : register(t80); +StructuredBuffer perShadow : register(t81); +Texture2D SkylightingTexture : register(t82); + +#if defined(WATER) || defined(EFFECT) + +float3 GetShadow(float3 positionWS) +{ + PerGeometry sD = perShadow[0]; + sD.EndSplitDistances.x = GetScreenDepth(sD.EndSplitDistances.x); + sD.EndSplitDistances.y = GetScreenDepth(sD.EndSplitDistances.y); + sD.EndSplitDistances.z = GetScreenDepth(sD.EndSplitDistances.z); + sD.EndSplitDistances.w = GetScreenDepth(sD.EndSplitDistances.w); + + float shadowMapDepth = length(positionWS.xyz); + + half cascadeIndex = 0; + half4x3 lightProjectionMatrix = sD.ShadowMapProj[0]; + half shadowMapThreshold = sD.AlphaTestRef.y; + + [flatten] if (2.5 < sD.EndSplitDistances.w && sD.EndSplitDistances.y < shadowMapDepth) + { + lightProjectionMatrix = sD.ShadowMapProj[2]; + shadowMapThreshold = sD.AlphaTestRef.z; + cascadeIndex = 2; + } + else if (sD.EndSplitDistances.x < shadowMapDepth) + { + lightProjectionMatrix = sD.ShadowMapProj[1]; + shadowMapThreshold = sD.AlphaTestRef.z; + cascadeIndex = 1; + } + + half3 positionLS = mul(transpose(lightProjectionMatrix), half4(positionWS.xyz, 1)).xyz; + float deltaZ = positionLS.z - shadowMapThreshold; + + float4 depths = TexShadowMapSampler.GatherRed(LinearSampler, half3(positionLS.xy, cascadeIndex), 0); + + float shadow = dot(depths > deltaZ, 0.25); + + return shadow; +} + +float phaseHenyeyGreenstein(float cosTheta, float g) +{ + static const float scale = .25 / 3.1415926535; + const float g2 = g * g; + + float num = (1.0 - g2); + float denom = pow(abs(1.0 + g2 - 2.0 * g * cosTheta), 1.5); + + return scale * num / denom; +} + +void GetVL(float3 startPosWS, float3 endPosWS, float2 screenPosition, out float3 scatter, out float3 transmittance) +{ + const static uint nSteps = 16; + const static float step = rcp(nSteps); + + // https://s.campbellsci.com/documents/es/technical-papers/obs_light_absorption.pdf + // clear water: 0.002 cm^-1 * 1.428 cm/game unit + float3 hue = normalize(rcp(ShallowColor)); + const float3 scatterCoeff = hue * 0.002 * 2 * 1.428; + const float3 absorpCoeff = hue * 0.0002 * 2 * 1.428; + const float3 extinction = scatterCoeff + absorpCoeff; + + float3 worldDir = endPosWS - startPosWS; + float dist = length(worldDir); + worldDir = worldDir / dist; + // float phase = .25 / 3.1415926535; + float phase = phaseHenyeyGreenstein(dot(SunDir.xyz, worldDir), 0.5); + float distRatio = abs(SunDir.z / worldDir.z); + + uint noiseIdx = dot(screenPosition, float2(1, lightingData[0].BufferDim.x)) + lightingData[0].Timer * 100; + float noise = frac(0.5 + noiseIdx * 0.38196601125); + + const float cutoffTransmittance = 1e-2; // don't go deeper than this +# if defined(UNDERWATER) + const float cutoffDist = -log(cutoffTransmittance) / max(extinction.x, max(extinction.y, extinction.z)); +# else + const float cutoffDist = -log(cutoffTransmittance) / ((1 + distRatio) * max(extinction.x, max(extinction.y, extinction.z))); +# endif + + float marchDist = min(dist, cutoffDist); + float sunMarchDist = marchDist * distRatio; + + PerGeometry sD = perShadow[0]; + sD.EndSplitDistances.x = GetScreenDepth(sD.EndSplitDistances.x); + sD.EndSplitDistances.y = GetScreenDepth(sD.EndSplitDistances.y); + sD.EndSplitDistances.z = GetScreenDepth(sD.EndSplitDistances.z); + sD.EndSplitDistances.w = GetScreenDepth(sD.EndSplitDistances.w); + + scatter = 0; + transmittance = 1; + for (uint i = 0; i < nSteps; ++i) { + float t = saturate((i + noise) * step); + + float sampleTransmittance = exp(-step * marchDist * extinction); + transmittance *= sampleTransmittance; + + // scattering + float shadow = 0; + { + float3 samplePositionWS = startPosWS + worldDir * t * marchDist; + float shadowMapDepth = length(samplePositionWS.xyz); + + half cascadeIndex = 0; + half4x3 lightProjectionMatrix = sD.ShadowMapProj[0]; + half shadowMapThreshold = sD.AlphaTestRef.y; + + [flatten] if (2.5 < sD.EndSplitDistances.w && sD.EndSplitDistances.y < shadowMapDepth) + { + lightProjectionMatrix = sD.ShadowMapProj[2]; + shadowMapThreshold = sD.AlphaTestRef.z; + cascadeIndex = 2; + } + else if (sD.EndSplitDistances.x < shadowMapDepth) + { + lightProjectionMatrix = sD.ShadowMapProj[1]; + shadowMapThreshold = sD.AlphaTestRef.z; + cascadeIndex = 1; + } + + half3 samplePositionLS = mul(transpose(lightProjectionMatrix), half4(samplePositionWS.xyz, 1)).xyz; + float deltaZ = samplePositionLS.z - shadowMapThreshold; + + float4 depths = TexShadowMapSampler.GatherRed(LinearSampler, half3(samplePositionLS.xy, cascadeIndex), 0); + + shadow = dot(depths > deltaZ, 0.25); + } + + float sunTransmittance = exp(-sunMarchDist * t * extinction) * shadow; // assuming water surface is always level + float inScatter = scatterCoeff * phase * sunTransmittance; + scatter += inScatter * (1 - sampleTransmittance) / extinction * transmittance; + } + + scatter *= SunColor * 3; + transmittance = exp(-dist * (1 + distRatio) * extinction); +} +#endif \ No newline at end of file diff --git a/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl b/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl new file mode 100644 index 000000000..4ac53737e --- /dev/null +++ b/features/Skylighting/Shaders/Skylighting/SkylightingCS.hlsl @@ -0,0 +1,361 @@ +#include "../Common/VR.hlsli" + +Texture2D DepthTexture : register(t0); + +struct PerGeometry +{ + float4 VPOSOffset; + float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam; + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + float4x3 FocusShadowMapProj[4]; +#if !defined(VR) + float4x3 ShadowMapProj[1][3]; + float4x4 CameraViewProjInverse[1]; +#else + float4x3 ShadowMapProj[2][3]; + float4x4 CameraViewProjInverse[2]; +#endif // VR +}; + +Texture2DArray TexShadowMapSampler : register(t1); +StructuredBuffer perShadow : register(t2); +Texture2DArray BlueNoise : register(t3); +Texture2D OcclusionMapSampler : register(t4); +Texture2D OcclusionMapTranslucentSampler : register(t5); +Texture2D NormalRoughnessTexture : register(t6); + +RWTexture2D SkylightingTextureRW : register(u0); + +cbuffer PerFrame : register(b1) +{ + row_major float4x4 OcclusionViewProj; + float4 ShadowDirection; + float4 BufferDim; + float4 DynamicRes; + float4 CameraData; + uint FrameCount; + uint pad0[3]; +}; + +SamplerState LinearSampler : register(s0); +SamplerComparisonState ShadowSamplerPCF : register(s1); + +half GetBlueNoise(half2 uv) +{ + return BlueNoise[uint3(uv % 128, FrameCount % 64)]; +} + +half GetScreenDepth(half depth) +{ + return (CameraData.w / (-depth * CameraData.z + CameraData.x)); +} + +cbuffer PerFrameDeferredShared : register(b0) +{ + float4 CamPosAdjust[2]; + float4 DirLightDirectionVS[2]; + float4 DirLightColor; + float4 CameraData2; + float2 BufferDim2; + float2 RcpBufferDim; + float4x4 ViewMatrix[2]; + float4x4 ProjMatrix[2]; + float4x4 ViewProjMatrix[2]; + float4x4 InvViewMatrix[2]; + float4x4 InvProjMatrix[2]; + float4x4 InvViewProjMatrix[2]; + row_major float3x4 DirectionalAmbient; + uint FrameCount2; + uint pad02[3]; +}; + +half3 DecodeNormal(half2 f) +{ + f = f * 2.0 - 1.0; + // https://twitter.com/Stubbesaurus/status/937994790553227264 + half3 n = half3(f.x, f.y, 1.0 - abs(f.x) - abs(f.y)); + half t = saturate(-n.z); + n.xy += n.xy >= 0.0 ? -t : t; + return -normalize(n); +} + +//#define SHADOWMAP +#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 * DynamicRes.zw; + uint eyeIndex = GetEyeIndexFromTexCoord(uv); + + half3 normalGlossiness = NormalRoughnessTexture[globalId.xy]; + half3 normalVS = DecodeNormal(normalGlossiness.xy); + half3 normalWS = normalize(mul(InvViewMatrix[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); + + PerGeometry sD = perShadow[0]; + + float4 positionMS = mul(sD.CameraViewProjInverse[eyeIndex], positionCS); + positionMS.xyz = positionMS.xyz / positionMS.w; + + float3 startPositionMS = positionMS; + + half noise = GetBlueNoise(globalId.xy) * 2.0 * PI; + + 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) + }; + + uint sampleCount = 16; + + half2 skylighting = 0; + + float occlusionThreshold = mul(OcclusionViewProj, float4(positionMS.xyz, 1)).z; + + half3 V = normalize(positionMS.xyz); + half3 R = reflect(V, normalWS); + + bool fadeOut = length(startPositionMS) > 256; + + half2 weights = 0.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); + + positionMS.xy = startPositionMS + offset * 128; + + half2 occlusionPosition = mul((float2x4)OcclusionViewProj, float4(positionMS.xyz, 1)); + occlusionPosition.y = -occlusionPosition.y; + half2 occlusionUV = occlusionPosition.xy * 0.5 + 0.5; + + half3 offsetDirection = normalize(half3(offset.xy, 0)); + + if ((occlusionUV.x == saturate(occlusionUV.x) && occlusionUV.y == saturate(occlusionUV.y)) || !fadeOut) { + half shadowMapValues = OcclusionMapSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius)); + half shadowMapTranslucentValues = OcclusionMapTranslucentSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius)); + + 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); + + half2 contributions = half2(dot(normalWS.xyz, offsetDirection.xyz) * 0.5 + 0.5, ggx); + + skylighting += shadowMapValues * contributions; + weights += contributions; + } else { + skylighting++; + weights++; + } + } + + if (weights.x > 0.0) + skylighting.x /= weights.x; + else + skylighting.x = 1.0; + + if (weights.y > 0.0) + skylighting.y /= weights.y; + else + skylighting.y = 1.0; + + weights = 0.0; + half2 skylightingTranslucent = 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); + + positionMS.xy = startPositionMS + offset * 256; + + half2 occlusionPosition = mul((float2x4)OcclusionViewProj, float4(positionMS.xyz, 1)); + occlusionPosition.y = -occlusionPosition.y; + half2 occlusionUV = occlusionPosition.xy * 0.5 + 0.5; + + half3 offsetDirection = normalize(half3(offset.xy, 0)); + + if ((occlusionUV.x == saturate(occlusionUV.x) && occlusionUV.y == saturate(occlusionUV.y)) || !fadeOut) { + half shadowMapValues = OcclusionMapTranslucentSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius)); + half shadowMapTranslucentValues = OcclusionMapTranslucentSampler.SampleCmpLevelZero(ShadowSamplerPCF, occlusionUV, occlusionThreshold - (1e-2 * 0.05 * radius)); + + 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); + + half2 contributions = half2(dot(normalWS.xyz, offsetDirection.xyz) * 0.5 + 0.5, ggx); + + skylightingTranslucent += shadowMapValues * contributions; + weights += contributions; + } else { + skylightingTranslucent++; + weights++; + } + } + + if (weights.x > 0.0) + skylightingTranslucent.x /= weights.x; + else + skylightingTranslucent.x = 1.0; + + if (weights.y > 0.0) + skylightingTranslucent.y /= weights.y; + else + skylightingTranslucent.y = 1.0; + + skylighting = min(skylighting, lerp(skylightingTranslucent, 1.0, 0.0)); + + SkylightingTextureRW[globalId.xy] = saturate(skylighting); +} +#else +[numthreads(8, 8, 1)] void main(uint3 globalId + : SV_DispatchThreadID) { + float2 uv = float2(globalId.xy + 0.5) * BufferDim.zw * DynamicRes.zw; + uint eyeIndex = GetEyeIndexFromTexCoord(uv); + + half3 normalGlossiness = NormalRoughnessTexture[globalId.xy]; + half3 normalVS = DecodeNormal(normalGlossiness.xy); + half3 normalWS = normalize(mul(InvViewMatrix[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); + + PerGeometry sD = perShadow[0]; + + sD.EndSplitDistances.x = GetScreenDepth(sD.EndSplitDistances.x); + sD.EndSplitDistances.y = GetScreenDepth(sD.EndSplitDistances.y); + sD.EndSplitDistances.z = GetScreenDepth(sD.EndSplitDistances.z); + sD.EndSplitDistances.w = GetScreenDepth(sD.EndSplitDistances.w); + + float4 positionMS = mul(sD.CameraViewProjInverse[eyeIndex], positionCS); + positionMS.xyz = positionMS.xyz / positionMS.w; + + float3 startPositionMS = positionMS; + + half fadeFactor = pow(saturate(dot(positionMS.xyz, positionMS.xyz) / sD.ShadowLightParam.z), 8); + + half noise = GetBlueNoise(globalId.xy) * 2.0 * PI; + + 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) + }; + + uint sampleCount = 16; + + half2 skylighting = 0; + + half3 V = normalize(positionMS.xyz); + half3 R = reflect(V, normalWS); + + float2 weights = 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); + + positionMS.xy = startPositionMS + offset.xy * 128 + ShadowDirection.xy * 128; + + half3 offsetDirection = normalize(half3(offset.xy, 0)); + + float shadowMapDepth = length(positionMS.xyz); + + [flatten] if (sD.EndSplitDistances.z > shadowMapDepth) + { + 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.SampleCmpLevelZero(ShadowSamplerPCF, float3(positionLS.xy, cascadeIndex), positionLS.z - (1e-2 * 0.1 * radius)); + + 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); + + half2 contributions = half2(dot(normalWS.xyz, offsetDirection.xyz) * 0.5 + 0.5, ggx); + + skylighting += shadowMapValues * contributions; + weights += contributions; + } + } + + if (weights > 0.0) + skylighting /= weights; + else + skylighting = 1.0; + + SkylightingTextureRW[globalId.xy] = lerp(saturate(skylighting), 1.0, fadeFactor); +} +#endif \ No newline at end of file diff --git a/features/Skylighting/Shaders/Skylighting/bluenoise.dds b/features/Skylighting/Shaders/Skylighting/bluenoise.dds new file mode 100644 index 000000000..ce41c5100 Binary files /dev/null and b/features/Skylighting/Shaders/Skylighting/bluenoise.dds differ diff --git a/features/Terrain Occlusion/Shaders/TerrainOcclusion/Output.cs.hlsl b/features/Terrain Occlusion/Shaders/TerrainOcclusion/Output.cs.hlsl index 81c6026c8..2cfbd5809 100644 --- a/features/Terrain Occlusion/Shaders/TerrainOcclusion/Output.cs.hlsl +++ b/features/Terrain Occlusion/Shaders/TerrainOcclusion/Output.cs.hlsl @@ -14,13 +14,9 @@ SamplerState SamplerDefault; [numthreads(32, 32, 1)] void main(uint2 dtid : SV_DispatchThreadID) { float2 uv = (dtid + .5) * RcpBufferDim; -#ifdef VR - const uint eyeIndex = uv > .5; -#else - const uint eyeIndex = 0; -#endif + uint eyeIndex = GetEyeIndexFromTexCoord(uv); - float3 ndc = float3(ConvertToStereoUV(uv, eyeIndex), 1); + float3 ndc = float3(ConvertFromStereoUV(uv, eyeIndex), 1); ndc = ndc * 2 - 1; ndc.y = -ndc.y; ndc.z = TexDepth[dtid]; @@ -28,7 +24,7 @@ SamplerState SamplerDefault; float4 worldPos = mul(InvViewMatrix[eyeIndex], mul(InvProjMatrix[eyeIndex], float4(ndc, 1))); worldPos.xyz /= worldPos.w; float viewDistance = length(worldPos); - worldPos.xyz += CamPosAdjust[0].xyz; + worldPos.xyz += CamPosAdjust[eyeIndex].xyz; float terrainShadow = 1; float terrainAo = 1; diff --git a/package/Shaders/DeferredCompositeCS.hlsl b/package/Shaders/DeferredCompositeCS.hlsl index 7c7988341..d7ca46441 100644 --- a/package/Shaders/DeferredCompositeCS.hlsl +++ b/package/Shaders/DeferredCompositeCS.hlsl @@ -10,24 +10,55 @@ Texture2D NormalRoughnessTexture : register(t3); Texture2D ShadowMaskTexture : register(t4); Texture2D DepthTexture : register(t5); Texture2D MasksTexture : register(t6); -Texture2D GITexture : register(t7); +Texture2D Masks2Texture : register(t7); +Texture2D GITexture : register(t8); + +Texture2D SkylightingTexture : register(t10); RWTexture2D MainRW : register(u0); RWTexture2D NormalTAAMaskSpecularMaskRW : register(u1); +RWTexture2D SnowParametersRW : register(u2); + +TextureCube EnvTexture : register(t12); +TextureCube ReflectionTexture : register(t13); SamplerState LinearSampler : register(s0); +struct PerGeometry +{ + float4 VPOSOffset; + float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam; + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + float4x3 FocusShadowMapProj[4]; +#if !defined(VR) + float4x3 ShadowMapProj[1][3]; + float4x4 CameraViewProjInverse[1]; +#else + float4x3 ShadowMapProj[2][3]; + float4x4 CameraViewProjInverse[2]; +#endif // VR +}; + +Texture2DArray TexShadowMapSampler : register(t10); +StructuredBuffer perShadow : register(t11); + // # define DEBUG -half GetScreenDepth(half depth) +float GetScreenDepth(float depth) { return (CameraData.w / (-depth * CameraData.z + CameraData.x)); } -[numthreads(32, 32, 1)] void DirectionalPass(uint3 globalId - : SV_DispatchThreadID, uint3 localId - : SV_GroupThreadID, uint3 groupId - : SV_GroupID) { +[numthreads(8, 8, 1)] void DirectionalPass(uint3 globalId + : SV_DispatchThreadID, uint3 localId + : SV_GroupThreadID, uint3 groupId + : SV_GroupID) { half2 uv = half2(globalId.xy + 0.5) * RcpBufferDim.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); @@ -50,10 +81,10 @@ half GetScreenDepth(half depth) MainRW[globalId.xy] = half4(color.xyz, 1.0); }; -[numthreads(32, 32, 1)] void DirectionalShadowPass(uint3 globalId - : SV_DispatchThreadID, uint3 localId - : SV_GroupThreadID, uint3 groupId - : SV_GroupID) { +[numthreads(8, 8, 1)] void DirectionalShadowPass(uint3 globalId + : SV_DispatchThreadID, uint3 localId + : SV_GroupThreadID, uint3 groupId + : SV_GroupID) { half2 uv = half2(globalId.xy + 0.5) * RcpBufferDim.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); @@ -63,8 +94,6 @@ half GetScreenDepth(half depth) half rawDepth = DepthTexture[globalId.xy]; half depth = GetScreenDepth(rawDepth); - half weight = 1.0; - half NdotL = dot(normalVS, DirLightDirectionVS[eyeIndex].xyz); half shadow = 1.0; @@ -72,45 +101,68 @@ half GetScreenDepth(half depth) half3 masks = MasksTexture[globalId.xy]; if (NdotL > 0.0 || masks.z > 0.0) { - shadow = ShadowMaskTexture[globalId.xy]; - - if (shadow != 0) { - // Approximation of PCF in screen-space - for (int i = -1; i < 1; i++) { - for (int k = -1; k < 1; k++) { - if (i == 0 && k == 0) - continue; - float2 offset = float2(i, k) * RcpBufferDim.xy * 1.5; - float sampleDepth = GetScreenDepth(DepthTexture.SampleLevel(LinearSampler, uv + offset, 0)); - float attenuation = 1.0 - saturate(abs(sampleDepth - depth)); - shadow += ShadowMaskTexture.SampleLevel(LinearSampler, uv + offset, 0) * attenuation; - weight += attenuation; - } + shadow = 0.0; + half weight = 0.0; + + // Approximation of PCF in screen-space + for (half i = -1.5; i < 1.5; i++) { + for (half k = -1.5; k < 1.5; k++) { + half2 offset = half2(i, k) * RcpBufferDim.xy; + float sampleDepth = GetScreenDepth(DepthTexture.SampleLevel(LinearSampler, uv + offset, 0)); + half attenuation = 1.0 - saturate(abs(sampleDepth - depth) * 0.1); + shadow += ShadowMaskTexture.SampleLevel(LinearSampler, uv + offset, 0) * attenuation; + weight += attenuation; } + } + if (weight > 0.0) { shadow /= weight; + } else { + shadow = ShadowMaskTexture[globalId.xy]; } } half3 color = MainRW[globalId.xy].rgb; - color += albedo * lerp(max(0, NdotL), 1.0, masks.z) * DirLightColor.xyz * shadow; - MainRW[globalId.xy] = half4(color.xyz, 1.0); + half3 normalWS = normalize(mul(InvViewMatrix[eyeIndex], half4(normalVS, 0))); + half3 directionalAmbientColor = mul(DirectionalAmbient, half4(normalWS, 1.0)); + + float skylighting = SkylightingTexture[globalId.xy]; + skylighting *= saturate(dot(normalWS, float3(0, 0, 1)) * 0.5 + 0.5); + half3 masks2 = Masks2Texture[globalId.xy]; + + color += albedo * directionalAmbientColor * skylighting * (1.0 - masks2.zzz); + + MainRW[globalId.xy] = half4(color, 1.0); }; -[numthreads(32, 32, 1)] void AmbientCompositePass(uint3 globalId - : SV_DispatchThreadID, uint3 localId - : SV_GroupThreadID, uint3 groupId - : SV_GroupID) { +float random(float2 uv) +{ + return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453123); +} + +float InterleavedGradientNoise(float2 uv) +{ + // Temporal factor + float frameStep = float(FrameCount % 16) * 0.0625f; + uv.x += frameStep * 4.7526; + uv.y += frameStep * 3.1914; + + float3 magic = float3(0.06711056f, 0.00583715f, 52.9829189f); + return frac(magic.z * frac(dot(uv, magic.xy))); +} + +[numthreads(8, 8, 1)] void AmbientCompositePass(uint3 globalId + : SV_DispatchThreadID, uint3 localId + : SV_GroupThreadID, uint3 groupId + : SV_GroupID) { half2 uv = half2(globalId.xy + 0.5) * RcpBufferDim.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); half3 normalGlossiness = NormalRoughnessTexture[globalId.xy]; half3 normalVS = DecodeNormal(normalGlossiness.xy); - half4 diffuseColor = MainRW[globalId.xy]; - - half3 normalWS = normalize(mul(InvViewMatrix[eyeIndex], half4(normalVS, 0))); + half3 diffuseColor = MainRW[globalId.xy]; half3 albedo = AlbedoTexture[globalId.xy]; @@ -120,16 +172,46 @@ half GetScreenDepth(half depth) half3 masks = MasksTexture[globalId.xy]; + half3 normalWS = normalize(mul(InvViewMatrix[eyeIndex], half4(normalVS, 0))); + half3 directionalAmbientColor = mul(DirectionalAmbient, half4(normalWS, 1.0)); - diffuseColor.rgb += albedo * directionalAmbientColor * ao + gi; - MainRW[globalId.xy] = half4(diffuseColor.xyz, 1.0); + float skylighting = SkylightingTexture[globalId.xy]; + + half weight = 1.0; + + half rawDepth = DepthTexture[globalId.xy]; + half depth = GetScreenDepth(rawDepth); + + gi *= (rawDepth < 1.0); + ao = lerp(ao, 1.0, rawDepth == 1.0); + + diffuseColor *= ao; + diffuseColor += gi; + + skylighting = lerp(skylighting, 1.0, 0.5); + + diffuseColor += albedo * directionalAmbientColor * ao * skylighting * lerp(saturate(dot(normalWS, float3(0, 0, -1)) * 0.5 + 0.5), 1.0, 0.5); + + float3 giao = (skylighting * directionalAmbientColor * ao) + gi; + + MainRW[globalId.xy] = half4(diffuseColor, 1.0); }; -[numthreads(32, 32, 1)] void MainCompositePass(uint3 globalId - : SV_DispatchThreadID, uint3 localId - : SV_GroupThreadID, uint3 groupId - : SV_GroupID) { +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 MainCompositePass(uint3 globalId + : SV_DispatchThreadID, uint3 localId + : SV_GroupThreadID, uint3 groupId + : SV_GroupID) { half2 uv = half2(globalId.xy + 0.5) * RcpBufferDim.xy; uint eyeIndex = GetEyeIndexFromTexCoord(uv); @@ -140,11 +222,40 @@ half GetScreenDepth(half depth) half3 specularColor = SpecularTexture[globalId.xy]; half3 albedo = AlbedoTexture[globalId.xy]; half3 masks = MasksTexture[globalId.xy]; + half3 reflectance = ReflectanceTexture[globalId.xy]; half3 normalWS = normalize(mul(InvViewMatrix[eyeIndex], half4(normalVS, 0))); half glossiness = normalGlossiness.z; - half3 color = diffuseColor + specularColor; + half3 color = sRGB2Lin(diffuseColor) + sRGB2Lin(specularColor); + + half2 skylighting = SkylightingTexture[globalId.xy]; + half4 giAo = GITexture[globalId.xy]; + + half rawDepth = DepthTexture[globalId.xy]; + + half4 positionCS = half4(2 * half2(uv.x, -uv.y + 1) - 1, rawDepth, 1); + + PerGeometry sD = perShadow[0]; + + half4 positionMS = mul(InvViewMatrix[eyeIndex], positionCS); + positionMS.xyz = positionMS.xyz / positionMS.w; + + float3 V = normalize(positionMS.xyz); + float3 R = reflect(V, normalWS); + + float roughness = 1.0 - glossiness; + float level = roughness * 9.0; + + float3 specularIrradiance = EnvTexture.SampleLevel(LinearSampler, R, level).xyz; + specularIrradiance = sRGB2Lin(specularIrradiance); + + float3 specularIrradiance2 = ReflectionTexture.SampleLevel(LinearSampler, R, level).xyz; + specularIrradiance2 = sRGB2Lin(specularIrradiance2); + + color += reflectance * lerp(specularIrradiance, specularIrradiance2, skylighting.y * giAo.w) * giAo.w; + + color = Lin2sRGB(color); #if defined(DEBUG) half2 texCoord = half2(globalId.xy) / BufferDim.xy; @@ -160,6 +271,9 @@ half GetScreenDepth(half depth) } #endif - MainRW[globalId.xy] = half4(color.xyz, 1.0); + half2 snowParamaters = Masks2Texture[globalId.xy]; + + MainRW[globalId.xy] = half4(color, 1.0); NormalTAAMaskSpecularMaskRW[globalId.xy] = half4(EncodeNormalVanilla(normalVS), 0.0, glossiness); + SnowParametersRW[globalId.xy] = snowParamaters * lerp(skylighting.x, 1.0, 0.5); } \ No newline at end of file diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index 464986b39..b4b554a09 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -405,9 +405,7 @@ struct PS_OUTPUT float4 Specular : SV_Target4; float4 Reflectance : SV_Target5; float4 Masks : SV_Target6; -# if defined(SNOW) - float4 SnowParameters : SV_Target7; -# endif + float4 Parameters : SV_Target7; }; #else struct PS_OUTPUT @@ -416,7 +414,7 @@ struct PS_OUTPUT float4 MotionVectors : SV_Target1; float4 ScreenSpaceNormals : SV_Target2; # if defined(SNOW) - float4 SnowParameters : SV_Target3; + float4 Parameters : SV_Target3; # endif }; #endif @@ -933,6 +931,8 @@ float GetSnowParameterY(float texProjTmp, float alpha) # endif # endif +# include "Skylighting/Skylighting.hlsli" + PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace) { @@ -1334,7 +1334,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace modelNormal.xyz = projectedNormal; # if defined(SNOW) - psout.SnowParameters.y = 1; + psout.Parameters.y = 1; # endif // SNOW # else if (ProjectedUVParams3.w > 0.5) { @@ -1354,18 +1354,18 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # if defined(SNOW) useSnowDecalSpecular = true; - psout.SnowParameters.y = GetSnowParameterY(texProjTmp2, baseColor.w); + psout.Parameters.y = GetSnowParameterY(texProjTmp2, baseColor.w); # endif // SNOW } else { if (texProjTmp > 0) { baseColor.xyz = ProjectedUVParams2.xyz; # if defined(SNOW) useSnowDecalSpecular = true; - psout.SnowParameters.y = GetSnowParameterY(texProjTmp, baseColor.w); + psout.Parameters.y = GetSnowParameterY(texProjTmp, baseColor.w); # endif // SNOW } else { # if defined(SNOW) - psout.SnowParameters.y = 0; + psout.Parameters.y = 0; # endif // SNOW } } @@ -1377,9 +1377,9 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # elif defined(SNOW) # if defined(LANDSCAPE) - psout.SnowParameters.y = landSnowMask; + psout.Parameters.y = landSnowMask; # else - psout.SnowParameters.y = baseColor.w; + psout.Parameters.y = baseColor.w; # endif // LANDSCAPE # endif @@ -1397,36 +1397,38 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace normalizedDirLightDirectionWS = normalize(mul(input.World[eyeIndex], float4(DirLightDirection.xyz, 0))); # endif - float3 nsDirLightColor = dirLightColor; - - if ((shaderDescriptors[0].PixelShaderDescriptor & _DefShadow) && (shaderDescriptors[0].PixelShaderDescriptor & _ShadowDir)) - dirLightColor *= shadowColor.xxx; - -# if !defined(DEFERRED) && defined(CPM_AVAILABLE) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) - float3 dirLightDirectionTS = mul(DirLightDirection, tbn).xyz; - bool dirLightIsLit = true; - if ((shaderDescriptors[0].PixelShaderDescriptor & _DefShadow) && (shaderDescriptors[0].PixelShaderDescriptor & _ShadowDir)) { - if (shadowColor.x == 0) - dirLightIsLit = false; + dirLightColor *= shadowColor.xxx; } -# if defined(SCREEN_SPACE_SHADOWS) - if (dirLightSShadow == 0) - dirLightIsLit = false; -# endif // SCREEN_SPACE_SHADOWS +# if defined(DEFERRED) + psout.Parameters.z = 0; +# endif + + float dirLightAngle = dot(modelNormal.xyz, DirLightDirection.xyz); +# if defined(CPM_AVAILABLE) && (defined(SKINNED) || !defined(MODELSPACENORMALS)) + if ((shaderDescriptors[0].PixelShaderDescriptor & _DefShadow) && (shaderDescriptors[0].PixelShaderDescriptor & _ShadowDir)) { + if (shadowColor.x > 0.0 && dirLightAngle > 0.0) { + float3 dirLightDirectionTS = mul(DirLightDirection, tbn).xyz; + float parallaxShadow = 1.0; # if defined(LANDSCAPE) - if (perPassParallax[0].EnableTerrainParallax && perPassParallax[0].EnableShadows) - dirLightColor *= GetParallaxSoftShadowMultiplierTerrain(input, terrainUVs, mipLevel, dirLightDirectionTS, sh0, dirLightIsLit * parallaxShadowQuality); + if (perPassParallax[0].EnableTerrainParallax && perPassParallax[0].EnableShadows) + parallaxShadow = GetParallaxSoftShadowMultiplierTerrain(input, terrainUVs, mipLevel, dirLightDirectionTS, sh0, parallaxShadowQuality); # elif defined(PARALLAX) - if (perPassParallax[0].EnableParallax && perPassParallax[0].EnableShadows) - dirLightColor *= GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, dirLightIsLit * parallaxShadowQuality); + if (perPassParallax[0].EnableParallax && perPassParallax[0].EnableShadows) + parallaxShadow = GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, parallaxShadowQuality); # elif defined(ENVMAP) - if (complexMaterialParallax && perPassParallax[0].EnableShadows) - dirLightColor *= GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, dirLightIsLit * parallaxShadowQuality); + if (complexMaterialParallax && perPassParallax[0].EnableShadows) + parallaxShadow = GetParallaxSoftShadowMultiplier(uv, mipLevel, dirLightDirectionTS, sh0, TexEnvMaskSampler, SampEnvMaskSampler, 3, parallaxShadowQuality); # endif // LANDSCAPE -# endif // defined(CPM_AVAILABLE) && (defined (SKINNED) || !defined \ +# if defined(DEFERRED) + psout.Parameters.z = 1.0 - parallaxShadow; +# endif + dirLightColor *= parallaxShadow; + } + } +# endif // defined(CPM_AVAILABLE) && (defined (SKINNED) || !defined \ // (MODELSPACENORMALS)) float3 diffuseColor = 0.0.xxx; @@ -1435,8 +1437,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 lightsDiffuseColor = 0.0.xxx; float3 lightsSpecularColor = 0.0.xxx; - float dirLightAngle = dot(modelNormal.xyz, DirLightDirection.xyz); - # if defined(DEFERRED) float3 dirDiffuseColor = 0.0; # else @@ -1444,15 +1444,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # if defined(SOFT_LIGHTING) - lightsDiffuseColor += nsDirLightColor.xyz * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirLightColor * GetSoftLightMultiplier(dirLightAngle) * rimSoftLightColor.xyz; # endif # if defined(RIM_LIGHTING) - lightsDiffuseColor += nsDirLightColor.xyz * GetRimLightMultiplier(DirLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz; + lightsDiffuseColor += dirLightColor * GetRimLightMultiplier(DirLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz; # endif # if defined(BACK_LIGHTING) - lightsDiffuseColor += nsDirLightColor.xyz * (saturate(-dirLightAngle) * backLightColor.xyz); + lightsDiffuseColor += dirLightColor * saturate(-dirLightAngle) * backLightColor.xyz; # endif if (useSnowSpecular && useSnowDecalSpecular) { @@ -1598,8 +1598,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float intensityMultiplier = 1 - intensityFactor * intensityFactor; float3 lightColor = PointLightColor[lightIndex].xyz * intensityMultiplier; - float3 nsLightColor = lightColor; - if (shaderDescriptors[0].PixelShaderDescriptor & _DefShadow) { if (lightIndex < numShadowLights) { lightColor *= shadowColor[ShadowLightMaskSelect[lightIndex]]; @@ -1612,15 +1610,15 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 lightDiffuseColor = lightColor * saturate(lightAngle.xxx); # if defined(SOFT_LIGHTING) - lightDiffuseColor += nsLightColor * GetSoftLightMultiplier(dot(modelNormal.xyz, lightDirection.xyz)) * rimSoftLightColor.xyz; + lightDiffuseColor += lightColor * GetSoftLightMultiplier(lightAngle) * rimSoftLightColor.xyz; # endif // SOFT_LIGHTING # if defined(RIM_LIGHTING) - lightDiffuseColor += nsLightColor * GetRimLightMultiplier(normalizedLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz; + lightDiffuseColor += lightColor * GetRimLightMultiplier(normalizedLightDirection, viewDirection, modelNormal.xyz) * rimSoftLightColor.xyz; # endif // RIM_LIGHTING # if defined(BACK_LIGHTING) - lightDiffuseColor += (saturate(-lightAngle) * backLightColor.xyz) * nsLightColor; + lightDiffuseColor += lightColor * saturate(-lightAngle) * backLightColor.xyz; # endif // BACK_LIGHTING # if defined(SPECULAR) || (defined(SPARKLE) && !defined(SNOW)) @@ -1667,6 +1665,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float intensityMultiplier = 1 - intensityFactor * intensityFactor; float3 lightColor = light.color.xyz * intensityMultiplier; + float contactShadow = 1.0; float shadowComponent = 1.0; if (shaderDescriptors[0].PixelShaderDescriptor & _DefShadow) { @@ -1676,28 +1675,27 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } } - float3 nsLightColor = lightColor; float3 normalizedLightDirection = normalize(lightDirection); + float lightAngle = dot(worldSpaceNormal.xyz, normalizedLightDirection.xyz); - [branch] if (perPassLLF[0].EnableGlobalLights && !FrameParams.z && FrameParams.y && (light.firstPersonShadow || perPassLLF[0].EnableContactShadows) && shadowComponent != 0.0) + [branch] if (perPassLLF[0].EnableGlobalLights && !FrameParams.z && FrameParams.y && (light.firstPersonShadow || perPassLLF[0].EnableContactShadows) && shadowComponent != 0.0 && lightAngle > 0.0) { float3 normalizedLightDirectionVS = normalize(light.positionVS[eyeIndex].xyz - viewPosition.xyz); float contactShadow = ContactShadows(viewPosition, screenUV, screenNoise, normalizedLightDirectionVS, light.radius, light.firstPersonShadow, eyeIndex); [flatten] if (light.firstPersonShadow) { - lightColor *= contactShadow; + contactShadow = contactShadow; } else { float shadowIntensityFactor = saturate(dot(worldSpaceNormal, normalizedLightDirection.xyz) * PI); - lightColor *= lerp(lerp(1.0, contactShadow, shadowIntensityFactor), 1.0, !frontFace * 0.2); + contactShadow = lerp(lerp(1.0, contactShadow, shadowIntensityFactor), 1.0, !frontFace * 0.2); } } # if defined(CPM_AVAILABLE) - if (perPassParallax[0].EnableShadows && shadowComponent != 0.0) { + if (perPassParallax[0].EnableShadows && shadowComponent != 0.0 && lightAngle > 0.0) { float3 lightDirectionTS = normalize(mul(normalizedLightDirection, tbn).xyz); - # if defined(PARALLAX) [branch] if (perPassParallax[0].EnableParallax) lightColor *= GetParallaxSoftShadowMultiplier(uv, mipLevel, lightDirectionTS, sh0, TexParallaxSampler, SampParallaxSampler, 0, parallaxShadowQuality); @@ -1711,19 +1709,18 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } # endif - float lightAngle = dot(worldSpaceNormal.xyz, normalizedLightDirection.xyz); - float3 lightDiffuseColor = lightColor * saturate(lightAngle.xxx); + float3 lightDiffuseColor = lightColor * contactShadow * saturate(lightAngle.xxx); # if defined(SOFT_LIGHTING) - lightDiffuseColor += nsLightColor * GetSoftLightMultiplier(dot(worldSpaceNormal.xyz, lightDirection.xyz)) * rimSoftLightColor.xyz; + lightDiffuseColor += lightColor * GetSoftLightMultiplier(lightAngle) * rimSoftLightColor.xyz; # endif # if defined(RIM_LIGHTING) - lightDiffuseColor += nsLightColor * GetRimLightMultiplier(normalizedLightDirection, worldSpaceViewDirection, worldSpaceNormal.xyz) * rimSoftLightColor.xyz; + lightDiffuseColor += lightColor * GetRimLightMultiplier(normalizedLightDirection, worldSpaceViewDirection, worldSpaceNormal.xyz) * rimSoftLightColor.xyz; # endif # if defined(BACK_LIGHTING) - lightDiffuseColor += (saturate(-lightAngle) * backLightColor.xyz) * nsLightColor; + lightDiffuseColor += lightColor * saturate(-lightAngle) * backLightColor.xyz; # endif # if defined(SPECULAR) || (defined(SPARKLE) && !defined(SNOW)) @@ -1817,11 +1814,6 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif envColor = GetDynamicCubemap(screenUV, worldSpaceNormal, worldSpaceVertexNormal, worldSpaceViewDirection, envRoughness, F0, diffuseColor, viewPosition.z) * envMask; - - if (shaderDescriptors[0].PixelShaderDescriptor & _DefShadow && shaderDescriptors[0].PixelShaderDescriptor & _ShadowDir) { - float upAngle = saturate(dot(float3(0, 0, 1), normalizedDirLightDirectionWS.xyz)); - envColor *= lerp(1.0, shadowColor.x, saturate(upAngle) / 3.0); - } } # endif # endif // defined (ENVMAP) || defined (MULTI_LAYER_PARALLAX) || defined(EYE) @@ -1895,16 +1887,22 @@ 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(DEFERRED) + diffuseColor = 0.0; +# else diffuseColor = 1.0; +# endif specularColor = sRGB2Lin(specularColor); } # endif # if defined(CPM_AVAILABLE) && defined(ENVMAP) # if defined(DYNAMIC_CUBEMAPS) - specularColor += envColor * lerp(complexSpecular, 1.0, dynamicCubemap) * diffuseColor; + envColor *= lerp(complexSpecular, 1.0, dynamicCubemap); + specularColor += envColor * diffuseColor; # else - specularColor += envColor * complexSpecular * diffuseColor; + envColor *= complexSpecular; + specularColor += envColor * diffuseColor; # endif # else specularColor += envColor * diffuseColor; @@ -1956,8 +1954,17 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace color.xyz = min(specularTmp.xyz, color.xyz); # endif // defined (SPECULAR) || defined(SPARKLE) -# if defined(ENVMAP) && defined(TESTCUBEMAP) - color.xyz = specularTexture.SampleLevel(SampEnvSampler, envSamplingPoint, 1).xyz; +# if defined(TESTCUBEMAP) +# if (defined(ENVMAP) || defined(MULTI_LAYER_PARALLAX) || defined(EYE)) +# if defined(DYNAMIC_CUBEMAPS) + baseColor.xyz = 0.0; + specularColor = 0.0; + diffuseColor = 0.0; + dynamicCubemap = true; + envColor = 1.0; + envRoughness = 0.0; +# endif +# endif # endif # if defined(LANDSCAPE) && !defined(LOD_LAND_BLEND) @@ -2028,7 +2035,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif // defined(LIGHT_LIMIT_FIX) # if defined(SNOW) - psout.SnowParameters.x = dot(lightsSpecularColor, float3(0.3, 0.59, 0.11)); + psout.Parameters.x = dot(lightsSpecularColor, float3(0.3, 0.59, 0.11)); # endif // SNOW && !PBR psout.MotionVectors.xy = SSRParams.z > 1e-5 ? float2(1, 0) : screenMotionVector.xy; @@ -2107,7 +2114,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace psout.Diffuse.w = blendFactorTerrain; # if defined(SNOW) - psout.SnowParameters.w = blendFactorTerrain; + psout.Parameters.w = blendFactorTerrain; # endif # endif @@ -2124,11 +2131,20 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace psout.Albedo = float4(baseColor.xyz * realVertexColor, psout.Diffuse.w); psout.Reflectance = float4(0.0.xxx, psout.Diffuse.w); psout.Masks = float4(0, 0, 0, psout.Diffuse.w); + psout.Parameters.w = psout.Diffuse.w; float outGlossiness = saturate(glossiness * SSRParams.w); - psout.NormalGlossiness = float4(EncodeNormal(screenSpaceNormal), outGlossiness, psout.Diffuse.w); +# if (defined(ENVMAP) || defined(MULTI_LAYER_PARALLAX) || defined(EYE)) +# if defined(DYNAMIC_CUBEMAPS) + if (dynamicCubemap) { + psout.Reflectance.xyz = envColor; + psout.NormalGlossiness.z = 1.0 - envRoughness; + } +# endif +# endif + # if defined(SSS) && defined(SKIN) psout.Masks.x = saturate(baseColor.a); psout.Masks.y = !perPassSSS[0].IsBeastRace; diff --git a/package/Shaders/ShadowTest/CopyShadowData.hlsl b/package/Shaders/ShadowTest/CopyShadowData.hlsl new file mode 100644 index 000000000..69073a7d1 --- /dev/null +++ b/package/Shaders/ShadowTest/CopyShadowData.hlsl @@ -0,0 +1,115 @@ + +struct PerGeometry +{ + float4 VPOSOffset; + float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam; + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + float4x3 FocusShadowMapProj[4]; +#if !defined(VR) + float4x3 ShadowMapProj[1][3]; + float4x4 CameraViewProjInverse[1]; +#else + float4x3 ShadowMapProj[2][3]; + float4x4 CameraViewProjInverse[2]; +#endif // VR +}; + +cbuffer PerFrame : register(b0) +{ + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + float4x3 FocusShadowMapProj[4]; +#if !defined(VR) + float4x3 ShadowMapProj[1][3]; +#else + float4x3 ShadowMapProj[2][3]; +#endif // VR +} + +cbuffer PerFrame2 : register(b1) +{ +#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 PerFrame3 : register(b2) +{ + float4 VPOSOffset : packoffset(c0); + float4 ShadowSampleParam : packoffset(c1); // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances : packoffset(c2); // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances : packoffset(c3); // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam : packoffset(c4); +} + +RWStructuredBuffer copiedData : register(u0); + +[numthreads(1, 1, 1)] void main() { + PerGeometry perGeometry; + perGeometry.DebugColor = DebugColor; + perGeometry.PropertyColor = PropertyColor; + perGeometry.AlphaTestRef = AlphaTestRef; + perGeometry.ShadowLightParam = ShadowLightParam; + perGeometry.FocusShadowMapProj = FocusShadowMapProj; + perGeometry.ShadowMapProj = ShadowMapProj; + + perGeometry.CameraViewProjInverse = CameraViewProjInverse; + + perGeometry.VPOSOffset = VPOSOffset; + perGeometry.ShadowSampleParam = ShadowSampleParam; + perGeometry.EndSplitDistances = EndSplitDistances; + perGeometry.StartSplitDistances = StartSplitDistances; + perGeometry.FocusShadowFadeParam = FocusShadowFadeParam; + + copiedData[0] = perGeometry; +} \ No newline at end of file diff --git a/package/Shaders/Sky.hlsl b/package/Shaders/Sky.hlsl index 40663447f..29d409d70 100644 --- a/package/Shaders/Sky.hlsl +++ b/package/Shaders/Sky.hlsl @@ -1,3 +1,7 @@ +#if defined(DEFERRED) +# undef CLOUD_SHADOWS +#endif + struct VS_INPUT { float4 Position : POSITION0; diff --git a/package/Shaders/Utility.hlsl b/package/Shaders/Utility.hlsl index 116b15cea..e4230fe50 100644 --- a/package/Shaders/Utility.hlsl +++ b/package/Shaders/Utility.hlsl @@ -1,3 +1,4 @@ +#include "Common/Constants.hlsli" #include "Common/FrameBuffer.hlsl" #include "Common/LodLandscape.hlsli" #include "Common/Skinned.hlsli" @@ -26,6 +27,9 @@ struct VS_INPUT float4 BoneWeights : BLENDWEIGHT0; float4 BoneIndices : BLENDINDICES0; #endif +#if defined(VR) + uint InstanceID : SV_INSTANCEID; +#endif // VR }; struct VS_OUTPUT @@ -67,13 +71,23 @@ struct VS_OUTPUT float Depth : TEXCOORD2; # endif #endif +#if defined(VR) + float ClipDistance : SV_ClipDistance0; // o11 + float CullDistance : SV_CullDistance0; // p11 + uint EyeIndex : EYEIDX0; +#endif // VR }; #ifdef VSHADER cbuffer PerTechnique : register(b0) { - float4 HighDetailRange : packoffset(c0); // loaded cells center in xy, size in zw - float2 ParabolaParam : packoffset(c1); // inverse radius in x, y is 1 for forward hemisphere or -1 for backward hemisphere +# if !defined(VR) + float4 HighDetailRange[1] : packoffset(c0); // loaded cells center in xy, size in zw + float2 ParabolaParam : packoffset(c1); // inverse radius in x, y is 1 for forward hemisphere or -1 for backward hemisphere +# else + float4 HighDetailRange[2] : packoffset(c0); // loaded cells center in xy, size in zw + float2 ParabolaParam : packoffset(c2); // inverse radius in x, y is 1 for forward hemisphere or -1 for backward hemisphere +# endif // VR }; cbuffer PerMaterial : register(b1) @@ -83,11 +97,19 @@ cbuffer PerMaterial : register(b1) cbuffer PerGeometry : register(b2) { +# if !defined(VR) float4 ShadowFadeParam : packoffset(c0); - row_major float4x4 World : packoffset(c1); - float4 EyePos : packoffset(c5); + row_major float4x4 World[1] : packoffset(c1); + float4 EyePos[1] : packoffset(c5); float4 WaterParams : packoffset(c6); float4 TreeParams : packoffset(c7); +# else + float4 ShadowFadeParam : packoffset(c0); + row_major float4x4 World[2] : packoffset(c1); + float4 EyePos[2] : packoffset(c9); + float4 WaterParams : packoffset(c11); + float4 TreeParams : packoffset(c12); +# endif // VR }; float2 SmoothSaturate(float2 value) @@ -110,7 +132,7 @@ VS_OUTPUT main(VS_INPUT input) # if defined(RENDER_SHADOWMASKDPB) vsout.PositionCS.z = ShadowFadeParam.z; # else - vsout.PositionCS.z = HighDetailRange.x; + vsout.PositionCS.z = HighDetailRange[eyeIndex].x; # endif vsout.PositionCS.w = 1; # elif defined(STENCIL_ABOVE_WATER) @@ -133,7 +155,7 @@ VS_OUTPUT main(VS_INPUT input) # endif # if defined(LOD_LANDSCAPE) - positionMS = AdjustLodLandscapeVertexPositionMS(positionMS, World, HighDetailRange); + positionMS = AdjustLodLandscapeVertexPositionMS(positionMS, World[eyeIndex], HighDetailRange[eyeIndex]); # endif # if defined(SKINNED) @@ -144,7 +166,7 @@ VS_OUTPUT main(VS_INPUT input) positionCS = mul(CameraViewProj[eyeIndex], positionWS); # else - precise float4x4 modelViewProj = mul(CameraViewProj[eyeIndex], World); + precise float4x4 modelViewProj = mul(CameraViewProj[eyeIndex], World[eyeIndex]); positionCS = mul(modelViewProj, positionMS); # endif @@ -171,7 +193,7 @@ VS_OUTPUT main(VS_INPUT input) normalMS = normalize(mul(normalMS, transpose(boneRSMatrix))); normalVS = mul(CameraView[eyeIndex], float4(normalMS, 0)).xyz; # else - normalVS = mul(mul(CameraView[eyeIndex], World), float4(normalMS, 0)).xyz; + normalVS = mul(mul(CameraView[eyeIndex], World[eyeIndex]), float4(normalMS, 0)).xyz; # endif # if defined(RENDER_NORMAL_CLAMP) normalVS = max(min(normalVS, 0.1), -0.1); @@ -196,12 +218,12 @@ VS_OUTPUT main(VS_INPUT input) float falloff = 1; # if defined(RENDER_NORMAL_FALLOFF) # if defined(SKINNED) - falloff = dot(normalMS, normalize(EyePos.xyz - positionWS.xyz)); + falloff = dot(normalMS, normalize(EyePos[eyeIndex].xyz - positionWS.xyz)); # else - falloff = dot(normalMS, normalize(EyePos.xyz - positionMS.xyz)); + falloff = dot(normalMS, normalize(EyePos[eyeIndex].xyz - positionMS.xyz)); # endif # endif - texCoord.w = EyePos.w * falloff; + texCoord.w = EyePos[eyeIndex].w * falloff; # endif vsout.TexCoord0 = texCoord; @@ -244,7 +266,13 @@ VS_OUTPUT main(VS_INPUT input) # endif # endif - +# ifdef VR + vsout.EyeIndex = eyeIndex; + VR_OUTPUT VRout = GetVRVSOutput(vsout.PositionCS, eyeIndex); + vsout.PositionCS = VRout.VRPosition; + vsout.ClipDistance.x = VRout.ClipDistance; + vsout.CullDistance.x = VRout.CullDistance; +# endif // VR return vsout; } #endif @@ -297,18 +325,37 @@ cbuffer PerGeometry : register(b2) float4 PropertyColor : packoffset(c1); float4 AlphaTestRef : packoffset(c2); float4 ShadowLightParam : packoffset(c3); // Falloff in x, ShadowDistance squared in z +# if !defined(VR) float4x3 FocusShadowMapProj[4] : packoffset(c4); -# if defined(RENDER_SHADOWMASK) - float4x3 ShadowMapProj[4] : packoffset(c16); -# elif defined(RENDER_SHADOWMASKSPOT) || defined(RENDER_SHADOWMASKPB) || defined(RENDER_SHADOWMASKDPB) - float4x4 ShadowMapProj : packoffset(c16); -# endif +# if defined(RENDER_SHADOWMASK) + float4x3 ShadowMapProj[1][3] : packoffset(c16); // 16, 19, 22 +# elif defined(RENDER_SHADOWMASKSPOT) || defined(RENDER_SHADOWMASKPB) || defined(RENDER_SHADOWMASKDPB) + float4x4 ShadowMapProj[1][3] : packoffset(c16); +# endif +# else + float4 VRUnknown : packoffset(c4); // used to multiply by identity matrix, see e.g., 4202499.ps.bin.hlsl + /* + r1.x = dot(cb2[4].xz, icb[r0.w+0].xz); + r1.x = r0.x * cb12[86].x + -r1.x; + r0.w = (int)r0.w + 1; + r0.w = (int)r0.w + -1; + r0.w = dot(cb2[4].yw, icb[r0.w+0].xz); + */ + float4x3 FocusShadowMapProj[4] : packoffset(c5); +# if defined(RENDER_SHADOWMASK) + float4x3 ShadowMapProj[2][3] : packoffset(c29); // VR has a couple of offsets of 3, e.g., {29, 32, 35} and {38, 41, 44}, compare to Flat which does [16, 19, 22] +# elif defined(RENDER_SHADOWMASKSPOT) || defined(RENDER_SHADOWMASKPB) || defined(RENDER_SHADOWMASKDPB) + float4x4 ShadowMapProj[2][3] : packoffset(c29); +# endif +# endif // VR } -cbuffer AlphaTestRefBuffer : register(b11) +# if !defined(VR) +cbuffer AlphaTestRefCB : register(b11) { - float GlobalAlphaTestRef : packoffset(c0); + float AlphaTestRefRS : packoffset(c0); } +# endif // !VR float GetPoissonDiskFilteredShadowVisibility(Texture2DArray tex, SamplerComparisonState samp, float sampleOffsetShift, float2 baseUv, float layerIndex, float compareValue, bool asymmetric) { @@ -1347,8 +1394,11 @@ PS_OUTPUT main(PS_INPUT input) { PS_OUTPUT psout; - uint eyeIndex = GetEyeIndexPS(input.PositionCS, VPOSOffset); - +# if !defined(VR) + uint eyeIndex = 0; +# else + uint eyeIndex = input.EyeIndex; +# endif // !VR # if defined(ADDITIONAL_ALPHA_MASK) uint2 alphaMask = input.PositionCS.xy; alphaMask.x = ((alphaMask.x << 2) & 12); @@ -1440,7 +1490,7 @@ PS_OUTPUT main(PS_INPUT input) TexStencilSampler.GetDimensions(0, stencilDimensions.x, stencilDimensions.y, stencilDimensions.z); stencilValue = TexStencilSampler.Load(float3(stencilDimensions.xy * depthUv, 0)).x; # endif - + depthUv = ConvertFromStereoUV(depthUv, eyeIndex); float4 positionCS = float4(2 * float2(DynamicResolutionParams2.x * depthUv.x, -depthUv.y * DynamicResolutionParams2.y + 1) - 1, depth, 1); float4 positionMS = mul(CameraViewProjInverse[eyeIndex], positionCS); positionMS.xyz = positionMS.xyz / positionMS.w; @@ -1456,15 +1506,15 @@ PS_OUTPUT main(PS_INPUT input) # if defined(RENDER_SHADOWMASK) if (EndSplitDistances.z >= shadowMapDepth) { - float4x3 lightProjectionMatrix = ShadowMapProj[0]; + float4x3 lightProjectionMatrix = ShadowMapProj[eyeIndex][0]; float shadowMapThreshold = AlphaTestRef.y; float cascadeIndex = 0; if (2.5 < EndSplitDistances.w && EndSplitDistances.y < shadowMapDepth) { - lightProjectionMatrix = ShadowMapProj[2]; + lightProjectionMatrix = ShadowMapProj[eyeIndex][2]; shadowMapThreshold = AlphaTestRef.z; cascadeIndex = 2; } else if (EndSplitDistances.x < shadowMapDepth) { - lightProjectionMatrix = ShadowMapProj[1]; + lightProjectionMatrix = ShadowMapProj[eyeIndex][1]; shadowMapThreshold = AlphaTestRef.z; cascadeIndex = 1; } @@ -1487,7 +1537,7 @@ PS_OUTPUT main(PS_INPUT input) if (cascadeIndex < 1 && StartSplitDistances.y < shadowMapDepth) { float cascade1ShadowVisibility = 0; - float3 cascade1PositionLS = mul(transpose(ShadowMapProj[1]), float4(positionMS.xyz, 1)).xyz; + float3 cascade1PositionLS = mul(transpose(ShadowMapProj[eyeIndex][1]), float4(positionMS.xyz, 1)).xyz; # if SHADOWFILTER == 0 float cascade1ShadowMapValue = TexShadowMapSampler.Sample(SampShadowMapSampler, float3(cascade1PositionLS.xy, 1)).x; @@ -1523,7 +1573,7 @@ PS_OUTPUT main(PS_INPUT input) shadowColor.xyzw = fadeFactor * (shadowVisibility - 1) + 1; } # elif defined(RENDER_SHADOWMASKSPOT) - float4 positionLS = mul(transpose(ShadowMapProj), float4(positionMS.xyz, 1)); + float4 positionLS = mul(transpose(ShadowMapProj[eyeIndex][0]), float4(positionMS.xyz, 1)); positionLS.xyz /= positionLS.w; float2 shadowMapUv = positionLS.xy * 0.5 + 0.5; float shadowBaseVisibility = 0; @@ -1561,7 +1611,7 @@ PS_OUTPUT main(PS_INPUT input) shadowColor.xyzw = fadeFactor * shadowVisibility; # elif defined(RENDER_SHADOWMASKPB) - float4 unadjustedPositionLS = mul(transpose(ShadowMapProj), float4(positionMS.xyz, 1)); + float4 unadjustedPositionLS = mul(transpose(ShadowMapProj[eyeIndex][0]), float4(positionMS.xyz, 1)); float shadowVisibility = 0; @@ -1586,7 +1636,7 @@ PS_OUTPUT main(PS_INPUT input) shadowColor.xyzw = fadeFactor * shadowVisibility; # elif defined(RENDER_SHADOWMASKDPB) - float4 unadjustedPositionLS = mul(transpose(ShadowMapProj), float4(positionMS.xyz, 1)); + float4 unadjustedPositionLS = mul(transpose(ShadowMapProj[eyeIndex][0]), float4(positionMS.xyz, 1)); float3 positionLS = unadjustedPositionLS.xyz / unadjustedPositionLS.w; bool lowerHalf = unadjustedPositionLS.z * 0.5 + 0.5 < 0; float3 normalizedPositionLS = normalize(positionLS); @@ -1628,7 +1678,7 @@ PS_OUTPUT main(PS_INPUT input) # elif defined(RENDER_NORMAL_CLEAR) && !defined(DEBUG_COLOR) testAlpha = 0; # endif - if (-GlobalAlphaTestRef + testAlpha < 0) { + if (-AlphaTestRefRS + testAlpha < 0) { discard; } # endif diff --git a/package/Shaders/Water.hlsl b/package/Shaders/Water.hlsl index 1446cb9e2..082e33c9e 100644 --- a/package/Shaders/Water.hlsl +++ b/package/Shaders/Water.hlsl @@ -4,6 +4,8 @@ #define WATER +#undef SKYLIGHTING + #include "Common/LightingData.hlsl" struct VS_INPUT @@ -573,17 +575,17 @@ float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection return ReflectionColor.xyz * VarAmounts.y; } -# if defined(DEPTH) +//# if defined(DEPTH) float GetScreenDepthWater(float2 screenPosition, uint a_useVR = 0) { float depth = DepthTex.Load(float3(screenPosition, 0)).x; return -# if defined(VR) // VR appears to use hard coded values +# if defined(VR) // VR appears to use hard coded values a_useVR ? depth * 1.01 + -0.01 : -# endif +# endif (CameraData.w / (-depth * CameraData.z + CameraData.x)); } -# endif +//# endif float3 GetLdotN(float3 normal) { @@ -607,12 +609,17 @@ float GetFresnelValue(float3 normal, float3 viewDirection) return (1 - FresnelRI.x) * pow(viewAngle, 5) + FresnelRI.x; } +# if defined(SKYLIGHTING) +# define LinearSampler Normals01Sampler +# include "Skylighting/Skylighting.hlsli" +# endif + # if defined(WATER_CAUSTICS) float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, - float4 distanceMul, float refractionsDepthFactor, float fresnel, float3 caustics, uint a_eyeIndex = 0) + float4 distanceMul, float refractionsDepthFactor, float fresnel, float3 caustics, uint a_eyeIndex, float3 viewPosition, inout float3 scatter, inout float3 transmittance) # else float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, - float4 distanceMul, float refractionsDepthFactor, float fresnel, uint a_eyeIndex = 0) + float4 distanceMul, float refractionsDepthFactor, float fresnel, uint a_eyeIndex, float3 viewPosition, inout float3 scatter, inout float3 transmittance) # endif { # if defined(REFRACTIONS) @@ -624,10 +631,11 @@ float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, float2(refractionNormal.x, refractionNormal.w - refractionNormal.y) / refractionNormal.ww; refractionUvRaw = ConvertToStereoUV(refractionUvRaw, a_eyeIndex); // need to convert here for VR due to refractionNormal values -# if defined(DEPTH) && !defined(VERTEX_ALPHA_DEPTH) float2 screenPosition = DynamicResolutionParams1.xy * (DynamicResolutionParams2.xy * input.HPosition.xy); float depth = GetScreenDepthWater(screenPosition); + float2 refractionScreenPosition = DynamicResolutionParams1.xy * (refractionUvRaw / VPOSOffset.xy); +# if defined(DEPTH) && !defined(VERTEX_ALPHA_DEPTH) float refractionDepth = GetScreenDepthWater(refractionScreenPosition); float refractionDepthMul = length(float3((((VPOSOffset.zw + refractionUvRaw) * 2 - 1)) * refractionDepth / ProjData.xy, refractionDepth)); @@ -647,6 +655,15 @@ float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, float3 refractionColor = RefractionTex.Sample(RefractionSampler, refractionUV).xyz; float3 refractionDiffuseColor = lerp(ShallowColor.xyz, DeepColor.xyz, distanceMul.y); +# ifdef SKYLIGHTING + float4 refractionWorldPosition = mul( + CameraViewProjInverse[a_eyeIndex], + float4((refractionUvRaw * 2 - 1) * float2(1, -1), DepthTex.Load(float3(refractionScreenPosition, 0)).x, 1)); + refractionWorldPosition.xyz /= refractionWorldPosition.w; + // float3 refractionWorldPosition = input.WPosition.xyz * depth / viewPosition.z; // this is without refraction + GetVL(input.WPosition.xyz, refractionWorldPosition.xyz, screenPosition, scatter, transmittance); +# endif + # if defined(UNDERWATER) float refractionMul = 0; # else @@ -660,6 +677,7 @@ float3 GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDirection, # endif return lerp(refractionColor * WaterParams.w, refractionDiffuseColor, refractionMul); + // return refractionColor * transmittance; // this is physically accurate # else return lerp(ShallowColor.xyz, DeepColor.xyz, fresnel) * GetLdotN(normal); # endif @@ -679,7 +697,7 @@ float3 GetSunColor(float3 normal, float3 viewDirection) float3 sunDirection = SunColor.xyz * SunDir.w; float sunMul = pow(saturate(dot(normal, float3(-0.099, -0.099, 0.99))), ShallowColor.w); - return (reflectionMul * sunDirection * 0.3) * DeepColor.w + WaterParams.z * (sunMul * sunDirection * 0.1); + return (reflectionMul * sunDirection) * DeepColor.w + WaterParams.z * (sunMul * sunDirection); # endif } # endif @@ -746,6 +764,9 @@ PS_OUTPUT main(PS_INPUT input) float4 depthControl = DepthControl * (distanceMul - 1) + 1; # endif + float3 viewPosition = mul(CameraView[eyeIndex], float4(input.WPosition.xyz, 1)).xyz; + float2 screenUV = ViewToUV(viewPosition, true, eyeIndex); + # if defined(WATER_CAUSTICS) float3 caustics = 0.0; float3 normal = GetWaterNormal(input, distanceFactor, depthControl.z, viewDirection, depth, caustics, eyeIndex); @@ -774,11 +795,13 @@ PS_OUTPUT main(PS_INPUT input) # else float3 specularColor = GetWaterSpecularColor(input, normal, viewDirection, distanceFactor, depthControl.y, eyeIndex); -# if defined(WATER_CAUSTICS) - float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, caustics, eyeIndex); + float3 scatter = 0; + float3 transmittance = 1; +# if defined(WATER_CAUSTICS) + float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, caustics, eyeIndex, viewPosition, scatter, transmittance); # else - float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, eyeIndex); + float3 diffuseColor = GetWaterDiffuseColor(input, normal, viewDirection, distanceMul, depthControl.y, fresnel, eyeIndex, viewPosition, scatter, transmittance); # endif float3 specularLighting = 0; @@ -786,9 +809,6 @@ PS_OUTPUT main(PS_INPUT input) # if defined(LIGHT_LIMIT_FIX) uint lightCount = 0; - float3 viewPosition = mul(CameraView[eyeIndex], float4(input.WPosition.xyz, 1)).xyz; - float2 screenUV = ViewToUV(viewPosition, true, eyeIndex); - uint clusterIndex = 0; if (perPassLLF[0].EnableGlobalLights && GetClusterIndex(screenUV, viewPosition.z, clusterIndex)) { lightCount = lightGrid[clusterIndex].lightCount; @@ -823,8 +843,14 @@ PS_OUTPUT main(PS_INPUT input) finalSpecularColor; # else float3 sunColor = GetSunColor(normal, viewDirection); +# if defined(SKYLIGHTING) + sunColor *= GetShadow(input.WPosition); +# endif float specularFraction = lerp(1, fresnel * depthControl.x, distanceFactor); float3 finalColorPreFog = lerp(diffuseColor, specularColor, specularFraction) + sunColor * depthControl.w; +# if defined(SKYLIGHTING) + finalColorPreFog += scatter; +# endif float3 finalColor = lerp(finalColorPreFog, input.FogParam.xyz, input.FogParam.w); # endif # endif diff --git a/src/Buffer.h b/src/Buffer.h index dda56f415..7bf9e399f 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -249,11 +249,18 @@ class Texture2D DX::ThrowIfFailed(device->CreateRenderTargetView(resource.get(), &a_desc, rtv.put())); } + void CreateDSV(D3D11_DEPTH_STENCIL_VIEW_DESC const& a_desc) + { + ID3D11Device* device = reinterpret_cast(RE::BSGraphics::Renderer::GetSingleton()->GetRuntimeData().forwarder); + DX::ThrowIfFailed(device->CreateDepthStencilView(resource.get(), &a_desc, dsv.put())); + } + D3D11_TEXTURE2D_DESC desc; winrt::com_ptr resource; winrt::com_ptr srv; winrt::com_ptr uav; winrt::com_ptr rtv; + winrt::com_ptr dsv; }; class Texture3D @@ -276,9 +283,14 @@ class Texture3D ID3D11Device* device = reinterpret_cast(RE::BSGraphics::Renderer::GetSingleton()->GetRuntimeData().forwarder); DX::ThrowIfFailed(device->CreateUnorderedAccessView(resource.get(), &a_desc, uav.put())); } - + void CreateRTV(D3D11_RENDER_TARGET_VIEW_DESC const& a_desc) + { + ID3D11Device* device = reinterpret_cast(RE::BSGraphics::Renderer::GetSingleton()->GetRuntimeData().forwarder); + DX::ThrowIfFailed(device->CreateRenderTargetView(resource.get(), &a_desc, rtv.put())); + } D3D11_TEXTURE3D_DESC desc; winrt::com_ptr resource; winrt::com_ptr srv; winrt::com_ptr uav; + winrt::com_ptr rtv; }; \ No newline at end of file diff --git a/src/Deferred.cpp b/src/Deferred.cpp index d270ad3c3..13d29304f 100644 --- a/src/Deferred.cpp +++ b/src/Deferred.cpp @@ -2,8 +2,10 @@ #include "State.h" #include "Util.h" #include +#include #include #include +#include #include #include #include @@ -139,6 +141,8 @@ void Deferred::SetupResources() SetupRenderTarget(NORMALROUGHNESS, texDesc, srvDesc, rtvDesc, uavDesc, DXGI_FORMAT_R8G8B8A8_UNORM); // Masks SetupRenderTarget(MASKS, texDesc, srvDesc, rtvDesc, uavDesc, DXGI_FORMAT_R8G8B8A8_UNORM); + // Additional Masks + SetupRenderTarget(MASKS2, texDesc, srvDesc, rtvDesc, uavDesc, DXGI_FORMAT_R8G8B8A8_UNORM); } { @@ -196,10 +200,6 @@ void Deferred::SetupResources() void Deferred::Reset() { - //for (auto& str : perms) - //{ - //// logger::info("{}", str); - //} } void Deferred::UpdateConstantBuffer() @@ -388,7 +388,7 @@ void Deferred::StartDeferred() SPECULAR, REFLECTANCE, MASKS, - forwardRenderTargets[3] // Improved snow shader + MASKS2 }; for (uint i = 2; i < 8; i++) { @@ -398,19 +398,6 @@ void Deferred::StartDeferred() stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); // Run OMSetRenderTargets again - static BlendStates* blendStates = (BlendStates*)REL::RelocationID(524749, 411364).address(); - - // Set modified blend states - blendStates->a[0][0][1][0] = deferredBlendStates[0]; - blendStates->a[0][0][10][0] = deferredBlendStates[1]; - blendStates->a[1][0][1][0] = deferredBlendStates[2]; - blendStates->a[1][0][11][0] = deferredBlendStates[3]; - blendStates->a[2][0][1][0] = deferredBlendStates[4]; - blendStates->a[2][0][11][0] = deferredBlendStates[5]; - blendStates->a[3][0][11][0] = deferredBlendStates[6]; - - stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_ALPHA_BLEND); - deferredPass = true; } @@ -428,6 +415,8 @@ void Deferred::DeferredPasses() context->CSSetConstantBuffers(0, 1, &buffer); } + Skylighting::GetSingleton()->Bind(); + { FLOAT clr[4] = { 0., 0., 0., 1. }; context->ClearUnorderedAccessViewFloat(giTexture->uav.get(), clr); @@ -440,9 +429,11 @@ void Deferred::DeferredPasses() auto depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; auto shadowMask = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kSHADOW_MASK]; auto masks = renderer->GetRuntimeData().renderTargets[MASKS]; + auto masks2 = renderer->GetRuntimeData().renderTargets[MASKS2]; auto main = renderer->GetRuntimeData().renderTargets[forwardRenderTargets[0]]; auto normals = renderer->GetRuntimeData().renderTargets[forwardRenderTargets[2]]; + auto snow = renderer->GetRuntimeData().renderTargets[forwardRenderTargets[3]]; // Only render directional shadows if the game has a directional shadow caster auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; @@ -461,22 +452,40 @@ void Deferred::DeferredPasses() if (CloudShadows::GetSingleton()->loaded) { CloudShadows::GetSingleton()->DrawShadows(); } + + if (Skylighting::GetSingleton()->loaded) { + ID3D11ShaderResourceView* srvs[1]{ + Skylighting::GetSingleton()->skylightingTexture->srv.get(), + }; + + context->CSSetShaderResources(10, ARRAYSIZE(srvs), srvs); + } + + if (DynamicCubemaps::GetSingleton()->loaded) { + ID3D11ShaderResourceView* srvs[2]{ + DynamicCubemaps::GetSingleton()->envTexture->srv.get(), + DynamicCubemaps::GetSingleton()->envReflectionsTexture->srv.get(), + }; + + context->CSSetShaderResources(12, ARRAYSIZE(srvs), srvs); + } } { - ID3D11ShaderResourceView* srvs[7]{ + ID3D11ShaderResourceView* srvs[8]{ specular.SRV, albedo.SRV, reflectance.SRV, normalRoughness.SRV, shadowMask.SRV, depth.depthSRV, - masks.SRV + masks.SRV, + masks2.SRV }; context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); - ID3D11UnorderedAccessView* uavs[2]{ main.UAV, normals.UAV }; + ID3D11UnorderedAccessView* uavs[1]{ main.UAV }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetSamplers(0, 1, &linearSampler); @@ -487,8 +496,8 @@ void Deferred::DeferredPasses() float resolutionX = state->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; float resolutionY = state->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; - uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 32.0f); - uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 32.0f); + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); context->Dispatch(dispatchX, dispatchY, 1); } @@ -501,7 +510,7 @@ void Deferred::DeferredPasses() { { - ID3D11ShaderResourceView* srvs[8]{ + ID3D11ShaderResourceView* srvs[9]{ specular.SRV, albedo.SRV, reflectance.SRV, @@ -509,12 +518,13 @@ void Deferred::DeferredPasses() shadowMask.SRV, depth.depthSRV, masks.SRV, + masks2.SRV, giTexture->srv.get(), }; context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); - ID3D11UnorderedAccessView* uavs[2]{ main.UAV, normals.UAV }; + ID3D11UnorderedAccessView* uavs[1]{ main.UAV }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetSamplers(0, 1, &linearSampler); @@ -525,8 +535,8 @@ void Deferred::DeferredPasses() float resolutionX = state->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; float resolutionY = state->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; - uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 32.0f); - uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 32.0f); + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); context->Dispatch(dispatchX, dispatchY, 1); } @@ -538,7 +548,7 @@ void Deferred::DeferredPasses() { { - ID3D11ShaderResourceView* srvs[8]{ + ID3D11ShaderResourceView* srvs[9]{ specular.SRV, albedo.SRV, reflectance.SRV, @@ -546,12 +556,13 @@ void Deferred::DeferredPasses() shadowMask.SRV, depth.depthSRV, masks.SRV, + masks2.SRV, giTexture->srv.get(), }; context->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs); - ID3D11UnorderedAccessView* uavs[2]{ main.UAV, normals.UAV }; + ID3D11UnorderedAccessView* uavs[3]{ main.UAV, normals.UAV, snow.UAV }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); context->CSSetSamplers(0, 1, &linearSampler); @@ -562,17 +573,17 @@ void Deferred::DeferredPasses() float resolutionX = state->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; float resolutionY = state->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; - uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 32.0f); - uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 32.0f); + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); context->Dispatch(dispatchX, dispatchY, 1); } } - ID3D11ShaderResourceView* views[8]{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + ID3D11ShaderResourceView* views[9]{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; context->CSSetShaderResources(0, ARRAYSIZE(views), views); - ID3D11UnorderedAccessView* uavs[2]{ nullptr, nullptr }; + ID3D11UnorderedAccessView* uavs[3]{ nullptr, nullptr, nullptr }; context->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, nullptr); ID3D11Buffer* buffer = nullptr; @@ -613,6 +624,115 @@ void Deferred::EndDeferred() stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); // Run OMSetRenderTargets again + deferredPass = false; +} + +void Deferred::OverrideBlendStates() +{ + static bool setup = false; + if (!setup) { + auto& device = State::GetSingleton()->device; + + static BlendStates* blendStates = (BlendStates*)REL::RelocationID(524749, 411364).address(); + + { + forwardBlendStates[0] = blendStates->a[0][0][1][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[0]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[0])); + } + + { + forwardBlendStates[1] = blendStates->a[0][0][10][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[1]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[1])); + } + + { + forwardBlendStates[2] = blendStates->a[1][0][1][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[2]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[2])); + } + + { + forwardBlendStates[3] = blendStates->a[1][0][11][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[3]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[3])); + } + + { + forwardBlendStates[4] = blendStates->a[2][0][1][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[4]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[4])); + } + + { + forwardBlendStates[5] = blendStates->a[2][0][11][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[5]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[5])); + } + + { + forwardBlendStates[6] = blendStates->a[3][0][11][0]; + + D3D11_BLEND_DESC blendDesc; + forwardBlendStates[6]->GetDesc(&blendDesc); + + blendDesc.IndependentBlendEnable = false; + + DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &deferredBlendStates[6])); + } + setup = true; + } + + static BlendStates* blendStates = (BlendStates*)REL::RelocationID(524749, 411364).address(); + + // Set modified blend states + blendStates->a[0][0][1][0] = deferredBlendStates[0]; + blendStates->a[0][0][10][0] = deferredBlendStates[1]; + blendStates->a[1][0][1][0] = deferredBlendStates[2]; + blendStates->a[1][0][11][0] = deferredBlendStates[3]; + blendStates->a[2][0][1][0] = deferredBlendStates[4]; + blendStates->a[2][0][11][0] = deferredBlendStates[5]; + blendStates->a[3][0][11][0] = deferredBlendStates[6]; + + auto& state = State::GetSingleton()->shadowState; + GET_INSTANCE_MEMBER(stateUpdateFlags, state) + + stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_ALPHA_BLEND); +} + +void Deferred::ResetBlendStates() +{ static BlendStates* blendStates = (BlendStates*)REL::RelocationID(524749, 411364).address(); // Restore modified blend states @@ -624,9 +744,10 @@ void Deferred::EndDeferred() blendStates->a[2][0][11][0] = forwardBlendStates[5]; blendStates->a[3][0][11][0] = forwardBlendStates[6]; - stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_ALPHA_BLEND); + auto& state = State::GetSingleton()->shadowState; + GET_INSTANCE_MEMBER(stateUpdateFlags, state) - deferredPass = false; + stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_ALPHA_BLEND); } void Deferred::UpdatePerms() diff --git a/src/Deferred.h b/src/Deferred.h index 6af20ad4c..229d9c57c 100644 --- a/src/Deferred.h +++ b/src/Deferred.h @@ -2,12 +2,16 @@ #include "Buffer.h" #include "State.h" +#include +#include +#include #define ALBEDO RE::RENDER_TARGETS::kINDIRECT #define SPECULAR RE::RENDER_TARGETS::kINDIRECT_DOWNSCALED #define REFLECTANCE RE::RENDER_TARGETS::kRAWINDIRECT #define NORMALROUGHNESS RE::RENDER_TARGETS::kRAWINDIRECT_DOWNSCALED #define MASKS RE::RENDER_TARGETS::kRAWINDIRECT_PREVIOUS +#define MASKS2 RE::RENDER_TARGETS::kRAWINDIRECT_PREVIOUS_DOWNSCALED class Deferred { @@ -28,6 +32,8 @@ class Deferred void Reset(); void StartDeferred(); + void OverrideBlendStates(); + void ResetBlendStates(); void DeferredPasses(); void EndDeferred(); @@ -97,6 +103,7 @@ class Deferred static void thunk(RE::BSBatchRenderer* This, uint32_t StartRange, uint32_t EndRanges, uint32_t RenderFlags, int GeometryGroup) { // Here is where the first opaque objects start rendering + GetSingleton()->OverrideBlendStates(); GetSingleton()->StartDeferred(); func(This, StartRange, EndRanges, RenderFlags, GeometryGroup); // RenderBatches } @@ -109,17 +116,30 @@ class Deferred { func(This, RenderFlags); // After this point, water starts rendering + GetSingleton()->ResetBlendStates(); GetSingleton()->EndDeferred(); } static inline REL::Relocation func; }; + struct Main_RenderWorld_End_Decals + { + static void thunk(RE::BSShaderAccumulator* This, uint32_t RenderFlags) + { + GetSingleton()->ResetBlendStates(); + GetSingleton()->EndDeferred(); + // After this point, decals start rendering + func(This, RenderFlags); + } + 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)); logger::info("[Deferred] Installed hooks"); } diff --git a/src/Feature.cpp b/src/Feature.cpp index 8b1ac5f41..71d1f59cf 100644 --- a/src/Feature.cpp +++ b/src/Feature.cpp @@ -9,6 +9,7 @@ #include "Features/LightLimitFix.h" #include "Features/ScreenSpaceGI.h" #include "Features/ScreenSpaceShadows.h" +#include "Features/Skylighting.h" #include "Features/SubsurfaceScattering.h" #include "Features/TerrainBlending.h" #include "Features/TerrainOcclusion.h" @@ -16,6 +17,7 @@ #include "Features/WaterCaustics.h" #include "Features/WaterParallax.h" #include "Features/WetnessEffects.h" + #include "State.h" void Feature::Load(json&) @@ -118,7 +120,8 @@ const std::vector& Feature::GetFeatureList() WaterCaustics::GetSingleton(), SubsurfaceScattering::GetSingleton(), TerrainOcclusion::GetSingleton(), - ScreenSpaceGI::GetSingleton() + ScreenSpaceGI::GetSingleton(), + Skylighting::GetSingleton() }; static std::vector featuresVR(features); diff --git a/src/Features/CloudShadows.cpp b/src/Features/CloudShadows.cpp index f61f1e35e..b05b4d853 100644 --- a/src/Features/CloudShadows.cpp +++ b/src/Features/CloudShadows.cpp @@ -4,6 +4,7 @@ #include "Deferred.h" #include "Util.h" +#include NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( CloudShadows::Settings, @@ -13,19 +14,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( EffectMix, TransparencyPower) -enum class SkyShaderTechniques -{ - SunOcclude = 0, - SunGlare = 1, - MoonAndStarsMask = 2, - Stars = 3, - Clouds = 4, - CloudsLerp = 5, - CloudsFade = 6, - Texture = 7, - Sky = 8, -}; - void CloudShadows::DrawSettings() { ImGui::Checkbox("Enable Cloud Shadows", (bool*)&settings.EnableCloudShadows); @@ -75,7 +63,7 @@ void CloudShadows::CompileComputeShaders() { logger::debug("Compiling shaders..."); { - outputProgram = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\CloudShadows\\output.cs.hlsl", { {} }, "cs_5_0")); + outputProgram = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\CloudShadows\\output.cs.hlsl", {}, "cs_5_0")); } } @@ -98,24 +86,10 @@ void CloudShadows::ModifySky(const RE::BSShader*, const uint32_t descriptor) if (cubeMapRenderTarget != RE::RENDER_TARGETS_CUBEMAP::kREFLECTIONS) return; - enum class SkyShaderTechniques - { - SunOcclude = 0, - SunGlare = 1, - MoonAndStarsMask = 2, - Stars = 3, - Clouds = 4, - CloudsLerp = 5, - CloudsFade = 6, - Texture = 7, - Sky = 8, - }; - - auto tech_enum = static_cast(descriptor); - if (tech_enum == SkyShaderTechniques::Clouds || tech_enum == SkyShaderTechniques::CloudsLerp || tech_enum == SkyShaderTechniques::CloudsFade) { + auto tech_enum = static_cast(descriptor); + if (tech_enum == SIE::ShaderCache::SkyShaderTechniques::Clouds || tech_enum == SIE::ShaderCache::SkyShaderTechniques::CloudsLerp || tech_enum == SIE::ShaderCache::SkyShaderTechniques::CloudsFade) { auto renderer = RE::BSGraphics::Renderer::GetSingleton(); auto& context = State::GetSingleton()->context; - auto& device = State::GetSingleton()->device; { ID3D11ShaderResourceView* srv = nullptr; @@ -142,32 +116,6 @@ void CloudShadows::ModifySky(const RE::BSShader*, const uint32_t descriptor) rtvs[3] = cubemapCloudOccRTVs[side]; context->OMSetRenderTargets(4, rtvs, depthStencil); - - // blend states - - ID3D11BlendState* blendState = nullptr; - FLOAT blendFactor[4] = { 0 }; - UINT sampleMask = 0; - - context->OMGetBlendState(&blendState, blendFactor, &sampleMask); - - if (!mappedBlendStates.contains(blendState)) { - if (modifiedBlendStates.contains(blendState)) { - D3D11_BLEND_DESC blendDesc; - blendState->GetDesc(&blendDesc); - - blendDesc.RenderTarget[3] = blendDesc.RenderTarget[0]; - - ID3D11BlendState* modifiedBlendState; - DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, &modifiedBlendState)); - - mappedBlendStates.insert(modifiedBlendState); - modifiedBlendStates.insert({ blendState, modifiedBlendState }); - } - context->OMSetBlendState(modifiedBlendStates[blendState], blendFactor, sampleMask); - - resetBlendState = blendState; - } } } @@ -296,23 +244,4 @@ void CloudShadows::SetupResources() void CloudShadows::RestoreDefaultSettings() { settings = {}; -} - -void CloudShadows::Hooks::BSBatchRenderer__RenderPassImmediately::thunk(RE::BSRenderPass* Pass, uint32_t Technique, bool AlphaTest, uint32_t RenderFlags) -{ - auto feat = GetSingleton(); - auto& context = State::GetSingleton()->context; - - func(Pass, Technique, AlphaTest, RenderFlags); - - if (feat->resetBlendState) { - ID3D11BlendState* blendState = nullptr; - FLOAT blendFactor[4] = { 0 }; - UINT sampleMask = 0; - - context->OMGetBlendState(&blendState, blendFactor, &sampleMask); - context->OMSetBlendState(feat->resetBlendState, blendFactor, sampleMask); - - feat->resetBlendState = nullptr; - } -} +} \ No newline at end of file diff --git a/src/Features/CloudShadows.h b/src/Features/CloudShadows.h index 6099207dd..93f7ad4af 100644 --- a/src/Features/CloudShadows.h +++ b/src/Features/CloudShadows.h @@ -65,15 +65,8 @@ struct CloudShadows : Feature struct Hooks { - struct BSBatchRenderer__RenderPassImmediately - { - static void thunk(RE::BSRenderPass* Pass, uint32_t Technique, bool AlphaTest, uint32_t RenderFlags); - static inline REL::Relocation func; - }; - static void Install() { - stl::write_thunk_call(REL::RelocationID(100877, 107630).address() + REL::Relocate(0x1E5, 0xFD)); // need SE addr } }; }; diff --git a/src/Features/DynamicCubemaps.cpp b/src/Features/DynamicCubemaps.cpp index 946e11b1c..60939d23b 100644 --- a/src/Features/DynamicCubemaps.cpp +++ b/src/Features/DynamicCubemaps.cpp @@ -293,102 +293,112 @@ void DynamicCubemaps::DrawDeferred() } } -void DynamicCubemaps::UpdateCubemap() +void DynamicCubemaps::Inferrence(bool a_reflections) { auto renderer = RE::BSGraphics::Renderer::GetSingleton(); auto& context = State::GetSingleton()->context; - //if (!REL::Module::IsVR()) { - // auto imageSpaceManager = RE::ImageSpaceManager::GetSingleton(); - // imageSpaceManager->GetRuntimeData().BSImagespaceShaderApplyReflections->active = false; - //} - - { - ID3D11ShaderResourceView* view = nullptr; - context->PSSetShaderResources(64, 1, &view); - } - - if (nextTask == NextTask::kInferrence) { - nextTask = NextTask::kIrradiance; + // Infer local reflection information + ID3D11UnorderedAccessView* uav = envInferredTexture->uav.get(); - // Infer local reflection information - ID3D11UnorderedAccessView* uav = envInferredTexture->uav.get(); + context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + context->GenerateMips(envCaptureTexture->srv.get()); - context->GenerateMips(envCaptureTexture->srv.get()); + auto& cubemap = renderer->GetRendererData().cubemapRenderTargets[RE::RENDER_TARGETS_CUBEMAP::kREFLECTIONS]; - auto& cubemap = renderer->GetRendererData().cubemapRenderTargets[RE::RENDER_TARGETS_CUBEMAP::kREFLECTIONS]; + ID3D11ShaderResourceView* srvs[3] = { envCaptureTexture->srv.get(), cubemap.SRV, defaultCubemap }; + context->CSSetShaderResources(0, 3, srvs); - ID3D11ShaderResourceView* srvs[2] = { envCaptureTexture->srv.get(), activeReflections ? cubemap.SRV : defaultCubemap }; - context->CSSetShaderResources(0, 2, srvs); + context->CSSetSamplers(0, 1, &computeSampler); - context->CSSetSamplers(0, 1, &computeSampler); + context->CSSetShader(a_reflections ? GetComputeShaderInferrenceReflections() : GetComputeShaderInferrence(), nullptr, 0); - context->CSSetShader(activeReflections ? GetComputeShaderInferrenceReflections() : GetComputeShaderInferrence(), nullptr, 0); + context->Dispatch((uint32_t)std::ceil(envCaptureTexture->desc.Width / 32.0f), (uint32_t)std::ceil(envCaptureTexture->desc.Height / 32.0f), 6); - context->Dispatch((uint32_t)std::ceil(envCaptureTexture->desc.Width / 32.0f), (uint32_t)std::ceil(envCaptureTexture->desc.Height / 32.0f), 6); + srvs[0] = nullptr; + srvs[1] = nullptr; + srvs[2] = nullptr; + context->CSSetShaderResources(0, 3, srvs); - srvs[0] = nullptr; - srvs[1] = nullptr; - context->CSSetShaderResources(0, 2, srvs); + uav = nullptr; - uav = nullptr; + context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + context->CSSetShader(nullptr, 0, 0); - context->CSSetShader(nullptr, 0, 0); + ID3D11SamplerState* sampler = nullptr; + context->CSSetSamplers(0, 1, &sampler); +} - ID3D11SamplerState* sampler = nullptr; - context->CSSetSamplers(0, 1, &sampler); - } else if (nextTask == NextTask::kIrradiance) { - nextTask = NextTask::kCapture; +void DynamicCubemaps::Irradiance(bool a_reflections) +{ + auto& context = State::GetSingleton()->context; - // Copy cubemap to other resources - for (uint face = 0; face < 6; face++) { - uint srcSubresourceIndex = D3D11CalcSubresource(0, face, MIPLEVELS); - context->CopySubresourceRegion(envTexture->resource.get(), D3D11CalcSubresource(0, face, MIPLEVELS), 0, 0, 0, envInferredTexture->resource.get(), srcSubresourceIndex, nullptr); - } + // Copy cubemap to other resources + for (uint face = 0; face < 6; face++) { + uint srcSubresourceIndex = D3D11CalcSubresource(0, face, MIPLEVELS); + context->CopySubresourceRegion(a_reflections ? envReflectionsTexture->resource.get() : envTexture->resource.get(), D3D11CalcSubresource(0, face, MIPLEVELS), 0, 0, 0, envInferredTexture->resource.get(), srcSubresourceIndex, nullptr); + } - // Compute pre-filtered specular environment map. - { - auto srv = envInferredTexture->srv.get(); - context->GenerateMips(srv); + // Compute pre-filtered specular environment map. + { + auto srv = envInferredTexture->srv.get(); + context->GenerateMips(srv); - context->CSSetShaderResources(0, 1, &srv); - context->CSSetSamplers(0, 1, &computeSampler); - context->CSSetShader(GetComputeShaderSpecularIrradiance(), nullptr, 0); + context->CSSetShaderResources(0, 1, &srv); + context->CSSetSamplers(0, 1, &computeSampler); + context->CSSetShader(GetComputeShaderSpecularIrradiance(), nullptr, 0); - ID3D11Buffer* buffer = spmapCB->CB(); - context->CSSetConstantBuffers(0, 1, &buffer); + ID3D11Buffer* buffer = spmapCB->CB(); + context->CSSetConstantBuffers(0, 1, &buffer); - float const delta_roughness = 1.0f / std::max(float(MIPLEVELS - 1), 1.0f); + float const delta_roughness = 1.0f / std::max(float(MIPLEVELS - 1), 1.0f); - std::uint32_t size = std::max(envTexture->desc.Width, envTexture->desc.Height); + std::uint32_t size = std::max(envTexture->desc.Width, envTexture->desc.Height); - for (std::uint32_t level = 1; level < MIPLEVELS; level++, size /= 2) { - const UINT numGroups = (UINT)std::max(1u, size / 32); + for (std::uint32_t level = 1; level < MIPLEVELS; level++, size /= 2) { + const UINT numGroups = (UINT)std::max(1u, size / 32); - const SpecularMapFilterSettingsCB spmapConstants = { level * delta_roughness }; - spmapCB->Update(spmapConstants); + const SpecularMapFilterSettingsCB spmapConstants = { level * delta_roughness }; + spmapCB->Update(spmapConstants); - auto uav = uavArray[level - 1]; + auto uav = a_reflections ? uavReflectionsArray[level - 1] : uavArray[level - 1]; - context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); - context->Dispatch(numGroups, numGroups, 6); - } + context->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); + context->Dispatch(numGroups, numGroups, 6); } + } + + ID3D11ShaderResourceView* nullSRV = { nullptr }; + ID3D11SamplerState* nullSampler = { nullptr }; + ID3D11Buffer* nullBuffer = { nullptr }; + ID3D11UnorderedAccessView* nullUAV = { nullptr }; - ID3D11ShaderResourceView* nullSRV = { nullptr }; - ID3D11SamplerState* nullSampler = { nullptr }; - ID3D11Buffer* nullBuffer = { nullptr }; - ID3D11UnorderedAccessView* nullUAV = { nullptr }; + context->CSSetShaderResources(0, 1, &nullSRV); + context->CSSetSamplers(0, 1, &nullSampler); + context->CSSetShader(nullptr, 0, 0); + context->CSSetConstantBuffers(0, 1, &nullBuffer); + context->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr); +} - context->CSSetShaderResources(0, 1, &nullSRV); - context->CSSetSamplers(0, 1, &nullSampler); - context->CSSetShader(nullptr, 0, 0); - context->CSSetConstantBuffers(0, 1, &nullBuffer); - context->CSSetUnorderedAccessViews(0, 1, &nullUAV, nullptr); +void DynamicCubemaps::UpdateCubemap() +{ + if (nextTask == NextTask::kInferrence) { + nextTask = NextTask::kIrradiance; + Inferrence(false); + } else if (nextTask == NextTask::kIrradiance) { + if (activeReflections) + nextTask = NextTask::kInferrence2; + else + nextTask = NextTask::kCapture; + Irradiance(false); + } else if (nextTask == NextTask::kInferrence2) { + Inferrence(true); + nextTask = NextTask::kIrradiance2; + } else if (nextTask == NextTask::kIrradiance2) { + nextTask = NextTask::kCapture; + Irradiance(true); } } @@ -492,6 +502,10 @@ void DynamicCubemaps::SetupResources() envTexture->CreateSRV(srvDesc); envTexture->CreateUAV(uavDesc); + envReflectionsTexture = new Texture2D(texDesc); + envReflectionsTexture->CreateSRV(srvDesc); + envReflectionsTexture->CreateUAV(uavDesc); + envInferredTexture = new Texture2D(texDesc); envInferredTexture->CreateSRV(srvDesc); envInferredTexture->CreateUAV(uavDesc); @@ -515,6 +529,11 @@ void DynamicCubemaps::SetupResources() uavDesc.Texture2DArray.MipSlice = level; DX::ThrowIfFailed(device->CreateUnorderedAccessView(envTexture->resource.get(), &uavDesc, &uavArray[level - 1])); } + + for (std::uint32_t level = 1; level < MIPLEVELS; ++level) { + uavDesc.Texture2DArray.MipSlice = level; + DX::ThrowIfFailed(device->CreateUnorderedAccessView(envReflectionsTexture->resource.get(), &uavDesc, &uavReflectionsArray[level - 1])); + } } { diff --git a/src/Features/DynamicCubemaps.h b/src/Features/DynamicCubemaps.h index 302dc96ac..739daafd5 100644 --- a/src/Features/DynamicCubemaps.h +++ b/src/Features/DynamicCubemaps.h @@ -35,7 +35,9 @@ struct DynamicCubemaps : Feature ID3D11ComputeShader* specularIrradianceCS = nullptr; ConstantBuffer* spmapCB = nullptr; Texture2D* envTexture = nullptr; + Texture2D* envReflectionsTexture = nullptr; ID3D11UnorderedAccessView* uavArray[9]; + ID3D11UnorderedAccessView* uavReflectionsArray[9]; // Reflection capture @@ -66,7 +68,9 @@ struct DynamicCubemaps : Feature { kCapture, kInferrence, - kIrradiance + kInferrence2, + kIrradiance, + kIrradiance2 }; NextTask nextTask = NextTask::kCapture; @@ -129,5 +133,9 @@ struct DynamicCubemaps : Feature virtual void DrawDeferred(); + void Inferrence(bool a_reflections); + + void Irradiance(bool a_reflections); + bool SupportsVR() override { return true; }; }; diff --git a/src/Features/ScreenSpaceGI.cpp b/src/Features/ScreenSpaceGI.cpp index 559bfd98a..0b45e9c4b 100644 --- a/src/Features/ScreenSpaceGI.cpp +++ b/src/Features/ScreenSpaceGI.cpp @@ -1,4 +1,5 @@ #include "ScreenSpaceGI.h" +#include "Menu.h" #include "Deferred.h" #include "State.h" @@ -29,7 +30,11 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( AOPower, GIStrength, DepthDisocclusion, - MaxAccumFrames) + NormalDisocclusion, + MaxAccumFrames, + BlurRadius, + BlurPasses, + DistanceNormalisation) class DisableGuard { @@ -67,9 +72,13 @@ void ScreenSpaceGI::RestoreDefaultSettings() void ScreenSpaceGI::DrawSettings() { + static bool showAdvanced; + /////////////////////////////// ImGui::SeparatorText("Toggles"); + ImGui::Checkbox("Show Advanced Options", &showAdvanced); + if (ImGui::BeginTable("Toggles", 3)) { ImGui::TableNextColumn(); ImGui::Checkbox("Enabled", &settings.Enabled); @@ -94,17 +103,14 @@ void ScreenSpaceGI::DrawSettings() if (auto _tt = Util::HoverTooltipWrapper()) ImGui::Text("How many samples does it take in one direction. A greater value enhances the effects but is more expensive."); - ImGui::SliderFloat("MIP Sampling Offset", &settings.DepthMIPSamplingOffset, 2.f, 6.f, "%.2f"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("Mainly performance (texture memory bandwidth) setting but as a side-effect reduces overshadowing by thin objects and increases temporal instability."); - - if (ImGui::BeginTable("Quality Toggles", 2)) { - ImGui::TableNextColumn(); - recompileFlag |= ImGui::Checkbox("Half Resolution", &settings.HalfRes); - - ImGui::EndTable(); + if (showAdvanced) { + ImGui::SliderFloat("MIP Sampling Offset", &settings.DepthMIPSamplingOffset, 2.f, 6.f, "%.2f"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("Mainly performance (texture memory bandwidth) setting but as a side-effect reduces overshadowing by thin objects and increases temporal instability."); } + recompileFlag |= ImGui::Checkbox("Half Resolution", &settings.HalfRes); + /////////////////////////////// ImGui::SeparatorText("Visual"); @@ -124,25 +130,28 @@ void ScreenSpaceGI::DrawSettings() ImGui::SliderFloat2("Depth Fade Range", &settings.DepthFadeRange.x, 1e4, 5e4, "%.0f game units"); - ImGui::Separator(); - - { - auto _ = DisableGuard(settings.UseBitmask); + if (showAdvanced) { + ImGui::Separator(); + { + auto _ = DisableGuard(settings.UseBitmask); - ImGui::SliderFloat("Falloff Range", &settings.EffectFalloffRange, 0.05f, 1.0f, "%.2f"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("Gently reduce sample impact as it gets out of 'Effect radius' bounds"); + ImGui::SliderFloat("Falloff Range", &settings.EffectFalloffRange, 0.05f, 1.0f, "%.2f"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("Gently reduce sample impact as it gets out of 'Effect radius' bounds"); - ImGui::SliderFloat("Thin Occluder Compensation", &settings.ThinOccluderCompensation, 0.f, 0.7f, "%.2f"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("Slightly reduce impact of samples further back to counter the bias from depth-based (incomplete) input scene geometry data"); - } - { - auto _ = DisableGuard(!settings.UseBitmask); + if (showAdvanced) { + ImGui::SliderFloat("Thin Occluder Compensation", &settings.ThinOccluderCompensation, 0.f, 0.7f, "%.2f"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("Slightly reduce impact of samples further back to counter the bias from depth-based (incomplete) input scene geometry data"); + } + } + { + auto _ = DisableGuard(!settings.UseBitmask); - ImGui::SliderFloat("Thickness", &settings.Thickness, 0.f, 500.0f, "%.1f game units"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("How thick the occluders are. 20 to 30 percent of effect radius is recommended."); + ImGui::SliderFloat("Thickness", &settings.Thickness, 0.f, 500.0f, "%.1f game units"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("How thick the occluders are. 20 to 30 percent of effect radius is recommended."); + } } /////////////////////////////// @@ -151,17 +160,19 @@ void ScreenSpaceGI::DrawSettings() { auto _ = DisableGuard(!settings.EnableGI); - ImGui::SliderFloat("GI Distance Compensation", &settings.GIDistanceCompensation, 0.0f, 9.0f, "%.1f"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text( - "Brighten up further radiance samples that are otherwise too weak. Creates a wider GI look.\n" - "If using bitmask, this value should be roughly inverse to thickness."); + if (showAdvanced) { + ImGui::SliderFloat("GI Distance Compensation", &settings.GIDistanceCompensation, 0.0f, 9.0f, "%.1f"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text( + "Brighten up further radiance samples that are otherwise too weak. Creates a wider GI look.\n" + "If using bitmask, this value should be roughly inverse to thickness."); - ImGui::SliderFloat("GI Compensation Distance", &settings.GICompensationMaxDist, 10.0f, 500.0f, "%.1f game units"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("The distance of maximal compensation/brightening."); + ImGui::SliderFloat("GI Compensation Distance", &settings.GICompensationMaxDist, 10.0f, 500.0f, "%.1f game units"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("The distance of maximal compensation/brightening."); - ImGui::Separator(); + ImGui::Separator(); + } recompileFlag |= ImGui::Checkbox("GI Bounce", &settings.EnableGIBounce); if (auto _tt = Util::HoverTooltipWrapper()) @@ -176,18 +187,20 @@ void ScreenSpaceGI::DrawSettings() ImGui::Text("How much of this frame's GI gets carried to the next frame."); } - ImGui::Separator(); + if (showAdvanced) { + ImGui::Separator(); - recompileFlag |= ImGui::Checkbox("Backface Checks", &settings.CheckBackface); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("Disable to get some frames, IF you don't care about light emitting from the back of objects."); - { - auto __ = DisableGuard(!settings.CheckBackface); - ImGui::Indent(); - percentageSlider("Backface Lighting Mix", &settings.BackfaceStrength); - ImGui::Unindent(); + recompileFlag |= ImGui::Checkbox("Backface Checks", &settings.CheckBackface); if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("How bright at the back of objects is compared to the front. A small value to make up for foliage translucency."); + ImGui::Text("Disable to get some frames, IF you don't care about light emitting from the back of objects."); + { + auto __ = DisableGuard(!settings.CheckBackface); + ImGui::Indent(); + percentageSlider("Backface Lighting Mix", &settings.BackfaceStrength); + ImGui::Unindent(); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("How bright at the back of objects is compared to the front. A small value to make up for foliage translucency."); + } } } @@ -196,29 +209,61 @@ void ScreenSpaceGI::DrawSettings() ImGui::TextWrapped("At full resolution, you can try disabling denoisers and let TAA handle the noise."); - recompileFlag |= ImGui::Checkbox("Temporal Denoiser", &settings.EnableTemporalDenoiser); + if (ImGui::BeginTable("denoisers", 2)) { + ImGui::TableNextColumn(); + recompileFlag |= ImGui::Checkbox("Temporal Denoiser", &settings.EnableTemporalDenoiser); + + ImGui::TableNextColumn(); + ImGui::Checkbox("Blur", &settings.EnableBlur); - { - auto _ = DisableGuard(!settings.EnableTemporalDenoiser); - ImGui::Indent(); - ImGui::SliderInt("Max Frame Accumulation", (int*)&settings.MaxAccumFrames, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); - ImGui::Unindent(); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("How many past frames to accumulate results with. Higher values are less noisy but potentially cause ghosting."); + ImGui::EndTable(); } - // ImGui::SliderInt("Passes", (int*)&settings.DenoisePasses, 0, 10); - // if (auto _tt = Util::HoverTooltipWrapper()) - // ImGui::Text("How many denoising passes to go through. The more the blurrier."); + if (showAdvanced) { + ImGui::Separator(); - { - auto _ = DisableGuard(!settings.EnableTemporalDenoiser && !(settings.EnableGI || settings.EnableGIBounce)); + { + auto _ = DisableGuard(!settings.EnableTemporalDenoiser); + ImGui::SliderInt("Max Frame Accumulation", (int*)&settings.MaxAccumFrames, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("How many past frames to accumulate results with. Higher values are less noisy but potentially cause ghosting."); + } - ImGui::SliderFloat("Movement Disocclusion", &settings.DepthDisocclusion, 0.f, 100.f, "%.1f game units"); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text( - "If a pixel has moved this far from the last frame, its radiance will not be carried to this frame.\n" - "Lower values are stricter."); + ImGui::Separator(); + + { + auto _ = DisableGuard(!settings.EnableTemporalDenoiser && !(settings.EnableGI || settings.EnableGIBounce)); + + ImGui::SliderFloat("Movement Disocclusion", &settings.DepthDisocclusion, 0.f, 100.f, "%.1f game units"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text( + "If a pixel has moved this far from the last frame, its radiance will not be carried to this frame.\n" + "Lower values are stricter."); + + ImGui::SliderFloat("Normal Disocclusion", &settings.NormalDisocclusion, 0.f, 1.f, "%.3f", ImGuiSliderFlags_AlwaysClamp); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text( + "If a pixel's normal deviates too much from the last frame, its radiance will not be carried to this frame.\n" + "Higher values are stricter."); + + ImGui::Separator(); + } + + { + auto _ = DisableGuard(!settings.EnableBlur); + ImGui::SliderFloat("Blur Radius", &settings.BlurRadius, 0.f, 8.f, "%.1f px"); + + ImGui::SliderInt("Blur Passes", (int*)&settings.BlurPasses, 1, 3, "%d", ImGuiSliderFlags_AlwaysClamp); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text("Blurring repeatedly for x times."); + + if (showAdvanced) { + ImGui::SliderFloat("Geometry Weight", &settings.DistanceNormalisation, 0.f, .1f, "%.4f"); + if (auto _tt = Util::HoverTooltipWrapper()) + ImGui::Text( + "Higher value makes the blur more sensitive to differences in geometry."); + } + } } /////////////////////////////// @@ -228,35 +273,13 @@ void ScreenSpaceGI::DrawSettings() static float debugRescale = .3f; ImGui::SliderFloat("View Resize", &debugRescale, 0.f, 1.f); - // ImGui doesn't support U32 - // if (ImGui::TreeNode("texHilbertLUT")) { - // ImGui::Image(texHilbertLUT->srv.get(), { (float)texHilbertLUT->desc.Width, (float)texHilbertLUT->desc.Height }); - // ImGui::TreePop(); - // } - if (ImGui::TreeNode("texWorkingDepth")) { - ImGui::Image(texWorkingDepth->srv.get(), { texWorkingDepth->desc.Width * debugRescale, texWorkingDepth->desc.Height * debugRescale }); - ImGui::TreePop(); - } - if (ImGui::TreeNode("texPrevDepth")) { - ImGui::Image(texPrevDepth->srv.get(), { texPrevDepth->desc.Width * debugRescale, texPrevDepth->desc.Height * debugRescale }); - ImGui::TreePop(); - } - if (ImGui::TreeNode("texRadiance")) { - ImGui::Image(texRadiance->srv.get(), { texRadiance->desc.Width * debugRescale, texRadiance->desc.Height * debugRescale }); - ImGui::TreePop(); - } - if (ImGui::TreeNode("texGI0")) { - ImGui::Image(texGI0->srv.get(), { texGI0->desc.Width * debugRescale, texGI0->desc.Height * debugRescale }); - ImGui::TreePop(); - } - if (ImGui::TreeNode("texGI1")) { - ImGui::Image(texGI1->srv.get(), { texGI1->desc.Width * debugRescale, texGI1->desc.Height * debugRescale }); - ImGui::TreePop(); - } - if (ImGui::TreeNode("texPrevGIAlbedo")) { - ImGui::Image(texPrevGIAlbedo->srv.get(), { texPrevGIAlbedo->desc.Width * debugRescale, texPrevGIAlbedo->desc.Height * debugRescale }); - ImGui::TreePop(); - } + //BUFFER_VIEWER_NODE(texHilbertLUT, debugRescale) + BUFFER_VIEWER_NODE(texWorkingDepth, debugRescale) + BUFFER_VIEWER_NODE(texPrevGeo, debugRescale) + BUFFER_VIEWER_NODE(texRadiance, debugRescale) + BUFFER_VIEWER_NODE(texGI[0], debugRescale) + BUFFER_VIEWER_NODE(texGI[1], debugRescale) + BUFFER_VIEWER_NODE(texPrevGIAlbedo, debugRescale) ImGui::TreePop(); } @@ -348,13 +371,13 @@ void ScreenSpaceGI::SetupResources() texDesc.MipLevels = srvDesc.Texture2D.MipLevels = 1; srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; { - texGI0 = eastl::make_unique(texDesc); - texGI0->CreateSRV(srvDesc); - texGI0->CreateUAV(uavDesc); + texGI[0] = eastl::make_unique(texDesc); + texGI[0]->CreateSRV(srvDesc); + texGI[0]->CreateUAV(uavDesc); - texGI1 = eastl::make_unique(texDesc); - texGI1->CreateSRV(srvDesc); - texGI1->CreateUAV(uavDesc); + texGI[1] = eastl::make_unique(texDesc); + texGI[1]->CreateSRV(srvDesc); + texGI[1]->CreateUAV(uavDesc); } srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R11G11B10_FLOAT; @@ -364,18 +387,22 @@ void ScreenSpaceGI::SetupResources() texPrevGIAlbedo->CreateUAV(uavDesc); } - srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R8_UINT; + srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R8_UNORM; { - texAccumFrames = eastl::make_unique(texDesc); - texAccumFrames->CreateSRV(srvDesc); - texAccumFrames->CreateUAV(uavDesc); + texAccumFrames[0] = eastl::make_unique(texDesc); + texAccumFrames[0]->CreateSRV(srvDesc); + texAccumFrames[0]->CreateUAV(uavDesc); + + texAccumFrames[1] = eastl::make_unique(texDesc); + texAccumFrames[1]->CreateSRV(srvDesc); + texAccumFrames[1]->CreateUAV(uavDesc); } - srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R16_FLOAT; + srvDesc.Format = uavDesc.Format = texDesc.Format = DXGI_FORMAT_R11G11B10_FLOAT; { - texPrevDepth = eastl::make_unique(texDesc); - texPrevDepth->CreateSRV(srvDesc); - texPrevDepth->CreateUAV(uavDesc); + texPrevGeo = eastl::make_unique(texDesc); + texPrevGeo->CreateSRV(srvDesc); + texPrevGeo->CreateUAV(uavDesc); } } @@ -402,7 +429,7 @@ void ScreenSpaceGI::SetupResources() void ScreenSpaceGI::ClearShaderCache() { static const std::vector*> shaderPtrs = { - &hilbertLutCompute, &prefilterDepthsCompute, &radianceDisoccCompute, &giCompute, &upsampleCompute, &outputCompute + &hilbertLutCompute, &prefilterDepthsCompute, &radianceDisoccCompute, &giCompute, &blurCompute, &upsampleCompute, &outputCompute }; for (auto shader : shaderPtrs) @@ -429,6 +456,7 @@ void ScreenSpaceGI::CompileComputeShaders() { &prefilterDepthsCompute, "prefilterDepths.cs.hlsl", {} }, { &radianceDisoccCompute, "radianceDisocc.cs.hlsl", {} }, { &giCompute, "gi.cs.hlsl", {} }, + { &blurCompute, "blur.cs.hlsl", {} }, { &upsampleCompute, "upsample.cs.hlsl", {} }, { &outputCompute, "output.cs.hlsl", {} } }; @@ -461,7 +489,7 @@ void ScreenSpaceGI::CompileComputeShaders() bool ScreenSpaceGI::ShadersOK() { - return hilbertLutCompute && prefilterDepthsCompute && radianceDisoccCompute && giCompute && upsampleCompute && outputCompute; + return hilbertLutCompute && prefilterDepthsCompute && radianceDisoccCompute && giCompute && blurCompute && upsampleCompute && outputCompute; } void ScreenSpaceGI::GenerateHilbertLUT() @@ -486,13 +514,11 @@ void ScreenSpaceGI::UpdateSB() auto viewport = RE::BSGraphics::State::GetSingleton(); auto& state = State::GetSingleton()->shadowState; - uint resolution[2] = { - (uint)(State::GetSingleton()->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale), - (uint)(State::GetSingleton()->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale) - }; - uint halfRes[2] = { (resolution[0] + 1) >> 1, (resolution[1] + 1) >> 1 }; - - float2 res = settings.HalfRes ? float2{ (float)halfRes[0], (float)halfRes[1] } : float2{ (float)resolution[0], (float)resolution[1] }; + float2 res = { (float)texRadiance->desc.Width, (float)texRadiance->desc.Height }; + float2 dynres = res * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; + dynres = { floor(dynres.x), floor(dynres.y) }; + float2 halfres = dynres * 0.5; + halfres = { floor(halfres.x), floor(halfres.y) }; static float4x4 prevInvView[2] = {}; @@ -504,15 +530,18 @@ void ScreenSpaceGI::UpdateSB() data.PrevInvViewMat[eyeIndex] = prevInvView[eyeIndex]; data.NDCToViewMul[eyeIndex] = { 2.0f / eye.projMat(0, 0), -2.0f / eye.projMat(1, 1) }; data.NDCToViewAdd[eyeIndex] = { -1.0f / eye.projMat(0, 0), 1.0f / eye.projMat(1, 1) }; - data.NDCToViewMul_x_PixelSize[eyeIndex] = data.NDCToViewMul[eyeIndex] / res; if (REL::Module::IsVR()) data.NDCToViewMul[eyeIndex].x *= 2; prevInvView[eyeIndex] = eye.viewMat.Invert(); } - data.FrameDim = res; - data.RcpFrameDim = float2(1.0f) / res; + data.TexDim = res; + data.RcpTexDim = float2(1.0f) / res; + data.SrcFrameDim = dynres; + data.RcpSrcFrameDim = float2(1.0f) / dynres; + data.OutFrameDim = settings.HalfRes ? halfres : dynres; + data.RcpOutFrameDim = float2(1.0f) / (settings.HalfRes ? halfres : dynres); data.FrameIndex = viewport->uiFrameCount; data.NumSlices = settings.NumSlices; @@ -535,7 +564,10 @@ void ScreenSpaceGI::UpdateSB() data.GIStrength = settings.GIStrength; data.DepthDisocclusion = settings.DepthDisocclusion; + data.NormalDisocclusion = settings.NormalDisocclusion; data.MaxAccumFrames = settings.MaxAccumFrames; + data.BlurRadius = settings.BlurRadius; + data.DistanceNormalisation = settings.DistanceNormalisation; } ssgiCB->Update(data); @@ -546,6 +578,10 @@ void ScreenSpaceGI::DrawSSGI(Texture2D* outGI) if (!(settings.Enabled && ShadersOK())) return; + static uint lastFrameGITexIdx = 0; + static uint lastFrameAccumTexIdx = 0; + uint inputGITexIdx = lastFrameGITexIdx; + ////////////////////////////////////////////////////// if (recompileFlag) @@ -571,7 +607,7 @@ void ScreenSpaceGI::DrawSSGI(Texture2D* outGI) uint halfRes[2] = { resolution[0] >> 1, resolution[1] >> 1 }; auto targetRes = settings.HalfRes ? halfRes : resolution; - std::array srvs = { nullptr }; + std::array srvs = { nullptr }; std::array uavs = { nullptr }; std::array samplers = { pointClampSampler.get(), linearClampSampler.get() }; auto cb = ssgiCB->CB(); @@ -591,9 +627,9 @@ void ScreenSpaceGI::DrawSSGI(Texture2D* outGI) // prefilter depths { - srvs[0] = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY].depthSRV; + srvs.at(0) = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY].depthSRV; for (int i = 0; i < 5; ++i) - uavs[i] = uavWorkingDepth[i].get(); + uavs.at(i) = uavWorkingDepth[i].get(); context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); @@ -604,17 +640,18 @@ void ScreenSpaceGI::DrawSSGI(Texture2D* outGI) // fetch radiance and disocclusion { resetViews(); - srvs[0] = rts[deferred->forwardRenderTargets[0]].SRV; - srvs[1] = texGI0->srv.get(); - srvs[2] = texWorkingDepth->srv.get(); - srvs[3] = rts[NORMALROUGHNESS].SRV; - srvs[4] = texPrevDepth->srv.get(); - srvs[5] = rts[RE::RENDER_TARGET::kMOTION_VECTOR].SRV; - srvs[6] = texPrevGIAlbedo->srv.get(); - - uavs[0] = texRadiance->uav.get(); - uavs[1] = texAccumFrames->uav.get(); - uavs[2] = texGI1->uav.get(); + srvs.at(0) = rts[deferred->forwardRenderTargets[0]].SRV; + srvs.at(1) = texGI[inputGITexIdx]->srv.get(); + srvs.at(2) = texWorkingDepth->srv.get(); + srvs.at(3) = rts[NORMALROUGHNESS].SRV; + srvs.at(4) = texPrevGeo->srv.get(); + srvs.at(5) = rts[RE::RENDER_TARGET::kMOTION_VECTOR].SRV; + srvs.at(6) = texPrevGIAlbedo->srv.get(); + srvs.at(7) = texAccumFrames[lastFrameAccumTexIdx]->srv.get(); + + uavs.at(0) = texRadiance->uav.get(); + uavs.at(1) = texAccumFrames[!lastFrameAccumTexIdx]->uav.get(); + uavs.at(2) = texGI[!inputGITexIdx]->uav.get(); context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); @@ -622,50 +659,81 @@ void ScreenSpaceGI::DrawSSGI(Texture2D* outGI) context->Dispatch((targetRes[0] + 7u) >> 3, (targetRes[1] + 7u) >> 3, 1); context->GenerateMips(texRadiance->srv.get()); + + inputGITexIdx = !inputGITexIdx; + lastFrameAccumTexIdx = !lastFrameAccumTexIdx; } // GI { resetViews(); - srvs[0] = texWorkingDepth->srv.get(); - srvs[1] = rts[NORMALROUGHNESS].SRV; - srvs[2] = texRadiance->srv.get(); - srvs[3] = texHilbertLUT->srv.get(); - srvs[4] = texAccumFrames->srv.get(); - srvs[5] = texGI1->srv.get(); + srvs.at(0) = texWorkingDepth->srv.get(); + srvs.at(1) = rts[NORMALROUGHNESS].SRV; + srvs.at(2) = texRadiance->srv.get(); + srvs.at(3) = texHilbertLUT->srv.get(); + srvs.at(4) = texAccumFrames[lastFrameAccumTexIdx]->srv.get(); + srvs.at(5) = texGI[inputGITexIdx]->srv.get(); - uavs[0] = texGI0->uav.get(); - uavs[1] = nullptr; - uavs[2] = texPrevDepth->uav.get(); + uavs.at(0) = texGI[!inputGITexIdx]->uav.get(); + uavs.at(1) = nullptr; + uavs.at(2) = texPrevGeo->uav.get(); context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); context->CSSetShader(giCompute.get(), nullptr, 0); context->Dispatch((targetRes[0] + 7u) >> 3, (targetRes[1] + 7u) >> 3, 1); + + inputGITexIdx = !inputGITexIdx; + lastFrameGITexIdx = inputGITexIdx; + } + + // blur + if (settings.EnableBlur) { + for (uint i = 0; i < settings.BlurPasses; i++) { + resetViews(); + srvs.at(0) = texGI[inputGITexIdx]->srv.get(); + srvs.at(1) = texAccumFrames[lastFrameAccumTexIdx]->srv.get(); + srvs.at(2) = texWorkingDepth->srv.get(); + srvs.at(3) = rts[NORMALROUGHNESS].SRV; + + uavs.at(0) = texGI[!inputGITexIdx]->uav.get(); + uavs.at(1) = texAccumFrames[!lastFrameAccumTexIdx]->uav.get(); + + context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); + context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); + context->CSSetShader(blurCompute.get(), nullptr, 0); + context->Dispatch((targetRes[0] + 7u) >> 3, (targetRes[1] + 7u) >> 3, 1); + + inputGITexIdx = !inputGITexIdx; + lastFrameGITexIdx = inputGITexIdx; + lastFrameAccumTexIdx = !lastFrameAccumTexIdx; + } } // upsasmple if (settings.HalfRes) { resetViews(); - srvs[0] = texWorkingDepth->srv.get(); - srvs[1] = texGI0->srv.get(); + srvs.at(0) = texWorkingDepth->srv.get(); + srvs.at(1) = texGI[inputGITexIdx]->srv.get(); - uavs[0] = texGI1->uav.get(); + uavs.at(0) = texGI[!inputGITexIdx]->uav.get(); context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); context->CSSetShader(upsampleCompute.get(), nullptr, 0); context->Dispatch((resolution[0] + 7u) >> 3, (resolution[1] + 7u) >> 3, 1); + + inputGITexIdx = !inputGITexIdx; } // output { resetViews(); - srvs[0] = settings.HalfRes ? texGI1->srv.get() : texGI0->srv.get(); - srvs[1] = rts[ALBEDO].SRV; + srvs.at(0) = texGI[inputGITexIdx]->srv.get(); + srvs.at(1) = rts[ALBEDO].SRV; - uavs[0] = outGI->uav.get(); - uavs[1] = texPrevGIAlbedo->uav.get(); + uavs.at(0) = outGI->uav.get(); + uavs.at(1) = texPrevGIAlbedo->uav.get(); context->CSSetShaderResources(0, (uint)srvs.size(), srvs.data()); context->CSSetUnorderedAccessViews(0, (uint)uavs.size(), uavs.data(), nullptr); diff --git a/src/Features/ScreenSpaceGI.h b/src/Features/ScreenSpaceGI.h index 7a0a3142e..ab9aa6d6a 100644 --- a/src/Features/ScreenSpaceGI.h +++ b/src/Features/ScreenSpaceGI.h @@ -44,12 +44,11 @@ struct ScreenSpaceGI : Feature bool EnableGI = true; // performance/quality uint NumSlices = 2; - uint NumSteps = 5; + uint NumSteps = 3; bool HalfRes = true; - // float SampleDistributionPower = 1.f; float DepthMIPSamplingOffset = 3.3f; // visual - float EffectRadius = 200.f; // world (viewspace) maximum size of the shadow + float EffectRadius = 200.f; float EffectFalloffRange = .615f; float ThinOccluderCompensation = 0.f; float Thickness = 50.f; @@ -66,8 +65,13 @@ struct ScreenSpaceGI : Feature float GIStrength = 8.f; // denoise bool EnableTemporalDenoiser = true; + bool EnableBlur = true; float DepthDisocclusion = 50.f; + float NormalDisocclusion = .3f; uint MaxAccumFrames = 16; + float BlurRadius = 6.f; + uint BlurPasses = 1; + float DistanceNormalisation = .05f; } settings; struct alignas(16) SSGICB @@ -75,10 +79,13 @@ struct ScreenSpaceGI : Feature float4x4 PrevInvViewMat[2]; float2 NDCToViewMul[2]; float2 NDCToViewAdd[2]; - float2 NDCToViewMul_x_PixelSize[2]; - float2 FrameDim; - float2 RcpFrameDim; // + float2 TexDim; + float2 RcpTexDim; // + float2 SrcFrameDim; + float2 RcpSrcFrameDim; // + float2 OutFrameDim; + float2 RcpOutFrameDim; // uint FrameIndex; uint NumSlices; @@ -101,20 +108,23 @@ struct ScreenSpaceGI : Feature float GIStrength; float DepthDisocclusion; - uint MaxAccumFrames; + float NormalDisocclusion; + uint MaxAccumFrames; // - float pad[1]; + float BlurRadius; + float DistanceNormalisation; + + float pad[2]; }; eastl::unique_ptr ssgiCB; eastl::unique_ptr texHilbertLUT = nullptr; eastl::unique_ptr texWorkingDepth = nullptr; winrt::com_ptr uavWorkingDepth[5] = { nullptr }; - eastl::unique_ptr texPrevDepth = nullptr; + eastl::unique_ptr texPrevGeo = nullptr; eastl::unique_ptr texRadiance = nullptr; - eastl::unique_ptr texAccumFrames = nullptr; - eastl::unique_ptr texGI0 = { nullptr }; - eastl::unique_ptr texGI1 = nullptr; + eastl::unique_ptr texAccumFrames[2] = { nullptr }; + eastl::unique_ptr texGI[2] = { nullptr }; eastl::unique_ptr texPrevGIAlbedo = { nullptr }; winrt::com_ptr linearClampSampler = nullptr; @@ -124,6 +134,7 @@ struct ScreenSpaceGI : Feature winrt::com_ptr prefilterDepthsCompute = nullptr; winrt::com_ptr radianceDisoccCompute = nullptr; winrt::com_ptr giCompute = nullptr; + winrt::com_ptr blurCompute = nullptr; winrt::com_ptr upsampleCompute = nullptr; winrt::com_ptr outputCompute = nullptr; }; \ No newline at end of file diff --git a/src/Features/ScreenSpaceShadows.cpp b/src/Features/ScreenSpaceShadows.cpp index 8b332e371..379de075f 100644 --- a/src/Features/ScreenSpaceShadows.cpp +++ b/src/Features/ScreenSpaceShadows.cpp @@ -262,8 +262,8 @@ void ScreenSpaceShadows::DrawNormalMappingShadows() float resolutionX = state->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; float resolutionY = state->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; - uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 32.0f); - uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 32.0f); + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); context->Dispatch(dispatchX, dispatchY, 1); } diff --git a/src/Features/ScreenSpaceShadows.h b/src/Features/ScreenSpaceShadows.h index 6d05fa490..5e0c91032 100644 --- a/src/Features/ScreenSpaceShadows.h +++ b/src/Features/ScreenSpaceShadows.h @@ -16,9 +16,9 @@ struct ScreenSpaceShadows : Feature struct BendSettings { - float SurfaceThickness = 0.005f; + float SurfaceThickness = 0.010f; float BilinearThreshold = 0.02f; - float ShadowContrast = 1.0f; + float ShadowContrast = 4.0f; uint Enable = 1; uint EnableNormalMappingShadows = 1; uint SampleCount = 1; diff --git a/src/Features/Skylighting.cpp b/src/Features/Skylighting.cpp new file mode 100644 index 000000000..4a6cef802 --- /dev/null +++ b/src/Features/Skylighting.cpp @@ -0,0 +1,400 @@ +#include "Skylighting.h" +#include +#include +#include + +void Skylighting::DrawSettings() +{ + ImGui::Checkbox("Do occlusion", &GetSingleton()->doOcclusion); + ImGui::Checkbox("Render trees", &renderTrees); + + ImGui::SliderFloat("Bound Size", &boundSize, 0, 512, "%.2f"); + ImGui::SliderFloat("Distance", &occlusionDistance, 0, 20000); +} + +void Skylighting::Draw(const RE::BSShader*, const uint32_t) +{ +} + +void Skylighting::SetupResources() +{ + { + D3D11_BUFFER_DESC sbDesc{}; + sbDesc.Usage = D3D11_USAGE_DEFAULT; + sbDesc.CPUAccessFlags = 0; + sbDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc{}; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{}; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.Flags = 0; + + std::uint32_t numElements = 1; + + sbDesc.StructureByteStride = sizeof(PerGeometry); + sbDesc.ByteWidth = sizeof(PerGeometry) * numElements; + perShadow = new Buffer(sbDesc); + srvDesc.Buffer.NumElements = numElements; + perShadow->CreateSRV(srvDesc); + uavDesc.Buffer.NumElements = numElements; + perShadow->CreateUAV(uavDesc); + + copyShadowCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\ShadowTest\\CopyShadowData.hlsl", {}, "cs_5_0"); + } + + GetSkylightingCS(); + + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + + { + auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN]; + + D3D11_TEXTURE2D_DESC texDesc{}; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + + main.texture->GetDesc(&texDesc); + main.SRV->GetDesc(&srvDesc); + main.UAV->GetDesc(&uavDesc); + + texDesc.Format = DXGI_FORMAT_R8G8_UNORM; + srvDesc.Format = texDesc.Format; + uavDesc.Format = texDesc.Format; + + skylightingTexture = new Texture2D(texDesc); + skylightingTexture->CreateSRV(srvDesc); + skylightingTexture->CreateUAV(uavDesc); + } + + { + auto& precipitationOcclusion = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + + D3D11_TEXTURE2D_DESC texDesc{}; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + + precipitationOcclusion.texture->GetDesc(&texDesc); + precipitationOcclusion.depthSRV->GetDesc(&srvDesc); + precipitationOcclusion.views[0]->GetDesc(&dsvDesc); + + occlusionTexture = new Texture2D(texDesc); + occlusionTexture->CreateSRV(srvDesc); + occlusionTexture->CreateDSV(dsvDesc); + + occlusionTranslucentTexture = new Texture2D(texDesc); + occlusionTranslucentTexture->CreateSRV(srvDesc); + occlusionTranslucentTexture->CreateDSV(dsvDesc); + } + + { + perFrameCB = new ConstantBuffer(ConstantBufferDesc()); + } + + { + auto& device = State::GetSingleton()->device; + auto& context = State::GetSingleton()->context; + + DirectX::CreateDDSTextureFromFile(device, context, L"Data\\Shaders\\Skylighting\\bluenoise.dds", nullptr, &noiseView); + } + + { + auto& device = State::GetSingleton()->device; + + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + DX::ThrowIfFailed(device->CreateSamplerState(&sampDesc, &comparisonSampler)); + } +} + +void Skylighting::Reset() +{ + translucent = false; +} + +void Skylighting::Load(json& o_json) +{ + Feature::Load(o_json); +} + +void Skylighting::Save(json&) +{ +} + +void Skylighting::RestoreDefaultSettings() +{ +} + +ID3D11ComputeShader* Skylighting::GetSkylightingCS() +{ + if (!skylightingCS) { + logger::debug("Compiling SkylightingCS"); + skylightingCS = (ID3D11ComputeShader*)Util::CompileShader(L"Data\\Shaders\\Skylighting\\SkylightingCS.hlsl", {}, "cs_5_0"); + } + return skylightingCS; +} + +void Skylighting::ClearShaderCache() +{ + if (skylightingCS) { + skylightingCS->Release(); + skylightingCS = nullptr; + } +} + +void Skylighting::CopyShadowData() +{ + if (!loaded) + return; + + auto& context = State::GetSingleton()->context; + + ID3D11UnorderedAccessView* uavs[1]{ perShadow->uav.get() }; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + ID3D11Buffer* buffers[1]; + context->PSGetConstantBuffers(2, 1, buffers); + context->CSSetConstantBuffers(0, 1, buffers); + + context->PSGetConstantBuffers(12, 1, buffers); + context->CSSetConstantBuffers(1, 1, buffers); + + context->PSGetConstantBuffers(0, 1, buffers); + context->CSSetConstantBuffers(2, 1, buffers); + + context->PSGetShaderResources(4, 1, &shadowView); + + context->CSSetSamplers(0, 1, &Deferred::GetSingleton()->linearSampler); + + context->CSSetShader(copyShadowCS, nullptr, 0); + + context->Dispatch(1, 1, 1); + + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + buffers[0] = nullptr; + context->CSSetConstantBuffers(0, 1, buffers); + context->CSSetConstantBuffers(1, 1, buffers); + context->CSSetConstantBuffers(2, 1, buffers); + + context->CSSetShader(nullptr, nullptr, 0); +} + +void Skylighting::Compute() +{ + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto state = State::GetSingleton(); + auto& context = state->context; + auto viewport = RE::BSGraphics::State::GetSingleton(); + + float resolutionX = state->screenWidth * viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; + float resolutionY = state->screenHeight * viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; + + { + PerFrameCB data{}; + + 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.DynamicRes.x = viewport->GetRuntimeData().dynamicResolutionCurrentWidthScale; + data.DynamicRes.y = viewport->GetRuntimeData().dynamicResolutionCurrentHeightScale; + data.DynamicRes.z = 1.0f / data.DynamicRes.x; + data.DynamicRes.w = 1.0f / data.DynamicRes.y; + + auto imageSpaceManager = RE::ImageSpaceManager::GetSingleton(); + + auto useTAA = !REL::Module::IsVR() ? imageSpaceManager->GetRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled : imageSpaceManager->GetVRRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled; + data.FrameCount = useTAA || state->upscalerLoaded ? viewport->uiFrameCount : 0; + + data.CameraData = Util::GetCameraData(); + + data.viewProjMat = viewProjMat; + auto shadowSceneNode = RE::BSShaderManager::State::GetSingleton().shadowSceneNode[0]; + auto shadowDirLight = (RE::BSShadowDirectionalLight*)shadowSceneNode->GetRuntimeData().shadowDirLight; + bool dirShadow = shadowDirLight && shadowDirLight->shadowLightIndex == 0; + + if (dirShadow) { + data.ShadowDirection = float4(shadowDirLight->lightDirection.x, shadowDirLight->lightDirection.y, shadowDirLight->lightDirection.z, 0); + } + + perFrameCB->Update(data); + } + + auto depth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY]; + auto normalRoughness = renderer->GetRuntimeData().renderTargets[NORMALROUGHNESS]; + + ID3D11ShaderResourceView* srvs[7]{ + depth.depthSRV, + shadowView, + perShadow->srv.get(), + noiseView, + occlusionTexture->srv.get(), + occlusionTranslucentTexture->srv.get(), + normalRoughness.SRV + }; + + context->CSSetShaderResources(0, 7, srvs); + + ID3D11UnorderedAccessView* uavs[1]{ skylightingTexture->uav.get() }; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + auto buffer = perFrameCB->CB(); + context->CSSetConstantBuffers(1, 1, &buffer); + + ID3D11SamplerState* samplers[2] = { Deferred::GetSingleton()->linearSampler, comparisonSampler }; + context->CSSetSamplers(0, 2, samplers); + + context->CSSetShader(GetSkylightingCS(), nullptr, 0); + + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); + + context->Dispatch(dispatchX, dispatchY, 1); + + srvs[0] = nullptr; + srvs[1] = nullptr; + srvs[2] = nullptr; + srvs[3] = nullptr; + srvs[4] = nullptr; + srvs[5] = nullptr; + srvs[6] = nullptr; + + context->CSSetShaderResources(0, 7, srvs); + + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + buffer = nullptr; + context->CSSetConstantBuffers(1, 1, &buffer); + + samplers[0] = nullptr; + samplers[1] = nullptr; + context->CSSetSamplers(0, 2, samplers); + + context->CSSetShader(nullptr, nullptr, 0); +} + +void Skylighting::EnableTranslucentDepth() +{ + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto& precipitation = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + + precipitation.depthSRV = occlusionTranslucentTexture->srv.get(); + precipitation.texture = occlusionTranslucentTexture->resource.get(); + precipitation.views[0] = occlusionTranslucentTexture->dsv.get(); + + auto& state = State::GetSingleton()->shadowState; + GET_INSTANCE_MEMBER(stateUpdateFlags, state) + stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); +} + +void Skylighting::DisableTranslucentDepth() +{ + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto& precipitation = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + + precipitation.depthSRV = occlusionTexture->srv.get(); + precipitation.texture = occlusionTexture->resource.get(); + precipitation.views[0] = occlusionTexture->dsv.get(); + + auto& state = State::GetSingleton()->shadowState; + GET_INSTANCE_MEMBER(stateUpdateFlags, state) + stateUpdateFlags.set(RE::BSGraphics::ShaderFlags::DIRTY_RENDERTARGET); +} + +void Skylighting::UpdateDepthStencilView(RE::BSRenderPass* a_pass) +{ + if (inOcclusion) { + auto currentTranslucent = a_pass->shaderProperty->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kTreeAnim); + if (translucent != currentTranslucent) { + translucent = currentTranslucent; + if (translucent) { + EnableTranslucentDepth(); + } else { + DisableTranslucentDepth(); + } + } + } +} + +void Skylighting::Bind() +{ + if (!loaded) + return; + + auto& context = State::GetSingleton()->context; + + ID3D11ShaderResourceView* srvs[8]; + context->PSGetShaderResources(0, 8, srvs); + + ID3D11ShaderResourceView* srvsCS[8]; + context->CSGetShaderResources(0, 8, srvsCS); + + ID3D11UnorderedAccessView* uavsCS[8]; + context->CSGetUnorderedAccessViews(0, 8, uavsCS); + + ID3D11UnorderedAccessView* nullUavs[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + context->CSSetUnorderedAccessViews(0, 8, nullUavs, nullptr); + + ID3D11ShaderResourceView* nullSrvs[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + context->PSSetShaderResources(0, 8, nullSrvs); + context->CSSetShaderResources(0, 8, nullSrvs); + + ID3D11RenderTargetView* views[8]; + ID3D11DepthStencilView* dsv; + context->OMGetRenderTargets(8, views, &dsv); + + ID3D11RenderTargetView* nullViews[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + ID3D11DepthStencilView* nullDsv = nullptr; + context->OMSetRenderTargets(8, nullViews, nullDsv); + + Compute(); + + context->PSSetShaderResources(0, 8, srvs); + context->CSSetShaderResources(0, 8, srvsCS); + context->CSSetUnorderedAccessViews(0, 8, uavsCS, nullptr); + context->OMSetRenderTargets(8, views, dsv); + + for (int i = 0; i < 8; i++) { + if (srvs[i]) + srvs[i]->Release(); + if (srvsCS[i]) + srvsCS[i]->Release(); + } + + for (int i = 0; i < 8; i++) { + if (views[i]) + views[i]->Release(); + } + + if (dsv) + dsv->Release(); + + ID3D11ShaderResourceView* srvs2[3]{ + shadowView, + perShadow->srv.get(), + skylightingTexture->srv.get() + }; + + context->PSSetShaderResources(80, 3, srvs2); +} \ No newline at end of file diff --git a/src/Features/Skylighting.h b/src/Features/Skylighting.h new file mode 100644 index 000000000..16e1f5d16 --- /dev/null +++ b/src/Features/Skylighting.h @@ -0,0 +1,484 @@ +#pragma once + +#include "Buffer.h" +#include "Feature.h" +#include "State.h" + +struct Skylighting : Feature +{ +public: + static Skylighting* GetSingleton() + { + static Skylighting singleton; + return &singleton; + } + + virtual inline std::string GetName() { return "Skylighting"; } + virtual inline std::string GetShortName() { return "Skylighting"; } + inline std::string_view GetShaderDefineName() override { return "SKYLIGHTING"; } + + bool HasShaderDefine(RE::BSShader::Type) override { return true; }; + + virtual void SetupResources(); + virtual void Reset(); + + virtual void DrawSettings(); + + virtual void Draw(const RE::BSShader* shader, const uint32_t descriptor); + + virtual void Load(json& o_json); + virtual void Save(json& o_json); + + virtual inline void PostPostLoad() override { Hooks::Install(); } + + virtual void RestoreDefaultSettings(); + + REX::W32::XMFLOAT4X4 viewProjMat; + float occlusionDistance = 10000; + bool renderTrees = false; + + ID3D11ComputeShader* skylightingCS = nullptr; + ID3D11ComputeShader* GetSkylightingCS(); + + ID3D11SamplerState* comparisonSampler; + + struct alignas(16) PerFrameCB + { + REX::W32::XMFLOAT4X4 viewProjMat; + float4 ShadowDirection; + float4 BufferDim; + float4 DynamicRes; + float4 CameraData; + uint FrameCount; + uint pad0[3]; + }; + + ConstantBuffer* perFrameCB = nullptr; + + virtual void ClearShaderCache() override; + + struct alignas(16) PerGeometry + { + float4 VPOSOffset; + float4 ShadowSampleParam; // fPoissonRadiusScale / iShadowMapResolution in z and w + float4 EndSplitDistances; // cascade end distances int xyz, cascade count int z + float4 StartSplitDistances; // cascade start ditances int xyz, 4 int z + float4 FocusShadowFadeParam; + float4 DebugColor; + float4 PropertyColor; + float4 AlphaTestRef; + float4 ShadowLightParam; // Falloff in x, ShadowDistance squared in z + DirectX::XMFLOAT4X3 FocusShadowMapProj[4]; + DirectX::XMFLOAT4X3 ShadowMapProj[4]; + DirectX::XMFLOAT4X4 CameraViewProjInverse; + }; + + ID3D11ComputeShader* copyShadowCS = nullptr; + + void CopyShadowData(); + + Buffer* perShadow = nullptr; + ID3D11ShaderResourceView* shadowView = nullptr; + + Texture2D* skylightingTexture = nullptr; + + ID3D11ShaderResourceView* noiseView = nullptr; + + Texture2D* occlusionTexture = nullptr; + Texture2D* occlusionTranslucentTexture = nullptr; + + bool translucent = false; + + RE::BSGraphics::DepthStencilData precipitationCopy; + + bool doOcclusion = true; + + struct BSParticleShaderRainEmitter + { + void* vftable_BSParticleShaderRainEmitter_0; + char _pad_8[4056]; + }; + + static void Precipitation_SetupMask(RE::Precipitation* a_This) + { + using func_t = decltype(&Precipitation_SetupMask); + REL::Relocation func{ REL::RelocationID(25641, 26183) }; + func(a_This); + } + + static void Precipitation_RenderMask(RE::Precipitation* a_This, BSParticleShaderRainEmitter* a_emitter) + { + using func_t = decltype(&Precipitation_RenderMask); + REL::Relocation func{ REL::RelocationID(25642, 26184) }; + func(a_This, a_emitter); + } + + void Bind(); + void Compute(); + + void EnableTranslucentDepth(); + + void DisableTranslucentDepth(); + + void UpdateDepthStencilView(RE::BSRenderPass* a_pass); + + enum class ShaderTechnique + { + // Sky + SkySunOcclude = 0x2, + + // Grass + GrassNoAlphaDirOnlyFlatLit = 0x3, + GrassNoAlphaDirOnlyFlatLitSlope = 0x5, + GrassNoAlphaDirOnlyVertLitSlope = 0x6, + GrassNoAlphaDirOnlyFlatLitBillboard = 0x13, + GrassNoAlphaDirOnlyFlatLitSlopeBillboard = 0x14, + + // Utility + UtilityGeneralStart = 0x2B, + + // Effect + EffectGeneralStart = 0x4000002C, + + // Lighting + LightingGeneralStart = 0x4800002D, + + // DistantTree + DistantTreeDistantTreeBlock = 0x5C00002E, + DistantTreeDepth = 0x5C00002F, + + // Grass + GrassDirOnlyFlatLit = 0x5C000030, + GrassDirOnlyFlatLitSlope = 0x5C000032, + GrassDirOnlyVertLitSlope = 0x5C000033, + GrassDirOnlyFlatLitBillboard = 0x5C000040, + GrassDirOnlyFlatLitSlopeBillboard = 0x5C000041, + GrassRenderDepth = 0x5C00005C, + + // Sky + SkySky = 0x5C00005E, + SkyMoonAndStarsMask = 0x5C00005F, + SkyStars = 0x5C000060, + SkyTexture = 0x5C000061, + SkyClouds = 0x5C000062, + SkyCloudsLerp = 0x5C000063, + SkyCloudsFade = 0x5C000064, + + // Particle + ParticleParticles = 0x5C000065, + ParticleParticlesGryColorAlpha = 0x5C000066, + ParticleParticlesGryColor = 0x5C000067, + ParticleParticlesGryAlpha = 0x5C000068, + ParticleEnvCubeSnow = 0x5C000069, + ParticleEnvCubeRain = 0x5C00006A, + + // Water + WaterSimple = 0x5C00006B, + WaterSimpleVc = 0x5C00006C, + WaterStencil = 0x5C00006D, + WaterStencilVc = 0x5C00006E, + WaterDisplacementStencil = 0x5C00006F, + WaterDisplacementStencilVc = 0x5C000070, + WaterGeneralStart = 0x5C000071, + + // Sky + SkySunGlare = 0x5C006072, + + // BloodSplater + BloodSplaterFlare = 0x5C006073, + BloodSplaterSplatter = 0x5C006074, + }; + + class BSUtilityShader : public RE::BSShader + { + public: + enum class Flags + { + None = 0, + Vc = 1 << 0, + Texture = 1 << 1, + Skinned = 1 << 2, + Normals = 1 << 3, + BinormalTangent = 1 << 4, + AlphaTest = 1 << 7, + LodLandscape = 1 << 8, + RenderNormal = 1 << 9, + RenderNormalFalloff = 1 << 10, + RenderNormalClamp = 1 << 11, + RenderNormalClear = 1 << 12, + RenderDepth = 1 << 13, + RenderShadowmap = 1 << 14, + RenderShadowmapClamped = 1 << 15, + GrayscaleToAlpha = 1 << 15, + RenderShadowmapPb = 1 << 16, + AdditionalAlphaMask = 1 << 16, + DepthWriteDecals = 1 << 17, + DebugShadowSplit = 1 << 18, + DebugColor = 1 << 19, + GrayscaleMask = 1 << 20, + RenderShadowmask = 1 << 21, + RenderShadowmaskSpot = 1 << 22, + RenderShadowmaskPb = 1 << 23, + RenderShadowmaskDpb = 1 << 24, + RenderBaseTexture = 1 << 25, + TreeAnim = 1 << 26, + LodObject = 1 << 27, + LocalMapFogOfWar = 1 << 28, + OpaqueEffect = 1 << 29, + }; + + static BSUtilityShader* GetSingleton() + { + REL::Relocation singleton{ RELOCATION_ID(528354, 415300) }; + return *singleton; + } + ~BSUtilityShader() override; // 00 + + // override (BSShader) + bool SetupTechnique(std::uint32_t globalTechnique) override; // 02 + void RestoreTechnique(std::uint32_t globalTechnique) override; // 03 + void SetupGeometry(RE::BSRenderPass* pass, uint32_t flags) override; // 06 + void RestoreGeometry(RE::BSRenderPass* pass, uint32_t flags) override; // 07 + }; + + struct RenderPassArray + { + static RE::BSRenderPass* MakeRenderPass(RE::BSShader* shader, RE::BSShaderProperty* property, RE::BSGeometry* geometry, + uint32_t technique, uint8_t numLights, RE::BSLight** lights) + { + using func_t = decltype(&RenderPassArray::MakeRenderPass); + REL::Relocation func{ RELOCATION_ID(100717, 107497) }; + return func(shader, property, geometry, technique, numLights, lights); + } + + static void ClearRenderPass(RE::BSRenderPass* pass) + { + using func_t = decltype(&RenderPassArray::ClearRenderPass); + REL::Relocation func{ RELOCATION_ID(100718, 107498) }; + func(pass); + } + + void Clear() + { + while (head != nullptr) { + RE::BSRenderPass* next = head->next; + ClearRenderPass(head); + head = next; + } + head = nullptr; + } + + RE::BSRenderPass* EmplacePass(RE::BSShader* shader, RE::BSShaderProperty* property, RE::BSGeometry* geometry, + uint32_t technique, uint8_t numLights = 0, RE::BSLight* light0 = nullptr, RE::BSLight* light1 = nullptr, + RE::BSLight* light2 = nullptr, RE::BSLight* light3 = nullptr) + { + RE::BSLight* lights[4]; + lights[0] = light0; + lights[1] = light1; + lights[2] = light2; + lights[3] = light3; + auto* newPass = MakeRenderPass(shader, property, geometry, technique, numLights, lights); + if (head != nullptr) { + RE::BSRenderPass* lastPass = head; + while (lastPass->next != nullptr) { + lastPass = lastPass->next; + } + lastPass->next = newPass; + } else { + head = newPass; + } + return newPass; + } + + RE::BSRenderPass* head; // 00 + uint64_t unk08; // 08 + }; + + float boundSize = 64; + + class BSBatchRenderer + { + public: + struct PersistentPassList + { + RE::BSRenderPass* m_Head; + RE::BSRenderPass* m_Tail; + }; + + struct GeometryGroup + { + BSBatchRenderer* m_BatchRenderer; + PersistentPassList m_PassList; + uintptr_t UnkPtr4; + float m_Depth; // Distance from geometry to camera location + uint16_t m_Count; + uint8_t m_Flags; // Flags + }; + + struct PassGroup + { + RE::BSRenderPass* m_Passes[5]; + uint32_t m_ValidPassBits; // OR'd with (1 << PassIndex) + }; + + RE::BSTArray unk008; // 008 + RE::BSTHashMap unk020; // 020 + std::uint64_t unk050; // 050 + std::uint64_t unk058; // 058 + std::uint64_t unk060; // 060 + std::uint64_t unk068; // 068 + GeometryGroup* m_GeometryGroups[16]; + GeometryGroup* m_AlphaGroup; + void* unk1; + void* unk2; + }; + + bool inOcclusion = false; + + struct BSLightingShaderProperty_GetPrecipitationOcclusionMapRenderPassesImpl + { + static void* thunk(RE::BSLightingShaderProperty* property, RE::BSGeometry* geometry, [[maybe_unused]] uint32_t renderMode, [[maybe_unused]] RE::BSGraphics::BSShaderAccumulator* accumulator) + { + auto batch = (BSBatchRenderer*)accumulator->GetRuntimeData().batchRenderer; + batch->m_GeometryGroups[14]->m_Flags &= ~1; + + using enum RE::BSShaderProperty::EShaderPropertyFlag; + using enum BSUtilityShader::Flags; + + auto* precipitationOcclusionMapRenderPassList = reinterpret_cast(&property->unk0C8); + + precipitationOcclusionMapRenderPassList->Clear(); + if (GetSingleton()->inOcclusion && !GetSingleton()->renderTrees) { + if (property->flags.any(kSkinned) && property->flags.none(kTreeAnim)) + return precipitationOcclusionMapRenderPassList; + } else { + if (property->flags.any(kSkinned)) + return precipitationOcclusionMapRenderPassList; + } + + if (property->flags.any(kZBufferWrite) && property->flags.none(kRefraction, kTempRefraction, kMultiTextureLandscape, kNoLODLandBlend, kLODLandscape, kEyeReflect, kDecal, kDynamicDecal, kAnisotropicLighting) && !(property->flags.any(kSkinned) && property->flags.none(kTreeAnim))) { + if (geometry->worldBound.radius > GetSingleton()->boundSize) { + stl::enumeration technique; + technique.set(RenderDepth); + + auto pass = precipitationOcclusionMapRenderPassList->EmplacePass( + BSUtilityShader::GetSingleton(), + property, + geometry, + technique.underlying() + static_cast(ShaderTechnique::UtilityGeneralStart)); + if (property->flags.any(kTreeAnim)) + pass->accumulationHint = 11; + } + } + return precipitationOcclusionMapRenderPassList; + }; + static inline REL::Relocation func; + }; + + struct Main_Precipitation_RenderOcclusion + { + static void thunk() + { + State::GetSingleton()->BeginPerfEvent("PRECIPITATION MASK"); + State::GetSingleton()->SetPerfMarker("PRECIPITATION MASK"); + + static bool doPrecip = false; + + auto sky = RE::Sky::GetSingleton(); + auto precip = sky->precip; + + if (GetSingleton()->doOcclusion) { + if (doPrecip) { + doPrecip = false; + + auto precipObject = precip->currentPrecip; + if (!precipObject) { + precipObject = precip->lastPrecip; + } + if (precipObject) { + Precipitation_SetupMask(precip); + Precipitation_SetupMask(precip); // Calling setup twice fixes an issue when it is raining + auto effect = precipObject->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; + auto shaderProp = netimmerse_cast(effect.get()); + auto particleShaderProperty = netimmerse_cast(shaderProp); + auto rain = (BSParticleShaderRainEmitter*)(particleShaderProperty->particleEmitter); + + Precipitation_RenderMask(precip, rain); + } + + } else { + doPrecip = true; + + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto& precipitation = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + GetSingleton()->precipitationCopy = precipitation; + + auto& context = State::GetSingleton()->context; + context->ClearDepthStencilView(GetSingleton()->occlusionTranslucentTexture->dsv.get(), D3D11_CLEAR_DEPTH, 1.0f, 0); + + precipitation.depthSRV = GetSingleton()->occlusionTexture->srv.get(); + precipitation.texture = GetSingleton()->occlusionTexture->resource.get(); + precipitation.views[0] = GetSingleton()->occlusionTexture->dsv.get(); + + static float& PrecipitationShaderCubeSize = (*(float*)REL::RelocationID(515451, 401590).address()); + float originalPrecipitationShaderCubeSize = PrecipitationShaderCubeSize; + + static RE::NiPoint3& PrecipitationShaderDirection = (*(RE::NiPoint3*)REL::RelocationID(515509, 401648).address()); + RE::NiPoint3 originalParticleShaderDirection = PrecipitationShaderDirection; + + GetSingleton()->inOcclusion = true; + PrecipitationShaderCubeSize = GetSingleton()->occlusionDistance; + + float originaLastCubeSize = precip->lastCubeSize; + precip->lastCubeSize = PrecipitationShaderCubeSize; + + PrecipitationShaderDirection = { 0, 0, -1 }; + + Precipitation_SetupMask(precip); + Precipitation_SetupMask(precip); // Calling setup twice fixes an issue when it is raining + + BSParticleShaderRainEmitter* rain = new BSParticleShaderRainEmitter; + Precipitation_RenderMask(precip, rain); + GetSingleton()->inOcclusion = false; + RE::BSParticleShaderCubeEmitter* cube = (RE::BSParticleShaderCubeEmitter*)rain; + GetSingleton()->viewProjMat = cube->occlusionProjection; + + cube = nullptr; + delete rain; + + PrecipitationShaderCubeSize = originalPrecipitationShaderCubeSize; + precip->lastCubeSize = originaLastCubeSize; + + PrecipitationShaderDirection = originalParticleShaderDirection; + + precipitation = GetSingleton()->precipitationCopy; + } + } + State::GetSingleton()->EndPerfEvent(); + } + static inline REL::Relocation func; + }; + + struct BSUtilityShader_SetupGeometry + { + static void thunk(RE::BSShader* This, RE::BSRenderPass* Pass, uint32_t RenderFlags) + { + GetSingleton()->UpdateDepthStencilView(Pass); + func(This, Pass, RenderFlags); + } + static inline REL::Relocation func; + }; + + struct Hooks + { + static void Install() + { + 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)); + stl::write_vfunc<0x6, BSUtilityShader_SetupGeometry>(RE::VTABLE_BSUtilityShader[0]); + } + }; + + bool SupportsVR() override { return false; }; +}; diff --git a/src/Features/TerrainOcclusion.cpp b/src/Features/TerrainOcclusion.cpp index f0436e4c2..ad51d5f79 100644 --- a/src/Features/TerrainOcclusion.cpp +++ b/src/Features/TerrainOcclusion.cpp @@ -1,4 +1,5 @@ #include "TerrainOcclusion.h" +#include "Menu.h" #include "Deferred.h" #include "State.h" @@ -111,12 +112,15 @@ void TerrainOcclusion::DrawSettings() } ImGui::Unindent(); - ImGui::BulletText("texOcclusion"); - ImGui::Image(texOcclusion->srv.get(), { texOcclusion->desc.Width * .1f, texOcclusion->desc.Height * .1f }); - ImGui::BulletText("texNormalisedHeight"); - ImGui::Image(texNormalisedHeight->srv.get(), { texNormalisedHeight->desc.Width * .1f, texNormalisedHeight->desc.Height * .1f }); - ImGui::BulletText("texShadowHeight"); - ImGui::Image(texShadowHeight->srv.get(), { texShadowHeight->desc.Width * .1f, texShadowHeight->desc.Height * .1f }); + if (ImGui::TreeNode("Buffer Viewer")) { + static float debugRescale = .1f; + ImGui::SliderFloat("View Resize", &debugRescale, 0.f, 1.f); + + BUFFER_VIEWER_NODE_BULLET(texOcclusion, debugRescale) + BUFFER_VIEWER_NODE_BULLET(texNormalisedHeight, debugRescale) + BUFFER_VIEWER_NODE_BULLET(texShadowHeight, debugRescale) + ImGui::TreePop(); + } } } } @@ -224,15 +228,15 @@ void TerrainOcclusion::CompileComputeShaders() { logger::debug("Compiling shaders..."); { - auto program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\AOGen.cs.hlsl", { {} }, "cs_5_0")); + auto program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\AOGen.cs.hlsl", {}, "cs_5_0")); if (program_ptr) occlusionProgram.attach(program_ptr); - program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\ShadowUpdate.cs.hlsl", { {} }, "cs_5_0")); + program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\ShadowUpdate.cs.hlsl", {}, "cs_5_0")); if (program_ptr) shadowUpdateProgram.attach(program_ptr); - program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\Output.cs.hlsl", { {} }, "cs_5_0")); + program_ptr = reinterpret_cast(Util::CompileShader(L"Data\\Shaders\\TerrainOcclusion\\Output.cs.hlsl", {}, "cs_5_0")); if (program_ptr) outputProgram.attach(program_ptr); } diff --git a/src/Features/TerrainOcclusion.h b/src/Features/TerrainOcclusion.h index 3fa2a5774..522bd3090 100644 --- a/src/Features/TerrainOcclusion.h +++ b/src/Features/TerrainOcclusion.h @@ -119,4 +119,5 @@ struct TerrainOcclusion : public Feature virtual inline void RestoreDefaultSettings() override { settings = {}; } virtual void ClearShaderCache() override; + bool SupportsVR() override { return true; }; }; \ No newline at end of file diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 985e2781c..ee7459801 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -217,7 +217,9 @@ decltype(&hk_BSShaderRenderTargets_Create) ptr_BSShaderRenderTargets_Create; void hk_BSShaderRenderTargets_Create() { - logger::info("bUse64bitsHDRRenderTarget is {}", RE::GetINISetting("bUse64bitsHDRRenderTarget:Display")->data.b ? "enabled" : "disabled"); + RE::GetINISetting("bUse64bitsHDRRenderTarget:Display")->data.b = false; + logger::info("bUse64bitsHDRRenderTarget was disabled"); + (ptr_BSShaderRenderTargets_Create)(); State::GetSingleton()->Setup(); } @@ -395,6 +397,16 @@ namespace Hooks static inline REL::Relocation func; }; + struct CreateRenderTarget_Snow + { + 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 CreateRenderTarget_ShadowMask { static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties) @@ -445,6 +457,8 @@ namespace Hooks stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x3F0, 0x3F3, 0x548)); stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x458, 0x45B, 0x5B0)); 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, 0x402)); stl::write_thunk_call(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x555, 0x554, 0x6b9)); } } \ No newline at end of file diff --git a/src/Menu.h b/src/Menu.h index fadb20c87..b20f074c1 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -7,11 +7,16 @@ #include using namespace std::chrono; -#define BUFFER_VIEWER_NODE(a_value) \ - if (ImGui::TreeNode(#a_value)) { \ - ImGui::Image(a_value->srv.get(), { a_value->desc.Width * .3f, a_value->desc.Height * .3f }); \ - ImGui::TreePop(); \ +#define BUFFER_VIEWER_NODE(a_value, a_scale) \ + if (ImGui::TreeNode(#a_value)) { \ + ImGui::Image(a_value->srv.get(), { a_value->desc.Width * a_scale, a_value->desc.Height * a_scale }); \ + ImGui::TreePop(); \ } + +#define BUFFER_VIEWER_NODE_BULLET(a_value, a_scale) \ + ImGui::BulletText(#a_value); \ + ImGui::Image(a_value->srv.get(), { a_value->desc.Width * a_scale, a_value->desc.Height * a_scale }); + #define ADDRESS_NODE(a_value) \ if (ImGui::Button(#a_value)) { \ ImGui::SetClipboardText(std::format("{0:x}", reinterpret_cast(a_value)).c_str()); \ diff --git a/src/ShaderCache.cpp b/src/ShaderCache.cpp index 835a17c3b..ba2b597ac 100644 --- a/src/ShaderCache.cpp +++ b/src/ShaderCache.cpp @@ -123,7 +123,7 @@ namespace SIE { using enum ShaderCache::SkyShaderTechniques; - const auto technique = static_cast(descriptor); + const auto technique = static_cast(descriptor & 255); int lastIndex = 0; switch (technique) { case SunOcclude: @@ -180,6 +180,12 @@ namespace SIE } } + uint32_t flags = descriptor >> 8; + + if (flags) { + defines[lastIndex++] = { "DEFERRED", nullptr }; + } + for (auto* feature : Feature::GetFeatureList()) { if (feature->loaded && feature->HasShaderDefine(RE::BSShader::Type::Sky)) { defines[lastIndex++] = { feature->GetShaderDefineName().data(), nullptr }; diff --git a/src/ShaderCache.h b/src/ShaderCache.h index ecb3f6503..1895459c7 100644 --- a/src/ShaderCache.h +++ b/src/ShaderCache.h @@ -119,7 +119,8 @@ namespace SIE type == RE::BSShader::Type::DistantTree || type == RE::BSShader::Type::Water || type == RE::BSShader::Type::Grass || - type == RE::BSShader::Type::Effect; + type == RE::BSShader::Type::Effect || + type == RE::BSShader::Type::Utility; } inline static bool IsSupportedShader(const RE::BSShader& shader) diff --git a/src/State.cpp b/src/State.cpp index 42ab6ef17..adc77a535 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -10,6 +10,7 @@ #include "Util.h" #include "Deferred.h" +#include "Features/Skylighting.h" #include "Features/TerrainBlending.h" #include "VariableRateShading.h" @@ -19,6 +20,11 @@ void State::Draw() Deferred::GetSingleton()->UpdatePerms(); if (currentShader && updateShader) { auto type = currentShader->shaderType.get(); + if (type == RE::BSShader::Type::Utility) { + if (currentPixelDescriptor & static_cast(SIE::ShaderCache::UtilityShaderFlags::RenderShadowmask)) { + Skylighting::GetSingleton()->CopyShadowData(); + } + } VariableRateShading::GetSingleton()->UpdateViews(type != RE::BSShader::Type::ImageSpace && type != RE::BSShader::Type::Sky && type != RE::BSShader::Type::Water); auto& shaderCache = SIE::ShaderCache::Instance(); if (shaderCache.IsEnabled()) { @@ -471,7 +477,7 @@ void State::SetupResources() void State::ModifyShaderLookup(const RE::BSShader& a_shader, uint& a_vertexDescriptor, uint& a_pixelDescriptor) { - if (a_shader.shaderType.get() == RE::BSShader::Type::Lighting || a_shader.shaderType.get() == RE::BSShader::Type::Water || a_shader.shaderType.get() == RE::BSShader::Type::Effect || a_shader.shaderType.get() == RE::BSShader::Type::DistantTree) { + if (a_shader.shaderType.get() == RE::BSShader::Type::Lighting || a_shader.shaderType.get() == RE::BSShader::Type::Water || a_shader.shaderType.get() == RE::BSShader::Type::Effect || a_shader.shaderType.get() == RE::BSShader::Type::DistantTree || a_shader.shaderType.get() == RE::BSShader::Type::Sky) { if (a_vertexDescriptor != lastVertexDescriptor || a_pixelDescriptor != lastPixelDescriptor) { PerShader data{}; data.VertexShaderDescriptor = a_vertexDescriptor; @@ -570,6 +576,12 @@ void State::ModifyShaderLookup(const RE::BSShader& a_shader, uint& a_vertexDescr a_pixelDescriptor |= (uint32_t)SIE::ShaderCache::DistantTreeShaderFlags::Deferred; } break; + case RE::BSShader::Type::Sky: + { + if (Deferred::GetSingleton()->deferredPass) + a_pixelDescriptor |= 256; + } + break; } ID3D11ShaderResourceView* view = shaderDataBuffer->srv.get(); diff --git a/src/Util.cpp b/src/Util.cpp index 93e9f4cce..4cee0ad78 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -172,7 +172,8 @@ namespace Util logger::warn("Shader compilation failed:\n\n{}", shaderErrors ? (const char*)shaderErrors->GetBufferPointer() : "Unknown error"); return nullptr; } - + if (shaderErrors) + logger::debug("Shader logs:\n{}", (const char*)shaderErrors->GetBufferPointer()); if (!_stricmp(ProgramType, "ps_5_0")) { ID3D11PixelShader* regShader; device->CreatePixelShader(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), nullptr, ®Shader); diff --git a/src/VariableRateShading.cpp b/src/VariableRateShading.cpp index ab7af80c3..d682880b2 100644 --- a/src/VariableRateShading.cpp +++ b/src/VariableRateShading.cpp @@ -46,55 +46,63 @@ void VariableRateShading::UpdateVRS() if (!vrsActive) return; - auto renderer = RE::BSGraphics::Renderer::GetSingleton(); - auto& context = State::GetSingleton()->context; + const auto imageSpaceManager = RE::ImageSpaceManager::GetSingleton(); + auto bTAA = !REL::Module::IsVR() ? imageSpaceManager->GetRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled : + imageSpaceManager->GetVRRuntimeData().BSImagespaceShaderISTemporalAA->taaEnabled; - ID3D11RenderTargetView* views[8]; - ID3D11DepthStencilView* dsv; - context->OMGetRenderTargets(8, views, &dsv); + temporal = bTAA || State::GetSingleton()->upscalerLoaded; - ID3D11RenderTargetView* nullViews[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - ID3D11DepthStencilView* nullDsv = nullptr; - context->OMSetRenderTargets(8, nullViews, nullDsv); + if (enableVRS && temporal && !RE::UI::GetSingleton()->GameIsPaused()) { + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + auto& context = State::GetSingleton()->context; - auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kMAIN]; - auto& motionVectors = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kMOTION_VECTOR]; + ID3D11RenderTargetView* views[8]; + ID3D11DepthStencilView* dsv; + context->OMGetRenderTargets(8, views, &dsv); - ID3D11ShaderResourceView* srvs[2]{ - main.SRV, - motionVectors.SRV - }; + ID3D11RenderTargetView* nullViews[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + ID3D11DepthStencilView* nullDsv = nullptr; + context->OMSetRenderTargets(8, nullViews, nullDsv); - context->CSSetShaderResources(0, 2, srvs); + auto& main = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kMAIN]; + auto& motionVectors = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGET::kMOTION_VECTOR]; - ID3D11UnorderedAccessView* uavs[1]{ reductionData->uav.get() }; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + ID3D11ShaderResourceView* srvs[2]{ + main.SRV, + motionVectors.SRV + }; - auto shader = GetComputeNASData(); - context->CSSetShader(shader, nullptr, 0); + context->CSSetShaderResources(0, 2, srvs); - context->Dispatch(reductionData->desc.Width, reductionData->desc.Height, 1); + ID3D11UnorderedAccessView* uavs[1]{ reductionData->uav.get() }; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - srvs[0] = nullptr; - srvs[1] = nullptr; - context->CSSetShaderResources(0, 1, srvs); + auto shader = GetComputeNASData(); + context->CSSetShader(shader, nullptr, 0); - uavs[0] = nullptr; - context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + context->Dispatch(reductionData->desc.Width, reductionData->desc.Height, 1); - context->CSSetShader(nullptr, nullptr, 0); + srvs[0] = nullptr; + srvs[1] = nullptr; + context->CSSetShaderResources(0, 1, srvs); - ComputeShadingRate(); + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); - context->OMSetRenderTargets(8, views, dsv); + context->CSSetShader(nullptr, nullptr, 0); - for (int i = 0; i < 8; i++) { - if (views[i]) - views[i]->Release(); - } + ComputeShadingRate(); + + context->OMSetRenderTargets(8, views, dsv); - if (dsv) - dsv->Release(); + for (int i = 0; i < 8; i++) { + if (views[i]) + views[i]->Release(); + } + + if (dsv) + dsv->Release(); + } } void VariableRateShading::ComputeShadingRate() @@ -116,8 +124,8 @@ void VariableRateShading::ComputeShadingRate() float resolutionX = (float)reductionData->desc.Width; float resolutionY = (float)reductionData->desc.Height; - uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 32.0f); - uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 32.0f); + uint32_t dispatchX = (uint32_t)std::ceil(resolutionX / 8.0f); + uint32_t dispatchY = (uint32_t)std::ceil(resolutionY / 8.0f); context->Dispatch(dispatchX, dispatchY, 1); @@ -154,6 +162,8 @@ std::vector CreateSingleEyeFixedFoveatedVRSPattern(int width, int heigh void VariableRateShading::Setup() { + Hooks::Install(); + auto renderer = RE::BSGraphics::Renderer::GetSingleton(); auto& device = State::GetSingleton()->device; @@ -195,7 +205,7 @@ void VariableRateShading::Setup() main.SRV->GetDesc(&srvDesc); main.UAV->GetDesc(&uavDesc); - texDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.Format = texDesc.Format; uavDesc.Format = texDesc.Format; @@ -274,14 +284,6 @@ void VariableRateShading::UpdateViews(bool a_enable) if (!vrsActive) return; - bool interior = false; - if (auto player = RE::PlayerCharacter::GetSingleton()) { - if (auto cell = player->GetParentCell()) { - if (cell->IsInteriorCell()) { - interior = true; - } - } - } auto& context = State::GetSingleton()->context; auto state = RE::BSGraphics::RendererShadowState::GetSingleton(); @@ -295,7 +297,7 @@ void VariableRateShading::UpdateViews(bool a_enable) vrsPass = true; } - vrsPass = enableVRS && vrsPass && a_enable && !RE::UI::GetSingleton()->GameIsPaused() && interior; + vrsPass = enableVRS && vrsPass && temporal && a_enable && notLandscape && !RE::UI::GetSingleton()->GameIsPaused(); static bool currentVRS = false; diff --git a/src/VariableRateShading.h b/src/VariableRateShading.h index 249568cc4..76bd91264 100644 --- a/src/VariableRateShading.h +++ b/src/VariableRateShading.h @@ -17,6 +17,8 @@ class VariableRateShading bool nvapiLoaded = false; bool vrsActive = false; bool vrsPass = false; + bool notLandscape = true; + bool temporal = false; ID3D11Texture2D* singleEyeVRSTex[2]; ID3D11UnorderedAccessView* singleEyeVRSUAV[2]; ID3D11NvShadingRateResourceView* singleEyeVRSView[2]; @@ -39,4 +41,40 @@ class VariableRateShading void Setup(); void SetupSingleEyeVRS(int eye, int width, int height); void UpdateViews(bool a_enable); + + struct Hooks + { + struct BSUtilityShader_SetupGeometry + { + static void thunk(RE::BSShader* This, RE::BSRenderPass* Pass, uint32_t RenderFlags) + { + if (Pass->shaderProperty) + GetSingleton()->notLandscape = Pass->shaderProperty->flags.none(RE::BSShaderProperty::EShaderPropertyFlag::kMultiTextureLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kLODLandscape); + else + GetSingleton()->notLandscape = true; + func(This, Pass, RenderFlags); + } + static inline REL::Relocation func; + }; + + struct BSLightingShader_SetupGeometry + { + static void thunk(RE::BSShader* This, RE::BSRenderPass* Pass, uint32_t RenderFlags) + { + if (Pass->shaderProperty) + GetSingleton()->notLandscape = Pass->shaderProperty->flags.none(RE::BSShaderProperty::EShaderPropertyFlag::kMultiTextureLandscape, RE::BSShaderProperty::EShaderPropertyFlag::kLODLandscape); + else + GetSingleton()->notLandscape = true; + func(This, Pass, RenderFlags); + } + static inline REL::Relocation func; + }; + + static void Install() + { + stl::write_vfunc<0x6, BSUtilityShader_SetupGeometry>(RE::VTABLE_BSUtilityShader[0]); + stl::write_vfunc<0x6, BSLightingShader_SetupGeometry>(RE::VTABLE_BSLightingShader[0]); + logger::info("[VRS] Installed hooks"); + } + }; }; \ No newline at end of file