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.
190 lines
8.6 KiB
190 lines
8.6 KiB
#pragma only_renderers d3d11 xboxseries ps5
|
|
|
|
#pragma kernel BilateralFilterHSingleDirectional BILATERAL_FILTER=BilateralFilterHSingleDirectional SINGLE_CHANNEL DIRECTIONAL_LIGHT
|
|
#pragma kernel BilateralFilterVSingleDirectional BILATERAL_FILTER=BilateralFilterVSingleDirectional FINAL_PASS SINGLE_CHANNEL DIRECTIONAL_LIGHT
|
|
|
|
#pragma kernel BilateralFilterHColorDirectional BILATERAL_FILTER=BilateralFilterHColorDirectional DIRECTIONAL_LIGHT
|
|
#pragma kernel BilateralFilterVColorDirectional BILATERAL_FILTER=BilateralFilterVColorDirectional FINAL_PASS DIRECTIONAL_LIGHT
|
|
|
|
#pragma kernel BilateralFilterHSinglePoint BILATERAL_FILTER=BilateralFilterHSinglePoint SINGLE_CHANNEL POINT_LIGHT
|
|
#pragma kernel BilateralFilterVSinglePoint BILATERAL_FILTER=BilateralFilterVSinglePoint FINAL_PASS SINGLE_CHANNEL POINT_LIGHT
|
|
|
|
#pragma kernel BilateralFilterHSingleSpot BILATERAL_FILTER=BilateralFilterHSingleSpot SINGLE_CHANNEL SPOT_LIGHT
|
|
#pragma kernel BilateralFilterVSingleSpot BILATERAL_FILTER=BilateralFilterVSingleSpot FINAL_PASS SINGLE_CHANNEL SPOT_LIGHT
|
|
|
|
#pragma kernel BilateralFilterHSinglePyramid BILATERAL_FILTER=BilateralFilterHSinglePyramid SINGLE_CHANNEL PYRAMID_LIGHT
|
|
#pragma kernel BilateralFilterVSinglePyramid BILATERAL_FILTER=BilateralFilterVSinglePyramid FINAL_PASS SINGLE_CHANNEL PYRAMID_LIGHT
|
|
|
|
#pragma kernel BilateralFilterHSingleBox BILATERAL_FILTER=BilateralFilterHSingleBox SINGLE_CHANNEL BOX_LIGHT
|
|
#pragma kernel BilateralFilterVSingleBox BILATERAL_FILTER=BilateralFilterVSingleBox FINAL_PASS SINGLE_CHANNEL BOX_LIGHT
|
|
|
|
#pragma multi_compile _ DISTANCE_BASED_DENOISER
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.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/RaytracingSampling.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Builtin/BuiltinData.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/TemporalAntialiasing.hlsl"
|
|
#define BILATERLAL_UNLIT
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Denoising/BilateralFilter.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/RayTracingShadowUtilities.hlsl"
|
|
|
|
#pragma only_renderers d3d11 xboxseries ps5
|
|
|
|
// #pragma enable_d3d11_debug_symbols
|
|
|
|
// Tile size of this compute
|
|
#define SHADOW_DENOISER_TILE_SIZE 8
|
|
|
|
// Ray tracing input textures
|
|
TEXTURE2D_X(_DenoiseInputTexture);
|
|
TEXTURE2D_X(_DistanceTexture);
|
|
|
|
// Generic denoiser inputs
|
|
int _DenoiserFilterRadius;
|
|
|
|
// Camera FOV
|
|
float _CameraFOV;
|
|
|
|
// Inputs for sphere lights (point and spot)
|
|
float3 _SphereLightPosition;
|
|
|
|
// Output texture
|
|
#if SINGLE_CHANNEL
|
|
RW_TEXTURE2D_X(float, _DenoiseOutputTextureRW);
|
|
#else
|
|
RW_TEXTURE2D_X(float4, _DenoiseOutputTextureRW);
|
|
#endif
|
|
|
|
// Separated bilateral filter (two passes, each with 2*Radius taps)
|
|
[numthreads(SHADOW_DENOISER_TILE_SIZE, SHADOW_DENOISER_TILE_SIZE, 1)]
|
|
void BILATERAL_FILTER(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Fetch the current pixel coordinate
|
|
int2 centerCoord = groupId * SHADOW_DENOISER_TILE_SIZE + groupThreadId;
|
|
|
|
// Read the center pixel0
|
|
const BilateralData center = TapBilateralData(centerCoord);
|
|
|
|
#if SPOT_LIGHT || PYRAMID_LIGHT || BOX_LIGHT || POINT_LIGHT
|
|
// Fetch the data of the area light
|
|
LightData lightData = _LightDatas[_RaytracingTargetLight];
|
|
#endif
|
|
|
|
#if defined(DISTANCE_BASED_DENOISER)
|
|
#if DIRECTIONAL_LIGHT
|
|
// For the directonal light, the solid angle can be used directly
|
|
float lightSolidAngle = _RaytracingLightAngle;
|
|
#else
|
|
// Compute the light distance
|
|
#if BOX_LIGHT
|
|
float lightPointDistance = dot(_SphereLightPosition - center.position, normalize(-lightData.forward));
|
|
#else
|
|
float lightPointDistance = length(_SphereLightPosition - center.position);
|
|
#endif
|
|
// Evaluate the normalized solid angle of the light
|
|
float lightSolidAngle = atan(_RaytracingLightRadius / lightPointDistance);
|
|
#endif
|
|
// Compute the distances we need for our filtering
|
|
const float distanceCameraToPlane = length(GetWorldSpaceViewDir(center.position));
|
|
const float distancePlaneToObject = LOAD_TEXTURE2D_X(_DistanceTexture, centerCoord).x;
|
|
|
|
// Compute the cone footprint on the image reflection plane for this configuration
|
|
const float brdfConeRadius = tan(lightSolidAngle * 0.5) * distancePlaneToObject * 2.0f;
|
|
|
|
// We need to compute the view cone radius
|
|
const float viewConeRadius = brdfConeRadius * distanceCameraToPlane / (distancePlaneToObject + distanceCameraToPlane);
|
|
|
|
// Compute the view cone's half angle. This matches the FOV angle to see exactly the half of the cone (The tangent could be precomputed in the table)
|
|
const float viewConeHalfAngle = FastATanPos(viewConeRadius / distanceCameraToPlane);
|
|
// Given the camera's fov and pixel resolution convert the viewConeHalfAngle to a number of pixels
|
|
const float pixelDistance = viewConeHalfAngle / _CameraFOV * _ScreenSize.x;
|
|
|
|
// Evaluate the radius that should be used for the filter
|
|
#if FINAL_PASS
|
|
const float radius = clamp(pixelDistance, 1, _DenoiserFilterRadius);
|
|
#else
|
|
const float radius = clamp(pixelDistance, 1, _DenoiserFilterRadius);
|
|
#endif
|
|
// Compute the sigma value for our filter
|
|
const float sigma = 0.5 * radius;
|
|
#else
|
|
const float sigma = 0.5 * _DenoiserFilterRadius;
|
|
const int radius = min(sigma * 2.0, _DenoiserFilterRadius);
|
|
#endif
|
|
|
|
// Initialize the accumulation variables
|
|
#if SINGLE_CHANNEL
|
|
float colorSum = 0.0;
|
|
#else
|
|
float3 colorSum = float3(0.0, 0.0, 0.0);
|
|
#endif
|
|
float wSum = 0.0;
|
|
|
|
// Based on if we are horizontal of vertical, define our increment direction
|
|
#if FINAL_PASS
|
|
const int2 passIncr = int2(1, 0);
|
|
#else
|
|
const int2 passIncr = int2(0, 1);
|
|
#endif
|
|
|
|
|
|
// Evaluate the filter
|
|
int2 tapCoord = centerCoord - radius * passIncr;
|
|
for (int r = -radius; r <= radius; ++r, tapCoord += passIncr)
|
|
{
|
|
// We should not tap outside of the screen (given that its a unit, if we go below zero we wrap around)
|
|
if (tapCoord.x >= _ScreenSize.x || tapCoord.y >= _ScreenSize.y || tapCoord.x < 0 || tapCoord.y < 0)
|
|
continue;
|
|
|
|
// Grab the data of the tap pixel
|
|
const BilateralData tapData = TapBilateralData(tapCoord);
|
|
|
|
// Compute the weight (skip computation for the center)
|
|
float w = r ? gaussian(r, sigma) * ComputeBilateralWeight(center, tapData) : 1.0;
|
|
w = tapData.isUnlit ? 0.0 : w;
|
|
|
|
#if POINT_LIGHT
|
|
float dist2 = DistSqrToLight(lightData, tapData.position);
|
|
w = PositionInPointRange(lightData, dist2) ? w : 0.0;
|
|
#endif
|
|
|
|
#if SPOT_LIGHT
|
|
float dist2 = DistSqrToLight(lightData, tapData.position);
|
|
w = PositionInSpotRange(lightData, _RaytracingLightAngle, tapData.position, dist2) ? w : 0.0;
|
|
#endif
|
|
|
|
#if PYRAMID_LIGHT
|
|
float dist2 = DistSqrToLight(lightData, tapData.position);
|
|
w = PositionInPyramidRange(lightData, _RaytracingLightSizeX, _RaytracingLightSizeY, tapData.position, dist2) ? w : 0.0;
|
|
#endif
|
|
|
|
#if BOX_LIGHT
|
|
float dist = dot(lightData.positionRWS - tapData.position, normalize(-lightData.forward));
|
|
w = PositionInBoxRange(lightData, _RaytracingLightSizeX, _RaytracingLightSizeY, tapData.position, dist * dist) ? w : 0.0;
|
|
#endif
|
|
|
|
// Accumulate the color
|
|
#if SINGLE_CHANNEL
|
|
colorSum += LOAD_TEXTURE2D_X(_DenoiseInputTexture, tapCoord).x * w;
|
|
#else
|
|
colorSum += LOAD_TEXTURE2D_X(_DenoiseInputTexture, tapCoord).xyz * w;
|
|
#endif
|
|
|
|
// Accumulate its weight
|
|
wSum += w;
|
|
}
|
|
|
|
// Normalize and store the value
|
|
#if SINGLE_CHANNEL
|
|
float finalColor = wSum != 0.0 ? colorSum / wSum : 0.0;
|
|
_DenoiseOutputTextureRW[COORD_TEXTURE2D_X(centerCoord)] = finalColor;
|
|
#else
|
|
float3 finalColor = wSum != 0.0 ? colorSum / wSum : 0.0;
|
|
_DenoiseOutputTextureRW[COORD_TEXTURE2D_X(centerCoord)] = float4(finalColor, 1.0);
|
|
#endif
|
|
}
|