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.
291 lines
13 KiB
291 lines
13 KiB
#pragma kernel RaytracingReflectionsFullRes
|
|
#pragma kernel RaytracingReflectionsHalfRes
|
|
|
|
#pragma kernel RaytracingReflectionsTransparentFullRes
|
|
#pragma kernel RaytracingReflectionsTransparentHalfRes
|
|
|
|
// Include and define the shader pass
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
|
|
#define SHADERPASS SHADERPASS_RAYTRACING
|
|
|
|
#pragma only_renderers d3d11 xboxseries ps5
|
|
|
|
// #pragma enable_d3d11_debug_symbols
|
|
|
|
// HDRP generic includes
|
|
#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/Material.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/NormalBuffer.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/ScreenSpaceLighting.hlsl"
|
|
|
|
// Raytracing includes
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/ShaderVariablesRaytracing.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingSampling.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingCommon.hlsl"
|
|
|
|
// Tile size of this compute
|
|
#define RAYTRACING_REFLECTIONS_TILE_SIZE 8
|
|
|
|
// Input data
|
|
TEXTURE2D_X(_DepthTexture);
|
|
TYPED_TEXTURE2D_X(uint2, _StencilTexture);
|
|
// Flag value that defines if a given pixel recieves reflections or not
|
|
int _SsrStencilBit;
|
|
TEXTURE2D_X(_SsrClearCoatMaskTexture);
|
|
|
|
// Output data
|
|
RW_TEXTURE2D_X(float4, _RaytracingDirectionBuffer);
|
|
|
|
// Structure that holds everything that defines a GGX sample
|
|
struct GGXSample
|
|
{
|
|
float3 direction;
|
|
float pdf;
|
|
};
|
|
|
|
GGXSample GenerateGGXSampleDirection(uint2 currentCoord, float3 normalWS, float3 viewWS, float roughness, int frameIndex)
|
|
{
|
|
// Create the local ortho basis
|
|
float3x3 localToWorld = GetLocalFrame(normalWS);
|
|
|
|
// Generate the new sample (follwing values of the sequence)
|
|
int initialFrameIndex = frameIndex;
|
|
float2 theSample;
|
|
theSample.x = GetBNDSequenceSample(currentCoord, initialFrameIndex, 0);
|
|
theSample.y = GetBNDSequenceSample(currentCoord, initialFrameIndex, 1);
|
|
|
|
// Importance sample the direction
|
|
float3 sampleDir = float3(0.0, 0.0, 0.0);
|
|
float NdotL, NdotH, VdotH;
|
|
SampleGGXDir(theSample, viewWS, localToWorld, roughness, sampleDir, NdotL, NdotH, VdotH);
|
|
|
|
// If this direction is under the surface, let's generate a new one that won't be.
|
|
// We allow ourselves 8 as the total of number of tries.
|
|
// TODO: use Eric's paper on visible normal distribution sampling
|
|
initialFrameIndex += 8;
|
|
for (int i = 1; i < 8; ++i)
|
|
{
|
|
if (dot(sampleDir, normalWS) >= 0.00f)
|
|
break;
|
|
|
|
theSample.x = GetBNDSequenceSample(currentCoord, initialFrameIndex + i, 0);
|
|
theSample.y = GetBNDSequenceSample(currentCoord, initialFrameIndex + i, 1);
|
|
SampleGGXDir(theSample, viewWS, localToWorld, roughness, sampleDir, NdotL, NdotH, VdotH);
|
|
}
|
|
|
|
// Build the sample and return it
|
|
GGXSample ggxSample;
|
|
ggxSample.direction = sampleDir;
|
|
// Given that GGX is invalid for a pure smooth material, we handle the case this by stating that the pdf == 1.0
|
|
ggxSample.pdf = roughness > 0.001 ? D_GGX(NdotH, roughness) * NdotH / (4.0 * VdotH) : 1.0;
|
|
return ggxSample;
|
|
}
|
|
|
|
// Function that evaluates the normal data for a given pixel
|
|
NormalData EvaluateNormalData(uint2 sourceCoord)
|
|
{
|
|
// Decode the world space normal
|
|
NormalData normalData;
|
|
DecodeFromNormalBuffer(sourceCoord, normalData);
|
|
|
|
// Override the roughness by the clearcoat value of this is a clear coat
|
|
float4 coatMask = LOAD_TEXTURE2D_X(_SsrClearCoatMaskTexture, sourceCoord);
|
|
normalData.perceptualRoughness = HasClearCoatMask(coatMask) ? CLEAR_COAT_SSR_PERCEPTUAL_ROUGHNESS : normalData.perceptualRoughness;
|
|
return normalData;
|
|
}
|
|
|
|
[numthreads(RAYTRACING_REFLECTIONS_TILE_SIZE, RAYTRACING_REFLECTIONS_TILE_SIZE, 1)]
|
|
void RaytracingReflectionsHalfRes(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the pixel position to process
|
|
uint2 halfResCoord = groupId * RAYTRACING_REFLECTIONS_TILE_SIZE + groupThreadId;
|
|
|
|
// Pixel coordinate in full res that we will be using to pick depth, normal and smoothness values.
|
|
uint2 sourceCoord = ComputeSourceCoordinates(halfResCoord, _RayTracingCheckerIndex);
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, sourceCoord).r;
|
|
|
|
// We initialize the output texture in case we early return. The last channel is set to -1.0 to mark the invalidity of the direction.
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(sourceCoord)] = float4(0.0, 0.0, 0.0, -1.0);
|
|
|
|
// This point is part of the background, we don't really care
|
|
if (depthValue == UNITY_RAW_FAR_CLIP_VALUE)
|
|
return;
|
|
|
|
// Does this pixel have SSR?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, sourceCoord));
|
|
if ((stencilValue & _SsrStencilBit) == 0)
|
|
return;
|
|
|
|
// Convert this to a world space position
|
|
PositionInputs posInput = GetPositionInput(sourceCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
|
|
|
|
// Compute the view vector
|
|
const float3 viewWS = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Decode the world space normal
|
|
NormalData normalData = EvaluateNormalData(sourceCoord);
|
|
|
|
// If this value is beyond the smoothness that we allow, no need to compute it
|
|
if (_RaytracingReflectionMinSmoothness > PerceptualRoughnessToPerceptualSmoothness(normalData.perceptualRoughness))
|
|
return;
|
|
|
|
// Create the local ortho basis
|
|
float3x3 localToWorld = GetLocalFrame(normalData.normalWS);
|
|
|
|
// Compute the actual roughness
|
|
float roughness = PerceptualRoughnessToRoughness(normalData.perceptualRoughness);
|
|
|
|
// Generate a GGX direction
|
|
GGXSample ggxSample = GenerateGGXSampleDirection(halfResCoord, normalData.normalWS, viewWS, roughness, _RayTracingReflectionFrameIndex);
|
|
|
|
// If we failed, return.
|
|
if (dot(ggxSample.direction, normalData.normalWS) <= 0.00f)
|
|
return;
|
|
|
|
// Store the generated direction and inverted PDF
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(sourceCoord)] = float4(ggxSample.direction, 1.0 / ggxSample.pdf);
|
|
}
|
|
|
|
[numthreads(RAYTRACING_REFLECTIONS_TILE_SIZE, RAYTRACING_REFLECTIONS_TILE_SIZE, 1)]
|
|
void RaytracingReflectionsTransparentHalfRes(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the pixel position to process
|
|
uint2 halfResCoord = groupId * RAYTRACING_REFLECTIONS_TILE_SIZE + groupThreadId;
|
|
|
|
// Pixel coordinate in full res that we will be using to pick depth and normal
|
|
uint2 sourceCoord = ComputeSourceCoordinates(halfResCoord, _RayTracingCheckerIndex);
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, sourceCoord).r;
|
|
|
|
// We initialize the output texture in case we early return. The last channel is set to -1.0 to mark the invalidity of the direction.
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(sourceCoord)] = float4(0.0, 0.0, 0.0, -1.0);
|
|
|
|
// This point is part of the background, we don't really care
|
|
if (depthValue == UNITY_RAW_FAR_CLIP_VALUE)
|
|
return;
|
|
|
|
// Does this pixel have SSR?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, sourceCoord));
|
|
if ((stencilValue & _SsrStencilBit) == 0)
|
|
return;
|
|
|
|
// Convert this to a world space position
|
|
PositionInputs posInput = GetPositionInput(sourceCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
|
|
|
|
// Compute the view vector
|
|
const float3 viewWS = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Decode the world space normal
|
|
NormalData normalData;
|
|
DecodeFromNormalBuffer(sourceCoord, normalData);
|
|
|
|
// If this value is beyond the smoothness that we allow, no need to compute it
|
|
if (_RaytracingReflectionMinSmoothness > PerceptualRoughnessToPerceptualSmoothness(normalData.perceptualRoughness))
|
|
return;
|
|
|
|
// Store the reflected direction and 1.0 in the w channel.
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(sourceCoord)] = float4(reflect(-viewWS, normalData.normalWS), 1.0);
|
|
}
|
|
|
|
[numthreads(RAYTRACING_REFLECTIONS_TILE_SIZE, RAYTRACING_REFLECTIONS_TILE_SIZE, 1)]
|
|
void RaytracingReflectionsFullRes(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the pixel position to process
|
|
uint2 currentCoord = groupId * RAYTRACING_REFLECTIONS_TILE_SIZE + groupThreadId;
|
|
|
|
// Clear the output color texture
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(currentCoord)] = float4(0.0, 0.0, 0.0, -1.0f);
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x;
|
|
|
|
// This point is part of the background, we don't really care
|
|
if (depthValue == UNITY_RAW_FAR_CLIP_VALUE)
|
|
return;
|
|
|
|
// Does this pixel have SSR?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord));
|
|
if ((stencilValue & _SsrStencilBit) == 0)
|
|
return;
|
|
|
|
// Convert this to a world space position
|
|
PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
|
|
|
|
// Compute the view vector
|
|
const float3 viewWS = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Decode the world space normal
|
|
NormalData normalData = EvaluateNormalData(currentCoord);
|
|
|
|
// If this value is beyond the smothness that we allow, no need to compute it
|
|
if (_RaytracingReflectionMinSmoothness > PerceptualRoughnessToPerceptualSmoothness(normalData.perceptualRoughness))
|
|
return;
|
|
|
|
// Create the local ortho basis
|
|
float3x3 localToWorld = GetLocalFrame(normalData.normalWS);
|
|
|
|
// Compute the actual roughness
|
|
float roughness = PerceptualRoughnessToRoughness(normalData.perceptualRoughness);
|
|
|
|
// Generate a GGX direction
|
|
GGXSample ggxSample = GenerateGGXSampleDirection(currentCoord, normalData.normalWS, viewWS, roughness, _RayTracingReflectionFrameIndex);
|
|
|
|
// If we failed, return.
|
|
if (dot(ggxSample.direction, normalData.normalWS) <= 0.00f)
|
|
return;
|
|
|
|
// Store the generated direction and inverted PDF
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(currentCoord)] = float4(ggxSample.direction, 1.0 / ggxSample.pdf);
|
|
}
|
|
|
|
[numthreads(RAYTRACING_REFLECTIONS_TILE_SIZE, RAYTRACING_REFLECTIONS_TILE_SIZE, 1)]
|
|
void RaytracingReflectionsTransparentFullRes(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the pixel position to process
|
|
uint2 currentCoord = groupId * RAYTRACING_REFLECTIONS_TILE_SIZE + groupThreadId;
|
|
|
|
// We initialize the output texture in case we early return. The last channel is set to -1.0 to mark the invalidity of the direction.
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(currentCoord)] = float4(0.0, 0.0, 0.0, -1.0f);
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x;
|
|
|
|
// This point is part of the background, we don't really care
|
|
if (depthValue == UNITY_RAW_FAR_CLIP_VALUE)
|
|
return;
|
|
|
|
// Does this pixel have SSR?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord));
|
|
if ((stencilValue & _SsrStencilBit) == 0)
|
|
return;
|
|
|
|
// Convert this to a world space position
|
|
PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
|
|
|
|
// Compute the view vector
|
|
const float3 viewWS = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Decode the world space normal
|
|
NormalData normalData;
|
|
DecodeFromNormalBuffer(currentCoord, normalData);
|
|
|
|
// If this value is beyond the smothness that we allow, no need to compute it
|
|
if (_RaytracingReflectionMinSmoothness > PerceptualRoughnessToPerceptualSmoothness(normalData.perceptualRoughness))
|
|
return;
|
|
|
|
// Write the output ray data
|
|
_RaytracingDirectionBuffer[COORD_TEXTURE2D_X(currentCoord)] = float4(reflect(-viewWS, normalData.normalWS), 1.0);
|
|
}
|