171 lines
6.9 KiB
HLSL
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, sampler_PointClamp).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
|