1
1
#ifndef __DEPTH_OF_FIELD__
2
2
#define __DEPTH_OF_FIELD__
3
3
4
- #include "UnityCG.cginc"
4
+ #if SHADER_TARGET >= 50
5
+ // Use separate texture/sampler objects on Shader Model 5.0
6
+ #define SEPARATE_TEXTURE_SAMPLER
7
+ #define DOF_DECL_TEX2D (tex) Texture2D tex; SamplerState sampler ##tex
8
+ #define DOF_TEX2D (tex, coord) tex.Sample (sampler ##tex, coord)
9
+ #else
10
+ #define DOF_DECL_TEX2D (tex) sampler2D tex
11
+ #define DOF_TEX2D (tex, coord) tex2D (tex, coord)
12
+ #endif
13
+
5
14
#include "Common.cginc"
6
15
#include "DiskKernels.cginc"
7
16
8
- #define PREFILTER_LUMA_WEIGHT 1
9
-
10
- sampler2D_float _CameraDepthTexture;
11
- sampler2D_float _HistoryCoC;
12
- float _HistoryWeight;
17
+ DOF_DECL_TEX2D (_CameraDepthTexture);
18
+ DOF_DECL_TEX2D (_CameraMotionVectorsTexture);
19
+ DOF_DECL_TEX2D (_CoCTex);
13
20
14
21
// Camera parameters
15
22
float _Distance;
16
23
float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
17
24
float _MaxCoC;
18
25
float _RcpMaxCoC;
19
26
float _RcpAspect;
27
+ half3 _TaaParams; // Jitter.x, Jitter.y, Blending
20
28
21
29
struct VaryingsDOF
22
30
{
@@ -47,75 +55,114 @@ VaryingsDOF VertDOF(AttributesDefault v)
47
55
return o;
48
56
}
49
57
50
- // Prefilter: CoC calculation, downsampling and premultiplying.
51
-
52
- #if defined (PREFILTER_TAA)
58
+ // CoC calculation
59
+ half4 FragCoC (VaryingsDOF i) : SV_Target
60
+ {
61
+ float depth = LinearEyeDepth (DOF_TEX2D (_CameraDepthTexture, i.uv));
62
+ half coc = (depth - _Distance) * _LensCoeff / max (depth, 1e-5 );
63
+ return saturate (coc * 0.5 * _RcpMaxCoC + 0.5 );
64
+ }
53
65
54
- // TAA enabled: use MRT to update the history buffer in the same pass.
55
- struct PrefilterOutput
66
+ // Temporal filter
67
+ half4 FragTempFilter (VaryingsDOF i) : SV_Target
56
68
{
57
- half4 base : SV_Target0 ;
58
- half4 history : SV_Target1 ;
59
- };
60
- #define PrefilterSemantics
69
+ float3 uvOffs = _MainTex_TexelSize.xyy * float3 (1 , 1 , 0 );
70
+
71
+ #if defined (SEPARATE_TEXTURE_SAMPLER)
72
+
73
+ half4 cocTL = _CoCTex.GatherRed (sampler_CoCTex, i.uv - uvOffs.xy * 0.5 ); // top-left
74
+ half4 cocBR = _CoCTex.GatherRed (sampler_CoCTex, i.uv + uvOffs.xy * 0.5 ); // bottom-right
75
+ half coc1 = cocTL.x; // top
76
+ half coc2 = cocTL.z; // left
77
+ half coc3 = cocBR.x; // bottom
78
+ half coc4 = cocBR.z; // right
61
79
62
80
#else
63
81
64
- // No TAA
65
- #define PrefilterOutput half4
66
- #define PrefilterSemantics :SV_Target
82
+ half coc1 = DOF_TEX2D (_CoCTex, i.uv - uvOffs.xz).r; // top
83
+ half coc2 = DOF_TEX2D (_CoCTex, i.uv - uvOffs.zy).r; // left
84
+ half coc3 = DOF_TEX2D (_CoCTex, i.uv + uvOffs.zy).r; // bottom
85
+ half coc4 = DOF_TEX2D (_CoCTex, i.uv + uvOffs.xz).r; // right
67
86
68
87
#endif
69
88
70
- PrefilterOutput FragPrefilter (VaryingsDOF i) PrefilterSemantics
89
+ // Dejittered center sample.
90
+ half coc0 = DOF_TEX2D (_CoCTex, i.uv - _TaaParams.xy).r;
91
+
92
+ // CoC dilation: determine the closest point in the four neighbors.
93
+ float3 closest = float3 (0 , 0 , coc0);
94
+ closest = coc1 < closest.z ? float3 (-uvOffs.xz, coc1) : closest;
95
+ closest = coc2 < closest.z ? float3 (-uvOffs.zy, coc2) : closest;
96
+ closest = coc3 < closest.z ? float3 (+uvOffs.zy, coc3) : closest;
97
+ closest = coc4 < closest.z ? float3 (+uvOffs.xz, coc4) : closest;
98
+
99
+ // Sample the history buffer with the motion vector at the closest point.
100
+ float2 motion = DOF_TEX2D (_CameraMotionVectorsTexture, i.uv + closest.xy).xy;
101
+ half cocHis = DOF_TEX2D (_MainTex, i.uv - motion).r;
102
+
103
+ // Neighborhood clamping.
104
+ half cocMin = closest.z;
105
+ half cocMax = max (max (max (max (coc0, coc1), coc2), coc3), coc4);
106
+ cocHis = clamp (cocHis, cocMin, cocMax);
107
+
108
+ // Blend with the history.
109
+ return lerp (coc0, cocHis, _TaaParams.z);
110
+ }
111
+
112
+ // Prefilter: downsampling and premultiplying.
113
+ half4 FragPrefilter (VaryingsDOF i) : SV_Target
71
114
{
115
+ #if defined (SEPARATE_TEXTURE_SAMPLER)
116
+
117
+ // Sample source colors.
118
+ half4 c_r = _MainTex.GatherRed (sampler_MainTex, i.uv);
119
+ half4 c_g = _MainTex.GatherGreen (sampler_MainTex, i.uv);
120
+ half4 c_b = _MainTex.GatherBlue (sampler_MainTex, i.uv);
121
+
122
+ half3 c0 = half3 (c_r.x, c_g.x, c_b.x);
123
+ half3 c1 = half3 (c_r.y, c_g.y, c_b.y);
124
+ half3 c2 = half3 (c_r.z, c_g.z, c_b.z);
125
+ half3 c3 = half3 (c_r.w, c_g.w, c_b.w);
126
+
127
+ // Sample CoCs.
128
+ half4 cocs = _CoCTex.Gather (sampler_CoCTex, i.uvAlt) * 2.0 - 1.0 ;
129
+ half coc0 = cocs.x;
130
+ half coc1 = cocs.y;
131
+ half coc2 = cocs.z;
132
+ half coc3 = cocs.w;
133
+
134
+ #else
135
+
72
136
float3 duv = _MainTex_TexelSize.xyx * float3 (0.5 , 0.5 , -0.5 );
73
137
74
138
// Sample source colors.
75
- half3 c0 = tex2D (_MainTex, i.uv - duv.xy).rgb;
76
- half3 c1 = tex2D (_MainTex, i.uv - duv.zy).rgb;
77
- half3 c2 = tex2D (_MainTex, i.uv + duv.zy).rgb;
78
- half3 c3 = tex2D (_MainTex, i.uv + duv.xy).rgb;
79
-
80
- // Sample linear depths.
81
- float d0 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt - duv.xy));
82
- float d1 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt - duv.zy));
83
- float d2 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt + duv.zy));
84
- float d3 = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uvAlt + duv.xy));
85
- float4 depths = float4 (d0, d1, d2, d3);
86
-
87
- // Calculate the radiuses of CoCs at these sample points.
88
- float4 cocs = (depths - _Distance) * _LensCoeff / depths;
89
- cocs = clamp (cocs, -_MaxCoC, _MaxCoC);
90
-
91
- #if defined (PREFILTER_TAA)
92
- // Get the average with the history to avoid temporal aliasing.
93
- half hcoc = tex2D (_HistoryCoC, i.uv).r;
94
- cocs = lerp (cocs, hcoc, _HistoryWeight);
95
- #endif
139
+ half3 c0 = DOF_TEX2D (_MainTex, i.uv - duv.xy).rgb;
140
+ half3 c1 = DOF_TEX2D (_MainTex, i.uv - duv.zy).rgb;
141
+ half3 c2 = DOF_TEX2D (_MainTex, i.uv + duv.zy).rgb;
142
+ half3 c3 = DOF_TEX2D (_MainTex, i.uv + duv.xy).rgb;
143
+
144
+ // Sample CoCs.
145
+ half coc0 = DOF_TEX2D (_CoCTex, i.uvAlt - duv.xy).r * 2.0 - 1.0 ;
146
+ half coc1 = DOF_TEX2D (_CoCTex, i.uvAlt - duv.zy).r * 2.0 - 1.0 ;
147
+ half coc2 = DOF_TEX2D (_CoCTex, i.uvAlt + duv.zy).r * 2.0 - 1.0 ;
148
+ half coc3 = DOF_TEX2D (_CoCTex, i.uvAlt + duv.xy).r * 2.0 - 1.0 ;
96
149
97
- // Premultiply CoC to reduce background bleeding.
98
- float4 weights = saturate (abs (cocs) * _RcpMaxCoC);
99
-
100
- #if defined (PREFILTER_LUMA_WEIGHT)
101
- // Apply luma weights to reduce flickering.
102
- // References:
103
- // http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
104
- // http://graphicrants.blogspot.fr/2013/12/tone-mapping.html
105
- weights.x *= 1.0 / (Max3 (c0) + 1.0 );
106
- weights.y *= 1.0 / (Max3 (c1) + 1.0 );
107
- weights.z *= 1.0 / (Max3 (c2) + 1.0 );
108
- weights.w *= 1.0 / (Max3 (c3) + 1.0 );
109
150
#endif
110
151
152
+ // Apply CoC and luma weights to reduce bleeding and flickering.
153
+ float w0 = abs (coc0) / (Max3 (c0) + 1.0 );
154
+ float w1 = abs (coc1) / (Max3 (c1) + 1.0 );
155
+ float w2 = abs (coc2) / (Max3 (c2) + 1.0 );
156
+ float w3 = abs (coc3) / (Max3 (c3) + 1.0 );
157
+
111
158
// Weighted average of the color samples
112
- half3 avg = c0 * weights.x + c1 * weights.y + c2 * weights.z + c3 * weights.w ;
113
- avg /= dot (weights, 1.0 );
159
+ half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3 ;
160
+ avg /= max (w0 + w1 + w2 + w3, 1e- 5 );
114
161
115
- // Output CoC = average of CoCs
116
- half cocmin = Min4 (cocs );
117
- half cocmax = Max4 (cocs );
118
- half coc = -cocmin > cocmax ? cocmin : cocmax ;
162
+ // Select the largest CoC value.
163
+ half coc_min = Min4 (coc0, coc1, coc2, coc3 );
164
+ half coc_max = Max4 (coc0, coc1, coc2, coc3 );
165
+ half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC ;
119
166
120
167
// Premultiply CoC again.
121
168
avg *= smoothstep (0 , _MainTex_TexelSize.y * 2 , abs (coc));
@@ -124,20 +171,13 @@ PrefilterOutput FragPrefilter(VaryingsDOF i) PrefilterSemantics
124
171
avg = GammaToLinearSpace (avg);
125
172
#endif
126
173
127
- #if defined (PREFILTER_TAA)
128
- PrefilterOutput output;
129
- output.base = half4 (avg, coc);
130
- output.history = coc.xxxx;
131
- return output;
132
- #else
133
174
return half4 (avg, coc);
134
- #endif
135
175
}
136
176
137
177
// Bokeh filter with disk-shaped kernels
138
178
half4 FragBlur (VaryingsDOF i) : SV_Target
139
179
{
140
- half4 samp0 = tex2D (_MainTex, i.uv);
180
+ half4 samp0 = DOF_TEX2D (_MainTex, i.uv);
141
181
142
182
half4 bgAcc = 0.0 ; // Background: far field bokeh
143
183
half4 fgAcc = 0.0 ; // Foreground: near field bokeh
@@ -148,7 +188,7 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
148
188
float dist = length (disp);
149
189
150
190
float2 duv = float2 (disp.x * _RcpAspect, disp.y);
151
- half4 samp = tex2D (_MainTex, i.uv + duv);
191
+ half4 samp = DOF_TEX2D (_MainTex, i.uv + duv);
152
192
153
193
// BG: Compare CoC of the current sample and the center sample
154
194
// and select smaller one.
@@ -181,50 +221,23 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
181
221
fgAcc.a *= UNITY_PI / kSampleCount;
182
222
183
223
// Alpha premultiplying
184
- half3 rgb = 0.0 ;
185
- rgb = lerp (rgb, bgAcc.rgb, saturate (bgAcc.a));
186
- rgb = lerp (rgb, fgAcc.rgb, saturate (fgAcc.a));
187
-
188
- // Combined alpha value
189
- half alpha = (1.0 - saturate (bgAcc.a)) * (1.0 - saturate (fgAcc.a));
224
+ half alpha = saturate (fgAcc.a);
225
+ half3 rgb = lerp (bgAcc.rgb, fgAcc.rgb, alpha);
190
226
191
227
return half4 (rgb, alpha);
192
228
}
193
229
194
230
// Postfilter blur
195
231
half4 FragPostBlur (VaryingsDOF i) : SV_Target
196
232
{
197
- // 9-tap tent filter
198
- float4 duv = _MainTex_TexelSize.xyxy * float4 (1 , 1 , -1 , 0 );
199
-
200
- half4 c0 = tex2D (_MainTex, i.uv - duv.xy);
201
- half4 c1 = tex2D (_MainTex, i.uv - duv.wy);
202
- half4 c2 = tex2D (_MainTex, i.uv - duv.zy);
203
-
204
- half4 c3 = tex2D (_MainTex, i.uv + duv.zw);
205
- half4 c4 = tex2D (_MainTex, i.uv );
206
- half4 c5 = tex2D (_MainTex, i.uv + duv.xw);
207
-
208
- half4 c6 = tex2D (_MainTex, i.uv + duv.zy);
209
- half4 c7 = tex2D (_MainTex, i.uv + duv.wy);
210
- half4 c8 = tex2D (_MainTex, i.uv + duv.xy);
211
-
212
- half4 acc = c0 * 1 + c1 * 2 + c2 * 1 +
213
- c3 * 2 + c4 * 4 + c5 * 2 +
214
- c6 * 1 + c7 * 2 + c8 * 1 ;
215
-
216
- half aa =
217
- c0.a * c0.a * 1 + c1.a * c1.a * 2 + c2.a * c2.a * 1 +
218
- c3.a * c3.a * 2 + c4.a * c4.a * 4 + c5.a * c5.a * 2 +
219
- c6.a * c6.a * 1 + c7.a * c7.a * 2 + c8.a * c8.a * 1 ;
220
-
221
- half wb = 1.2 ;
222
- half a = (wb * acc.a - aa) / (wb * 16 - acc.a);
223
-
224
- acc /= 16 ;
225
-
226
- half3 rgb = acc.rgb * (1 + saturate (acc.a - a));
227
- return half4 (rgb, a);
233
+ // 9 tap tent filter with 4 bilinear samples
234
+ const float4 duv = _MainTex_TexelSize.xyxy * float4 (0.5 , 0.5 , -0.5 , 0 );
235
+ half4 acc;
236
+ acc = DOF_TEX2D (_MainTex, i.uv - duv.xy);
237
+ acc += DOF_TEX2D (_MainTex, i.uv - duv.zy);
238
+ acc += DOF_TEX2D (_MainTex, i.uv + duv.zy);
239
+ acc += DOF_TEX2D (_MainTex, i.uv + duv.xy);
240
+ return acc / 4.0 ;
228
241
}
229
242
230
243
#endif // __DEPTH_OF_FIELD__
0 commit comments