-
Notifications
You must be signed in to change notification settings - Fork 869
Expand file tree
/
Copy pathNormalReconstruction.hlsl
More file actions
190 lines (154 loc) · 7.65 KB
/
NormalReconstruction.hlsl
File metadata and controls
190 lines (154 loc) · 7.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#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, float deviceDepth)
{
float3 viewSpaceRay = mul(_NormalReconstructionMatrix[unity_eyeIndex], float4(uv * 2.0 - 1.0, 1.0, 1.0) * _ProjectionParams.z).xyz;
return viewSpaceRay * Linear01Depth(deviceDepth, _ZBufferParams);
}
float3 ViewSpacePosAtPixelPosition(float2 positionSS, float deviceDepth)
{
float2 uv = positionSS * _ScreenSize.zw;
return ViewSpacePosAtScreenUV(uv, deviceDepth);
}
half3 ReconstructNormalDerivative(float2 positionSS, float deviceDepth)
{
float3 viewSpacePos = ViewSpacePosAtPixelPosition(positionSS, deviceDepth);
float3 hDeriv = ddy(viewSpacePos);
float3 vDeriv = ddx(viewSpacePos);
return half3(SafeNormalize(cross(hDeriv, vDeriv)));
}
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(SafeNormalize(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