Skip to content
This repository was archived by the owner on Nov 30, 2020. It is now read-only.

Commit 42319c1

Browse files
authored
Merge pull request #138 from keijiro/dof-taa-improvements
New temporal filter for DoF
2 parents db2c14f + e8c9732 commit 42319c1

File tree

7 files changed

+337
-167
lines changed

7 files changed

+337
-167
lines changed

PostProcessing/Resources/Shaders/Common.cginc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
// -----------------------------------------------------------------------------
1717
// Uniforms
1818

19+
#if defined(SEPARATE_TEXTURE_SAMPLER)
20+
Texture2D _MainTex;
21+
SamplerState sampler_MainTex;
22+
#else
1923
sampler2D _MainTex;
24+
#endif
2025
float4 _MainTex_TexelSize;
2126
float4 _MainTex_ST;
2227

Lines changed: 117 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
#ifndef __DEPTH_OF_FIELD__
22
#define __DEPTH_OF_FIELD__
33

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+
514
#include "Common.cginc"
615
#include "DiskKernels.cginc"
716

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);
1320

1421
// Camera parameters
1522
float _Distance;
1623
float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
1724
float _MaxCoC;
1825
float _RcpMaxCoC;
1926
float _RcpAspect;
27+
half3 _TaaParams; // Jitter.x, Jitter.y, Blending
2028

2129
struct VaryingsDOF
2230
{
@@ -47,75 +55,114 @@ VaryingsDOF VertDOF(AttributesDefault v)
4755
return o;
4856
}
4957

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+
}
5365

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
5668
{
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
6179

6280
#else
6381

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
6786

6887
#endif
6988

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
71114
{
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+
72136
float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
73137

74138
// 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;
96149

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);
109150
#endif
110151

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+
111158
// 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);
114161

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;
119166

120167
// Premultiply CoC again.
121168
avg *= smoothstep(0, _MainTex_TexelSize.y * 2, abs(coc));
@@ -124,20 +171,13 @@ PrefilterOutput FragPrefilter(VaryingsDOF i) PrefilterSemantics
124171
avg = GammaToLinearSpace(avg);
125172
#endif
126173

127-
#if defined(PREFILTER_TAA)
128-
PrefilterOutput output;
129-
output.base = half4(avg, coc);
130-
output.history = coc.xxxx;
131-
return output;
132-
#else
133174
return half4(avg, coc);
134-
#endif
135175
}
136176

137177
// Bokeh filter with disk-shaped kernels
138178
half4 FragBlur(VaryingsDOF i) : SV_Target
139179
{
140-
half4 samp0 = tex2D(_MainTex, i.uv);
180+
half4 samp0 = DOF_TEX2D(_MainTex, i.uv);
141181

142182
half4 bgAcc = 0.0; // Background: far field bokeh
143183
half4 fgAcc = 0.0; // Foreground: near field bokeh
@@ -148,7 +188,7 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
148188
float dist = length(disp);
149189

150190
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);
152192

153193
// BG: Compare CoC of the current sample and the center sample
154194
// and select smaller one.
@@ -181,50 +221,23 @@ half4 FragBlur(VaryingsDOF i) : SV_Target
181221
fgAcc.a *= UNITY_PI / kSampleCount;
182222

183223
// 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);
190226

191227
return half4(rgb, alpha);
192228
}
193229

194230
// Postfilter blur
195231
half4 FragPostBlur(VaryingsDOF i) : SV_Target
196232
{
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;
228241
}
229242

230243
#endif // __DEPTH_OF_FIELD__

0 commit comments

Comments
 (0)