You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
10 KiB
243 lines
10 KiB
#pragma kernel PreBlur
|
|
|
|
#pragma only_renderers d3d11 xboxseries ps5
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/ReBlur/ReBlur_BlurUtilities.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/ReBlurDenoiser.cs.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingCommon.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/ShaderVariablesRaytracing.cs.hlsl"
|
|
|
|
// Bilateral filtering
|
|
#define BILATERAL_ROUGHNESS
|
|
#define BILATERLAL_UNLIT
|
|
#define BILATERLAL_SSR
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl"
|
|
|
|
#define REBLUR_PREPASS_TILE_SIZE 8
|
|
|
|
#pragma multi_compile _ HALF_RESOLUTION
|
|
|
|
//#pragma enable_d3d11_debug_symbols
|
|
|
|
// Constants
|
|
#define PREPASS_BLUR_RADIUS 20.0
|
|
|
|
// #define WITHOUT_LDS
|
|
|
|
// Input texture
|
|
TEXTURE2D_X(_LightingInputTexture);
|
|
TEXTURE2D_X(_DistanceInputTexture);
|
|
|
|
// Output texture
|
|
RW_TEXTURE2D_X(float4, _LightingDistanceTextureRW);
|
|
|
|
#ifdef HALF_RESOLUTION
|
|
groupshared float3 gs_cacheLighting[36];
|
|
groupshared float gs_cacheDistance[36];
|
|
groupshared float gs_cacheDepth[36];
|
|
groupshared bool gs_cacheValidity[36];
|
|
|
|
void FillRegionLDS(uint groupIndex, uint2 groupOrigin)
|
|
{
|
|
// Define which value we will be acessing with this worker thread
|
|
int acessCoordX = groupIndex % 6;
|
|
int acessCoordY = groupIndex / 6;
|
|
|
|
// The initial position of the access
|
|
int2 originXY = groupOrigin / 2 - int2(1, 1);
|
|
|
|
// Compute the sample position
|
|
int2 sampleCoord = int2(clamp(originXY.x + acessCoordX, 0, _ScreenSize.x / 2 - 1), clamp(originXY.y + acessCoordY, 0, _ScreenSize.y / 2 - 1));
|
|
|
|
// The representative coordinate to use depends if we are using the checkerboard integration pattern (or not)
|
|
int2 representativeCoord = ComputeSourceCoordinates(sampleCoord, _RayTracingCheckerIndex);
|
|
|
|
// Read the depth value and linearize it
|
|
float sampleDepth = LOAD_TEXTURE2D_X(_DepthTexture, representativeCoord).x;
|
|
gs_cacheDepth[groupIndex] = Linear01Depth(sampleDepth, _ZBufferParams);
|
|
|
|
// Evaluate if the the pixel's data can be used (if it is not unlit, has receive SSR and has the right smoothness value)
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, representativeCoord));
|
|
bool validity = (stencilValue & STENCILUSAGE_IS_UNLIT) == 0;
|
|
validity = validity && (stencilValue & STENCILUSAGE_TRACE_REFLECTION_RAY) != 0;
|
|
validity = validity && (sampleDepth != UNITY_RAW_FAR_CLIP_VALUE);
|
|
gs_cacheValidity[groupIndex] = validity;
|
|
|
|
// Read the lighting data
|
|
float3 sampleLighting = LOAD_TEXTURE2D_X(_LightingInputTexture, sampleCoord).xyz;
|
|
gs_cacheLighting[groupIndex] = sampleLighting;
|
|
|
|
// Read the distance data
|
|
float sampleDistance = LOAD_TEXTURE2D_X(_DistanceInputTexture, sampleCoord).x;
|
|
gs_cacheDistance[groupIndex] = sampleDistance;
|
|
}
|
|
|
|
uint OffsetToLDSAdress(uint2 groupThreadId, int2 offset)
|
|
{
|
|
// Compute the tap coordinate in the 6x6 grid
|
|
uint2 tapAddress = (uint2)((int2)(groupThreadId / 2 + 1) + offset);
|
|
return clamp((uint)(tapAddress.x) % 6 + tapAddress.y * 6, 0, 35);
|
|
}
|
|
#endif
|
|
|
|
[numthreads(REBLUR_PREPASS_TILE_SIZE, REBLUR_PREPASS_TILE_SIZE, 1)]
|
|
void PreBlur(uint3 dispatchThreadId : SV_DispatchThreadID,
|
|
uint2 groupThreadId : SV_GroupThreadID,
|
|
int groupIndex : SV_GroupIndex,
|
|
uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
uint2 currentCoord = dispatchThreadId.xy;
|
|
|
|
#if defined(HALF_RESOLUTION) && !defined(WITHOUT_LDS)
|
|
// Only 36 workers of the 64 do the pre-fetching
|
|
if (groupIndex < 36)
|
|
{
|
|
// Load 1 value per thread
|
|
FillRegionLDS(groupIndex, groupId * 8);
|
|
}
|
|
// Make sure all values are loaded in LDS by now.
|
|
GroupMemoryBarrierWithGroupSync();
|
|
#endif
|
|
|
|
// Read the central position data
|
|
const BilateralData center = TapBilateralData(currentCoord);
|
|
|
|
// If this is a background pixel or an unlit one, we are done
|
|
if (center.z01 == 1.0 || center.isUnlit || !center.hasSSR)
|
|
{
|
|
_LightingDistanceTextureRW[COORD_TEXTURE2D_X(currentCoord)] = float4(0.0, 0.0, 0.0, -1);
|
|
return;
|
|
}
|
|
|
|
// Center distance
|
|
#if defined(HALF_RESOLUTION)
|
|
#if !defined(WITHOUT_LDS)
|
|
int halfResLDSIndex = OffsetToLDSAdress(groupThreadId, int2(0, 0));
|
|
float centerDistance = gs_cacheDistance[halfResLDSIndex];
|
|
#else
|
|
float centerDistance = LOAD_TEXTURE2D_X(_DistanceInputTexture, currentCoord / 2).x;
|
|
#endif
|
|
#else
|
|
float centerDistance = LOAD_TEXTURE2D_X(_DistanceInputTexture, currentCoord).x;
|
|
#endif
|
|
|
|
// Evaluate the blur radius
|
|
float blurRadius = ComputeBlurRadius(center.roughness, PREPASS_BLUR_RADIUS) * _ReBlurDenoiserRadius;
|
|
blurRadius *= HitDistanceAttenuation(center.roughness, length(center.position), centerDistance);
|
|
|
|
// Evaluate the UV coordinates of the pixel
|
|
float2 currentUV = (currentCoord + 0.5) * _ScreenSize.zw;
|
|
|
|
// Loop through the samples
|
|
float4 signalSum = 0.0;
|
|
float sumWeight = 0.0;
|
|
for (uint sampleIndex = 0; sampleIndex < POISSON_SAMPLE_COUNT; ++sampleIndex)
|
|
{
|
|
// Pick the next sample value
|
|
float3 offset = k_PoissonDiskSamples[sampleIndex];
|
|
|
|
// Evaluate the tap uv
|
|
float2 uv = currentUV + RotateVector(_ReBlurPreBlurRotator, offset.xy) * _ScreenSize.zw * blurRadius;
|
|
|
|
// Evaluate the tap coordinates
|
|
float2 tapCoord = uv * _ScreenSize.xy;
|
|
|
|
// If we are working in half resolution, we need to pick which up-resolution pixel was used to generate the current frame data.
|
|
#if defined(HALF_RESOLUTION)
|
|
tapCoord = ComputeSourceCoordinates(tapCoord / 2, _RayTracingCheckerIndex);
|
|
#endif
|
|
|
|
// Fetch the corresponding data
|
|
const BilateralData tapData = TapBilateralData(tapCoord);
|
|
|
|
// Sample weights
|
|
float w = GetGaussianWeight(offset.z);
|
|
w *= ComputeBilateralWeight(center, tapData);
|
|
w *= tapData.z01 != 1.0 ? 1.0 : 0.0;
|
|
w = UVInScreen(uv) ? w : 0.0;
|
|
w = tapData.hasSSR ? w : 0.0;
|
|
|
|
#if defined(HALF_RESOLUTION)
|
|
// Fetch the full resolution depth
|
|
float3 lighting = LOAD_TEXTURE2D_X(_LightingInputTexture, tapCoord / 2).xyz;
|
|
float distance = LOAD_TEXTURE2D_X(_DistanceInputTexture, tapCoord / 2).x;
|
|
#else
|
|
// Fetch the full resolution depth
|
|
float3 lighting = LOAD_TEXTURE2D_X(_LightingInputTexture, tapCoord).xyz;
|
|
float distance = LOAD_TEXTURE2D_X(_DistanceInputTexture, tapCoord).x;
|
|
#endif
|
|
|
|
// Accumulate
|
|
signalSum += float4(lighting, distance) * w;
|
|
sumWeight += w;
|
|
}
|
|
|
|
// If none of the samples picked are usable, use the central pixel
|
|
float4 finalSignal;
|
|
if (sumWeight != 0.0)
|
|
{
|
|
finalSignal = signalSum / sumWeight;
|
|
}
|
|
else
|
|
{
|
|
// If we are
|
|
#if defined(HALF_RESOLUTION)
|
|
float4 fallbackLighting = 0.0;
|
|
float weightSum = 0.0;
|
|
for (int y = -1; y <= 1; ++y)
|
|
{
|
|
for (int x = -1; x <= 1; ++x)
|
|
{
|
|
// Evaluate the initial weight
|
|
float radius = sqrt(x * x + y * y);
|
|
float weight = gaussian(radius, 0.9);
|
|
|
|
#if !defined(WITHOUT_LDS)
|
|
// Compute the LDS index of this half res tap
|
|
int tapHalfResLDSIndex = OffsetToLDSAdress(groupThreadId, int2(x, y));
|
|
float tapDepth = gs_cacheDepth[tapHalfResLDSIndex];
|
|
#else
|
|
int2 halfResCoord = currentCoord / 2 + int2(x,y);
|
|
int2 representativeCoord = ComputeSourceCoordinates(halfResCoord, _RayTracingCheckerIndex);
|
|
float tapDepth = Linear01Depth(LOAD_TEXTURE2D_X(_DepthTexture, representativeCoord).x, _ZBufferParams);
|
|
#endif
|
|
|
|
// Make sure the depth is not a background depth and is similar to the final one
|
|
weight *= ((tapDepth != 1.0) ? 1.0 : 0.0);
|
|
weight *= (((abs(tapDepth - center.z01) < center.z01 * 0.1)) ? 1.0 : 0.0);
|
|
|
|
// Make sure the pixel has a valid signal
|
|
#if !defined(WITHOUT_LDS)
|
|
weight *= gs_cacheValidity[tapHalfResLDSIndex] ? 1.0 : 0.0;
|
|
#else
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, representativeCoord));
|
|
bool validity = (stencilValue & STENCILUSAGE_IS_UNLIT) == 0;
|
|
validity = validity && ((stencilValue & STENCILUSAGE_TRACE_REFLECTION_RAY) != 0);
|
|
weight *= (validity ? 1.0 : 0.0);
|
|
#endif
|
|
|
|
// Add the contribution of the sample
|
|
#if !defined(WITHOUT_LDS)
|
|
fallbackLighting += float4(gs_cacheLighting[tapHalfResLDSIndex], gs_cacheDistance[tapHalfResLDSIndex]) * weight;
|
|
#else
|
|
fallbackLighting += float4(LOAD_TEXTURE2D_X(_LightingInputTexture, halfResCoord).xyz, LOAD_TEXTURE2D_X(_DistanceInputTexture, halfResCoord).x) * weight;
|
|
#endif
|
|
weightSum += weight;
|
|
}
|
|
}
|
|
|
|
// After all of this, it is still possible that we're not able to find a candidate to upscale, in that case, there is nothing we can do, so the signal is going to be black.
|
|
finalSignal = weightSum == 0.0 ? float4(0, 0, 0, 0) : fallbackLighting / weightSum;
|
|
#else
|
|
finalSignal = float4(LOAD_TEXTURE2D_X(_LightingInputTexture, currentCoord).xyz, centerDistance);
|
|
#endif
|
|
}
|
|
|
|
// Normalize the result
|
|
_LightingDistanceTextureRW[COORD_TEXTURE2D_X(currentCoord)] = finalSignal;
|
|
}
|