426 lines
19 KiB
Plaintext
426 lines
19 KiB
Plaintext
// SSAO Compute Shader for GTAO mode
|
|
// This compute shader provides an alternative path to the fragment shader for GTAO computation
|
|
|
|
// #pragma enable_d3d11_debug_symbols
|
|
|
|
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch switch2 glcore gles3 webgpu
|
|
|
|
#pragma kernel ComputeAO
|
|
#pragma kernel BilateralBlurH
|
|
#pragma kernel BilateralBlurV
|
|
#pragma kernel BoxSpatialFilter
|
|
#pragma kernel TemporalFilter
|
|
#pragma kernel CopyHistory
|
|
#pragma kernel FinalBlit
|
|
|
|
// Keywords matching fragment shader variants
|
|
#pragma multi_compile_local _ _BLUE_NOISE _INTERLEAVED_GRADIENT
|
|
#pragma multi_compile_local _ _TEMPORAL_FILTERING
|
|
#pragma multi_compile_local _ _ORTHOGRAPHIC
|
|
|
|
// Provide types needed for the texture and macro declarations that follow
|
|
#define GTAO_COMPUTE_PATH
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
|
|
|
|
// Textures and Caller-defined macros for sampling (must be defined before SSAOCommon include)
|
|
TEXTURE2D_HALF(_BlueNoiseTexture);
|
|
SAMPLER(sampler_BlitTexture);
|
|
#define SSAO_COMMON_SAMPLE_BASEMAP_R(uv) half(SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_BlitTexture, UnityStereoTransformScreenSpaceTex(uv), 0).r)
|
|
#define SSAO_COMMON_SAMPLE_BLUE_NOISE(uv) SAMPLE_TEXTURE2D_LOD(_BlueNoiseTexture, sampler_PointRepeat, UnityStereoTransformScreenSpaceTex(uv), 0).a
|
|
#define SSAO_COMMON_FETCH_DEPTH(samplePos, screenSize, downsample) LoadSceneDepth(uint2(samplePos * rcp(downsample)))
|
|
#define SSAO_COMMON_DECLARE_UNIFORMS
|
|
|
|
// Compute path uses dynamic values instead of compile-time constants
|
|
int _GTAODirectionCount;
|
|
int _GTAOStepCount;
|
|
int _GTAOSpatialFilter;
|
|
float _GTAOBoxFilterStep; // a-trous step width, height
|
|
|
|
#define GTAO_STEP_COUNT _GTAOStepCount
|
|
#define GTAO_DIRECTION_COUNT _GTAODirectionCount
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SSAOCommon.hlsl"
|
|
|
|
RW_TEXTURE2D(half4, _AOOutput);
|
|
RW_TEXTURE2D(half4, _BlurOutput);
|
|
RW_TEXTURE2D(half4, _OcclusionTexture);
|
|
RW_TEXTURE2D(half4, _AOOutputHistory);
|
|
RW_TEXTURE2D(half4, _FinalOutput);
|
|
|
|
TEXTURE2D_X_HALF(_ScreenSpaceOcclusionTexture);
|
|
TEXTURE2D_X(_AOPackedHistory);
|
|
TEXTURE2D_X(_MotionVectorTexture);
|
|
|
|
// Compute-specific defines
|
|
#define SSAO_GROUP_SIZE 8
|
|
#define DOWNSAMPLE _SSAOParams.z
|
|
#define DOWNSAMPLED_SCREEN_SIZE uint2(_SourceSize.xy * DOWNSAMPLE)
|
|
#define DOWNSAMPLED_TEXEL_SIZE (_SourceSize.zw * rcp(DOWNSAMPLE))
|
|
|
|
static const float kMaxTemporalHistoryFrameCount = 64.0;
|
|
static const float kInvMaxTemporalHistoryFrameCount = 1.0 / kMaxTemporalHistoryFrameCount;
|
|
static const int kGTAOSpatialFilterBilateral = 0;
|
|
// SVGF-style normal edge-stop: weight = pow(max(0, dot(nCenter, nSample)), kNormalRejectionPower) instead of a hard threshold.
|
|
// A higher power tightens the accepted normal cone (Schied et al. 2017).
|
|
static const float kNormalRejectionPower = 16.0; // empirical (SVGF uses 128)
|
|
|
|
// Scales the relative off-plane depth deviation in the range weight: exp(-kDepthRejectionScale * |delta|).
|
|
// Larger values reject across depth more aggressively. (SVGF depth term; Schied et al. 2017)
|
|
static const float kDepthRejectionScale = 2000.0; // empirical
|
|
|
|
static const float kMotionWeightScale = 5.0;
|
|
static const float kHistoryDepthRatioMin = 0.5;
|
|
static const float kHistoryDepthRatioMax = 2.0;
|
|
static const float kCoherenceContrastScale = 5.0; // Coherence-contrast scale: scales |neighborhoodAvg - currentAO|; spatialCoherence reaches 0 once that contrast exceeds ~1/this (about 0.2 AO).
|
|
static const float kClampMargin = 0.05;
|
|
// ------------------------------------------------------------------
|
|
// Compute-Specific Functions
|
|
// ------------------------------------------------------------------
|
|
|
|
half4 ComputeBilateralBlur(TEXTURE2D_X_PARAM(blurredAO, samplerBlurredAO), float2 uv, float2 delta)
|
|
{
|
|
half4 p0 = half4(SAMPLE_TEXTURE2D_X_LOD(blurredAO, samplerBlurredAO, UnityStereoTransformScreenSpaceTex(uv), 0));
|
|
half4 p1a = half4(SAMPLE_TEXTURE2D_X_LOD(blurredAO, samplerBlurredAO, UnityStereoTransformScreenSpaceTex(uv - delta * 1.3846153846), 0));
|
|
half4 p1b = half4(SAMPLE_TEXTURE2D_X_LOD(blurredAO, samplerBlurredAO, UnityStereoTransformScreenSpaceTex(uv + delta * 1.3846153846), 0));
|
|
half4 p2a = half4(SAMPLE_TEXTURE2D_X_LOD(blurredAO, samplerBlurredAO, UnityStereoTransformScreenSpaceTex(uv - delta * 3.2307692308), 0));
|
|
half4 p2b = half4(SAMPLE_TEXTURE2D_X_LOD(blurredAO, samplerBlurredAO, UnityStereoTransformScreenSpaceTex(uv + delta * 3.2307692308), 0));
|
|
|
|
half3 n0 = GetPackedNormal(p0);
|
|
|
|
half w0 = half(0.2270270270);
|
|
half w1a = CompareNormal(n0, GetPackedNormal(p1a)) * half(0.3162162162);
|
|
half w1b = CompareNormal(n0, GetPackedNormal(p1b)) * half(0.3162162162);
|
|
half w2a = CompareNormal(n0, GetPackedNormal(p2a)) * half(0.0702702703);
|
|
half w2b = CompareNormal(n0, GetPackedNormal(p2b)) * half(0.0702702703);
|
|
|
|
half s = half(0.0);
|
|
s += GetPackedAO(p0) * w0;
|
|
s += GetPackedAO(p1a) * w1a;
|
|
s += GetPackedAO(p1b) * w1b;
|
|
s += GetPackedAO(p2a) * w2a;
|
|
s += GetPackedAO(p2b) * w2b;
|
|
s *= rcp(w0 + w1a + w1b + w2a + w2b);
|
|
|
|
return PackAOAndNormal(s, n0);
|
|
}
|
|
|
|
float2 SampleMotionVectors(TEXTURE2D_X_PARAM(motionVectors, samplerMotionVectors), float2 uv)
|
|
{
|
|
return SAMPLE_TEXTURE2D_X_LOD(motionVectors, samplerMotionVectors, UnityStereoTransformScreenSpaceTex(uv), 0).xy;
|
|
}
|
|
|
|
// HDRP-style temporal denoise neighborhood on the blurred AO texture.
|
|
float3 FindMinMaxAvgAO(TEXTURE2D_X(blurredAO), uint2 centralPixelCoords)
|
|
{
|
|
float minAO = 2.0;
|
|
float maxAO = -2.0;
|
|
float avg = 0.0;
|
|
const int2 maxCoord = int2(DOWNSAMPLED_SCREEN_SIZE) - 1;
|
|
for (int i = -1; i <= 1; ++i)
|
|
{
|
|
for (int j = -1; j <= 1; ++j)
|
|
{
|
|
int2 p = clamp(int2(centralPixelCoords) + int2(i, j), 0, maxCoord);
|
|
half currAO = half(LOAD_TEXTURE2D_X_LOD(blurredAO, p, 0).r);
|
|
avg += currAO;
|
|
minAO = min(minAO, currAO);
|
|
maxAO = max(maxAO, currAO);
|
|
}
|
|
}
|
|
|
|
return float3(minAO, maxAO, avg * (1.0 / 9.0));
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// GTAO Compute Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void ComputeAO(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
half temporalRotation = 0;
|
|
uint temporalOffset = 0u;
|
|
#if defined(_TEMPORAL_FILTERING)
|
|
temporalRotation = _SSAOTemporalRotation;
|
|
temporalOffset = _SSAOTemporalOffset;
|
|
#endif
|
|
|
|
GTAOConfig config = CreateGTAOConfig(_SSAOParams, _SSAOParams2, _AODepthToViewParams, BlueNoiseScale, BlueNoiseOffset, temporalRotation, temporalOffset);
|
|
|
|
float2 positionSS = float2(pixelCoords) + 0.5;
|
|
float2 uv = positionSS * DOWNSAMPLED_TEXEL_SIZE;
|
|
uint2 fullResCoords = uint2(positionSS * rcp(config.downsample));
|
|
|
|
float centerRawDepth = LoadSceneDepth(fullResCoords);
|
|
float centerLinearDepth = GetLinearEyeDepth(centerRawDepth);
|
|
half centerHalfLinearDepth = half(centerLinearDepth);
|
|
half3 centerNormal = half3(LoadSceneNormals(fullResCoords));
|
|
|
|
if (ShouldSkipAO(centerRawDepth, centerHalfLinearDepth, config.falloff))
|
|
{
|
|
_AOOutput[pixelCoords] = PackAOAndNormal(HALF_ZERO, centerNormal);
|
|
return;
|
|
}
|
|
|
|
float3 positionVS = GetPositionVS(positionSS, centerRawDepth, config.depthToViewParams);
|
|
half3 V = GetViewVectorVS(positionVS);
|
|
|
|
half ao = EvaluateGTAOValue(config, uv, positionSS, positionVS, V, centerNormal, centerLinearDepth);
|
|
_AOOutput[pixelCoords] = PackAOAndNormal(ao, centerNormal);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bilateral Blur Horizontal Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void BilateralBlurH(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
float2 uv = (float2(pixelCoords) + 0.5) * DOWNSAMPLED_TEXEL_SIZE;
|
|
float2 delta = float2(DOWNSAMPLED_TEXEL_SIZE.x, 0.0);
|
|
half4 result = ComputeBilateralBlur(TEXTURE2D_X_ARGS(_BlitTexture, sampler_BlitTexture), uv, delta);
|
|
_BlurOutput[pixelCoords] = result;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bilateral Blur Vertical Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void BilateralBlurV(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
float2 uv = (float2(pixelCoords) + 0.5) * DOWNSAMPLED_TEXEL_SIZE;
|
|
float2 delta = float2(0.0, DOWNSAMPLED_TEXEL_SIZE.y);
|
|
half4 result = ComputeBilateralBlur(TEXTURE2D_X_ARGS(_BlitTexture, sampler_BlitTexture), uv, delta);
|
|
_BlurOutput[pixelCoords] = result;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// GTAO Box Spatial Filter Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void BoxSpatialFilter(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
const float invDownsample = rcp(DOWNSAMPLE);
|
|
const int2 downsampledScreenMax = int2(DOWNSAMPLED_SCREEN_SIZE) - 1;
|
|
const int2 pixelCoordsI = int2(pixelCoords);
|
|
const float2 positionSS = float2(pixelCoords) + 0.5;
|
|
const uint2 fullResCoords = uint2(positionSS * invDownsample);
|
|
|
|
half4 center = half4(LOAD_TEXTURE2D_X_LOD(_BlitTexture, pixelCoords, 0));
|
|
half centerAO = GetPackedAO(center);
|
|
half3 centerNormal = GetPackedNormal(center);
|
|
|
|
half temporalRotation = 0;
|
|
uint temporalOffset = 0u;
|
|
#if defined(_TEMPORAL_FILTERING)
|
|
temporalRotation = _SSAOTemporalRotation;
|
|
temporalOffset = _SSAOTemporalOffset;
|
|
#endif
|
|
|
|
GTAOConfig config = CreateGTAOConfig(_SSAOParams, _SSAOParams2, _AODepthToViewParams, BlueNoiseScale, BlueNoiseOffset, temporalRotation, temporalOffset);
|
|
float centerRawDepth = LoadSceneDepth(fullResCoords);
|
|
float centerLinearDepth = GetLinearEyeDepth(centerRawDepth);
|
|
|
|
if (ShouldSkipAO(centerRawDepth, half(centerLinearDepth), config.falloff))
|
|
{
|
|
_BlurOutput[pixelCoords] = PackAOAndNormal(HALF_ZERO, centerNormal);
|
|
return;
|
|
}
|
|
|
|
float3 centerPositionVS = GetPositionVS(positionSS, centerRawDepth, config.depthToViewParams);
|
|
half3 centerNormalVS = TransformWorldToViewNormal(centerNormal);
|
|
centerNormalVS = half3(centerNormalVS.xy, -centerNormalVS.z);
|
|
float planeDistance = dot(centerPositionVS, float3(centerNormalVS));
|
|
|
|
float sumAO = centerAO;
|
|
float sumWeight = 1.0;
|
|
|
|
const static int2 sampleOffsets[4] =
|
|
{
|
|
int2(-1, 0),
|
|
int2( 0, -1),
|
|
int2( 1, 0),
|
|
int2( 0, 1)
|
|
};
|
|
|
|
float filterStep = max(_GTAOBoxFilterStep * DOWNSAMPLE, 1.0);
|
|
|
|
UNITY_UNROLL
|
|
for (uint i = 0u; i < 4u; ++i)
|
|
{
|
|
int2 sampleOffset = int2(round(float2(sampleOffsets[i]) * filterStep));
|
|
int2 samplePixelCoords = clamp(pixelCoordsI + sampleOffset, int2(0, 0), downsampledScreenMax);
|
|
half4 sampleValue = half4(LOAD_TEXTURE2D_X_LOD(_BlitTexture, samplePixelCoords, 0));
|
|
half sampleAO = GetPackedAO(sampleValue);
|
|
half3 sampleNormal = GetPackedNormal(sampleValue);
|
|
|
|
float2 samplePositionSS = float2(samplePixelCoords) + 0.5;
|
|
uint2 sampleFullResCoords = uint2(samplePositionSS * invDownsample);
|
|
float sampleRawDepth = LoadSceneDepth(sampleFullResCoords);
|
|
float3 samplePositionVS = GetPositionVS(samplePositionSS, sampleRawDepth, config.depthToViewParams);
|
|
|
|
float planeDelta = abs(dot(samplePositionVS, float3(centerNormalVS)) - planeDistance);
|
|
float depthDifference = planeDelta / max(centerLinearDepth, 1.0e-4);
|
|
float depthWeight = exp(-kDepthRejectionScale * depthDifference);
|
|
float normalWeight = pow(max(0.0, dot(centerNormal, sampleNormal)), kNormalRejectionPower);
|
|
float sampleWeight = depthWeight * normalWeight;
|
|
|
|
sumAO += float(sampleAO) * sampleWeight;
|
|
sumWeight += sampleWeight;
|
|
}
|
|
|
|
half filteredAO = half(sumAO * rcp(max(sumWeight, 1.0e-4)));
|
|
_BlurOutput[pixelCoords] = PackAOAndNormal(filteredAO, centerNormal);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Temporal Filter Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void TemporalFilter(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
float2 uv = (float2(pixelCoords) + 0.5) * DOWNSAMPLED_TEXEL_SIZE;
|
|
half temporalRotation = 0;
|
|
uint temporalOffset = 0u;
|
|
#if defined(_TEMPORAL_FILTERING)
|
|
temporalRotation = _SSAOTemporalRotation;
|
|
temporalOffset = _SSAOTemporalOffset;
|
|
#endif
|
|
GTAOConfig config = CreateGTAOConfig(_SSAOParams, _SSAOParams2, _AODepthToViewParams, BlueNoiseScale, BlueNoiseOffset, temporalRotation, temporalOffset);
|
|
uint2 fullResCoords = uint2((float2(pixelCoords) + 0.5) * rcp(config.downsample));
|
|
float currDepth = LoadSceneDepth(fullResCoords);
|
|
|
|
bool outputPackedNormal = _GTAOSpatialFilter == kGTAOSpatialFilterBilateral;
|
|
half4 currValue = half4(LOAD_TEXTURE2D_X_LOD(_BlitTexture, pixelCoords, 0));
|
|
half currAO = currValue.r;
|
|
|
|
if (currDepth == UNITY_RAW_FAR_CLIP_VALUE || currDepth < SKY_DEPTH_VALUE)
|
|
{
|
|
_OcclusionTexture[pixelCoords] = outputPackedNormal
|
|
? half4(HALF_ZERO, currValue.g, currValue.b, currValue.a)
|
|
: half4(HALF_ZERO, HALF_ZERO, HALF_ZERO, HALF_ONE);
|
|
_AOOutputHistory[pixelCoords] = half4(CreateHistoryData(0.0, 0.0, 0.0));
|
|
return;
|
|
}
|
|
|
|
float2 velocity = SampleMotionVectors(TEXTURE2D_X_ARGS(_MotionVectorTexture, sampler_PointClamp), uv);
|
|
float motionVecLength = length(velocity);
|
|
float motionVecWeighting = saturate(motionVecLength * kMotionWeightScale);
|
|
|
|
float2 historyUV = uv - velocity;
|
|
bool validHistoryUV = historyUV.x >= 0.0 && historyUV.x <= 1.0 && historyUV.y >= 0.0 && historyUV.y <= 1.0;
|
|
|
|
float2 historyUVStereo = UnityStereoTransformScreenSpaceTex(historyUV);
|
|
|
|
float2 prevHistoryData = SAMPLE_TEXTURE2D_X_LOD(_AOPackedHistory, sampler_LinearClamp, historyUVStereo, 0).zw;
|
|
float prevAO = prevHistoryData.x;
|
|
float prevNormalizedHistoryFrameCount = saturate(prevHistoryData.y);
|
|
|
|
float2 prevPackedDepth = SAMPLE_TEXTURE2D_X_LOD(_AOPackedHistory, sampler_PointClamp, historyUVStereo, 0).xy;
|
|
float prevDepth = UnpackFloatFromR8G8Safe(prevPackedDepth);
|
|
|
|
float3 minMaxAvg = FindMinMaxAvgAO(_BlitTexture, pixelCoords);
|
|
float minAO = minMaxAvg.x;
|
|
float maxAO = minMaxAvg.y;
|
|
float avgAO = minMaxAvg.z;
|
|
|
|
float motionStability = 1.0 - motionVecWeighting;
|
|
float ghostingMitigation = saturate(_SSAOGhostingMitigation);
|
|
float spatialCoherence = saturate(1.0 - kCoherenceContrastScale * abs(avgAO - currAO));
|
|
|
|
float clampStrength = ghostingMitigation * motionStability * spatialCoherence;
|
|
float clampedPrevAO = clamp(prevAO, minAO - kClampMargin, maxAO + kClampMargin);
|
|
prevAO = lerp(prevAO, clampedPrevAO, clampStrength);
|
|
|
|
float depthRatio = prevDepth / max(currDepth, 1e-6);
|
|
bool depthValid = depthRatio >= kHistoryDepthRatioMin && depthRatio <= kHistoryDepthRatioMax;
|
|
|
|
float historyLength = saturate(_SSAOHistoryLength);
|
|
float historyValidity = (validHistoryUV && depthValid) ? 1.0 : 0.0;
|
|
float maxHistoryFrameCount = lerp(1.0, kMaxTemporalHistoryFrameCount, historyLength);
|
|
float prevHistoryFrameCount = prevNormalizedHistoryFrameCount * kMaxTemporalHistoryFrameCount;
|
|
float retainedHistoryFrameCount = prevHistoryFrameCount * historyValidity * motionStability;
|
|
float historyFrameCount = min(retainedHistoryFrameCount + 1.0, maxHistoryFrameCount);
|
|
|
|
float currentFrameWeight = rcp(historyFrameCount);
|
|
float newAO = lerp(prevAO, currAO, currentFrameWeight);
|
|
half4 occlusionResult = outputPackedNormal
|
|
? half4(newAO, currValue.g, currValue.b, currValue.a)
|
|
: half4(newAO, newAO, newAO, HALF_ONE);
|
|
float rcpHistoryFrameCount = historyFrameCount * kInvMaxTemporalHistoryFrameCount;
|
|
float4 historyPacked = CreateHistoryData(newAO, currDepth, rcpHistoryFrameCount);
|
|
|
|
_OcclusionTexture[pixelCoords] = occlusionResult;
|
|
_AOOutputHistory[pixelCoords] = half4(historyPacked);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Copy History Kernel
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void CopyHistory(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
if (any(pixelCoords >= DOWNSAMPLED_SCREEN_SIZE))
|
|
return;
|
|
|
|
half ao = half(LOAD_TEXTURE2D_X_LOD(_BlitTexture, pixelCoords, 0).r);
|
|
GTAOConfig config = CreateGTAOConfig(_SSAOParams, _SSAOParams2, _AODepthToViewParams, BlueNoiseScale, BlueNoiseOffset, 0, 0u);
|
|
uint2 fullResCoords = uint2((float2(pixelCoords) + 0.5) * rcp(config.downsample));
|
|
float depth = LoadSceneDepth(fullResCoords);
|
|
if (depth == UNITY_RAW_FAR_CLIP_VALUE || depth < SKY_DEPTH_VALUE)
|
|
{
|
|
_AOOutputHistory[pixelCoords] = half4(CreateHistoryData(0.0, 0.0, 0.0));
|
|
return;
|
|
}
|
|
|
|
_AOOutputHistory[pixelCoords] = half4(CreateHistoryData(ao, depth, kInvMaxTemporalHistoryFrameCount));
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Final Blit Kernel (Non-AfterOpaque)
|
|
// Inverts AO and writes to final output texture at full resolution
|
|
// ------------------------------------------------------------------
|
|
[numthreads(SSAO_GROUP_SIZE, SSAO_GROUP_SIZE, 1)]
|
|
void FinalBlit(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
const uint2 pixelCoords = dispatchThreadId.xy;
|
|
const uint2 fullResScreenSize = uint2(_SourceSize.xy);
|
|
|
|
if (any(pixelCoords >= fullResScreenSize))
|
|
return;
|
|
|
|
// UV is in full resolution space, sample from downsampled AO texture
|
|
float2 uv = (float2(pixelCoords) + 0.5) * _SourceSize.zw;
|
|
|
|
// Invert AO to match fragment shader behavior (FinalBlur: HALF_ONE - ao)
|
|
half ao = SSAO_COMMON_SAMPLE_BASEMAP_R(uv);
|
|
ao = HALF_ONE - ao;
|
|
|
|
_FinalOutput[pixelCoords] = half4(ao, ao, ao, HALF_ONE);
|
|
}
|