Singularity/Library/PackageCache/com.unity.render-pipelines..../ShaderLibrary/NormalReconstruction.hlsl
2024-05-06 11:45:45 -07:00

171 lines
6.9 KiB
HLSL

#ifndef UNIVERSAL_NORMAL_RECONSTRUCTION
#define UNIVERSAL_NORMAL_RECONSTRUCTION
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#if defined(USING_STEREO_MATRICES)
#define unity_eyeIndex unity_StereoEyeIndex
#else
#define unity_eyeIndex 0
#endif
float4x4 _NormalReconstructionMatrix[2];
float GetRawDepth(float2 uv)
{
return SampleSceneDepth(uv.xy).r;
}
// inspired by keijiro's depth inverse projection
// https://github.com/keijiro/DepthInverseProjection
// constructs view space ray at the far clip plane from the screen uv
// then multiplies that ray by the linear 01 depth
float3 ViewSpacePosAtScreenUV(float2 uv)
{
float3 viewSpaceRay = mul(_NormalReconstructionMatrix[unity_eyeIndex], float4(uv * 2.0 - 1.0, 1.0, 1.0) * _ProjectionParams.z).xyz;
float rawDepth = GetRawDepth(uv);
return viewSpaceRay * Linear01Depth(rawDepth, _ZBufferParams);
}
float3 ViewSpacePosAtPixelPosition(float2 positionSS)
{
float2 uv = positionSS * _ScreenSize.zw;
return ViewSpacePosAtScreenUV(uv);
}
half3 ReconstructNormalDerivative(float2 positionSS)
{
float3 viewSpacePos = ViewSpacePosAtPixelPosition(positionSS);
float3 hDeriv = ddy(viewSpacePos);
float3 vDeriv = ddx(viewSpacePos);
return half3(normalize(cross(hDeriv, vDeriv)));
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 33 math, 3 tex
half3 ReconstructNormalTap3(float2 positionSS)
{
// get current pixel's view space position
float3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 hDeriv = viewSpacePos_r - viewSpacePos_c;
float3 vDeriv = viewSpacePos_u - viewSpacePos_c;
// get view space normal from the cross product of the diffs
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 50 math, 4 tex
half3 ReconstructNormalTap4(float2 positionSS)
{
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 hDeriv = viewSpacePos_r - viewSpacePos_l;
float3 vDeriv = viewSpacePos_u - viewSpacePos_d;
// get view space normal from the cross product of the diffs
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 54 math, 5 tex
half3 ReconstructNormalTap5(float2 positionSS)
{
// get current pixel's view space position
half3 viewSpacePos_c = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 0.0));
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtPixelPosition(positionSS + float2(-1.0, 0.0));
float3 viewSpacePos_r = ViewSpacePosAtPixelPosition(positionSS + float2(1.0, 0.0));
float3 viewSpacePos_d = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, -1.0));
float3 viewSpacePos_u = ViewSpacePosAtPixelPosition(positionSS + float2(0.0, 1.0));
// get the difference between the current and each offset position
float3 l = viewSpacePos_c - viewSpacePos_l;
float3 r = viewSpacePos_r - viewSpacePos_c;
float3 d = viewSpacePos_c - viewSpacePos_d;
float3 u = viewSpacePos_u - viewSpacePos_c;
// pick horizontal and vertical diff with the smallest z difference
float3 hDeriv = abs(l.z) < abs(r.z) ? l : r;
float3 vDeriv = abs(d.z) < abs(u.z) ? d : u;
// get view space normal from the cross product of the two smallest offsets
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
// Taken from https://gist.github.com/bgolus/a07ed65602c009d5e2f753826e8078a0
// unity's compiled fragment shader stats: 66 math, 9 tex
half3 ReconstructNormalTap9(float2 positionSS)
{
// screen uv from positionSS
float2 uv = positionSS * _ScreenSize.zw;
// current pixel's depth
float c = GetRawDepth(uv);
// get current pixel's view space position
float3 viewSpacePos_c = ViewSpacePosAtScreenUV(uv);
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = ViewSpacePosAtScreenUV(uv + float2(-1.0, 0.0) * _ScreenSize.zw);
float3 viewSpacePos_r = ViewSpacePosAtScreenUV(uv + float2(1.0, 0.0) * _ScreenSize.zw);
float3 viewSpacePos_d = ViewSpacePosAtScreenUV(uv + float2(0.0, -1.0) * _ScreenSize.zw);
float3 viewSpacePos_u = ViewSpacePosAtScreenUV(uv + float2(0.0, 1.0) * _ScreenSize.zw);
// get the difference between the current and each offset position
float3 l = viewSpacePos_c - viewSpacePos_l;
float3 r = viewSpacePos_r - viewSpacePos_c;
float3 d = viewSpacePos_c - viewSpacePos_d;
float3 u = viewSpacePos_u - viewSpacePos_c;
// get depth values at 1 & 2 pixels offsets from current along the horizontal axis
half4 H = half4(
GetRawDepth(uv + float2(-1.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(1.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(-2.0, 0.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(2.0, 0.0) * _ScreenSize.zw.xy)
);
// get depth values at 1 & 2 pixels offsets from current along the vertical axis
half4 V = half4(
GetRawDepth(uv + float2(0.0, -1.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, 1.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, -2.0) * _ScreenSize.zw.xy),
GetRawDepth(uv + float2(0.0, 2.0) * _ScreenSize.zw.xy)
);
// current pixel's depth difference from slope of offset depth samples
// differs from original article because we're using non-linear depth values
// see article's comments
half2 he = abs((2 * H.xy - H.zw) - c);
half2 ve = abs((2 * V.xy - V.zw) - c);
// pick horizontal and vertical diff with the smallest depth difference from slopes
float3 hDeriv = he.x < he.y ? l : r;
float3 vDeriv = ve.x < ve.y ? d : u;
// get view space normal from the cross product of the best derivatives
half3 viewNormal = half3(normalize(cross(vDeriv, hDeriv)));
return viewNormal;
}
#endif // UNIVERSAL_NORMAL_RECONSTRUCTION