1  /*
2     CAMERA MOTION BLUR IMAGE EFFECTS
3
4     Reconstruction Filter:
5     Based
on "Plausible Motion Blur"
6     http://graphics.cs.williams.edu/papers/MotionBlurI3D12/
7
8     CameraMotion:
9     Based
on Alex Vlacho's technique in
10     http://www.valvesoftware.com/publications/
2008/GDC2008_PostProcessingInTheOrangeBox.pdf
11
12     SimpleBlur:
13     Straightforward sampling along velocities
14
15     ScatterFromGather:
16     Combines Reconstruction with depth of field type defocus
17  */

18  
19  Shader
"Hidden/CameraMotionBlur" {
20     Properties {
21         _MainTex (
"-", 2D) = "" {}
22         _NoiseTex (
"-", 2D) = "grey" {}
23         _VelTex (
"-", 2D) = "black" {}
24         _NeighbourMaxTex (
"-", 2D) = "black" {}
25     }
26
27     CGINCLUDE
28     
29     #include
"UnityCG.cginc"
30     
31     
// 's' in paper (# of samples for reconstruction)
32     #define NUM_SAMPLES (
11)
33     
// # samples for valve style blur
34     #define MOTION_SAMPLES (
16)
35     
// 'k' in paper
36     
float _MaxRadiusOrKInPaper;
37
38     
static const int SmallDiscKernelSamples = 12;
39     
static const float2 SmallDiscKernel[SmallDiscKernelSamples] =
40     {
41         float2(-
0.326212,-0.40581),
42         float2(-
0.840144,-0.07358),
43         float2(-
0.695914,0.457137),
44         float2(-
0.203345,0.620716),
45         float2(
0.96234,-0.194983),
46         float2(
0.473434,-0.480026),
47         float2(
0.519456,0.767022),
48         float2(
0.185461,-0.893124),
49         float2(
0.507431,0.064425),
50         float2(
0.89642,0.412458),
51         float2(-
0.32194,-0.932615),
52         float2(-
0.791559,-0.59771)
53     };
54
55     
struct v2f
56     {
57         float4 pos : SV_POSITION;
58         float2 uv : TEXCOORD0;
59     };
60                 
61     sampler2D _MainTex;
62     sampler2D_float _CameraDepthTexture;
63     sampler2D _VelTex;
64     sampler2D _NeighbourMaxTex;
65     sampler2D _NoiseTex;
66     sampler2D _TileTexDebug;
67     
68     float4 _MainTex_TexelSize;
69     float4 _CameraDepthTexture_TexelSize;
70     float4 _VelTex_TexelSize;
71     
72     float4x4 _InvViewProj;
// inverse view-projection matrix
73     float4x4 _PrevViewProj;
// previous view-projection matrix
74     float4x4 _ToPrevViewProjCombined;
// combined
75
76     
float _Jitter;
77     
78     
float _VelocityScale;
79     
float _DisplayVelocityScale;
80
81     
float _MaxVelocity;
82     
float _MinVelocity;
83     
84     float4 _BlurDirectionPacked;
85     
86     
float _SoftZDistance;
87     
88     v2f vert(appdata_img v)
89     {
90         v2f o;
91         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
92         o.uv = v.texcoord.xy;
93         
return o;
94     }
95     
96     float4 CameraVelocity(v2f i) : SV_Target
97     {
98         float2 depth_uv = i.uv;
99
100         #
if UNITY_UV_STARTS_AT_TOP
101         
if (_MainTex_TexelSize.y < 0)
102             depth_uv.y =
1 - depth_uv.y;
103         #endif
104
105         
// read depth
106         
float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, depth_uv);
107         
108         
// calculate position from pixel from depth
109         float3 clipPos = float3(i.uv.x*
2.0-1.0, (i.uv.y)*2.0-1.0, d);
110
111         
// only 1 matrix mul:
112         float4 prevClipPos = mul(_ToPrevViewProjCombined, float4(clipPos,
1.0));
113         prevClipPos.xyz /= prevClipPos.w;
114
115         
/*
116         float4 ws = mul(_InvViewProj, float4(clipPos,
1.0));
117         ws /= ws.w;
118         prevClipPos = mul(_PrevViewProj,ws);
119         prevClipPos.xyz /= prevClipPos.w;
120         */

121
122         
/*
123         float2 vel = _VelocityScale *(clipPos.xy - prevClipPos.xy) /
2.f;
124         // clamp to maximum velocity (
in pixels)
125         
float maxVel = length(_MainTex_TexelSize.xy*_MaxVelocity);
126         
if (length(vel) > maxVel) {
127             vel = normalize(vel) * maxVel;
128         }
129         
return float4(vel, 0.0, 0.0);
130         */

131
132         float2 vel = _MainTex_TexelSize.zw * _VelocityScale * (clipPos.xy - prevClipPos.xy) /
2.f;
133         
float vellen = length(vel);
134         
float maxVel = _MaxVelocity;
135         float2 velOut = vel * max(
0.5, min(vellen, maxVel)) / (vellen + 1e-2f);
136         velOut *= _MainTex_TexelSize.xy;
137         
return float4(velOut, 0.0, 0.0);
138         
139     }
140
141     
// vector with largest magnitude
142     float2 vmax(float2 a, float2 b)
143     {
144         
float ma = dot(a, a);
145         
float mb = dot(b, b);
146         
return (ma > mb) ? a : b;
147     }
148
149     
// find dominant velocity for each tile
150     float4 TileMax(v2f i) : SV_Target
151     {
152         float2 uvCorner = i.uv - _MainTex_TexelSize.xy * (_MaxRadiusOrKInPaper *
0.5);
153         float2 maxvel = float2(
0,0);
154         float4 baseUv = float4(uvCorner,
0,0);
155         float4 uvScale = float4(_MainTex_TexelSize.xy,
0, 0);
156
157         
for(int l=0; l<(int)_MaxRadiusOrKInPaper; l++)
158         {
159             
for(int k=0; k<(int)_MaxRadiusOrKInPaper; k++)
160             {
161                 maxvel = vmax(maxvel, tex2Dlod(_MainTex, baseUv + float4(l,k,
0,0) * uvScale).xy);
162             }
163         }
164         
return float4(maxvel, 0, 1);
165     }
166
167     
// find maximum velocity in any adjacent tile
168     float4 NeighbourMax(v2f i) : SV_Target
169     {
170         float2 x_ = i.uv;
171
172         
// to fetch all neighbours, we need 3x3 point filtered samples
173
174         float2 nx = tex2D(_MainTex, x_+float2(
1.0, 1.0)*_MainTex_TexelSize.xy).xy;
175         nx = vmax(nx, tex2D(_MainTex, x_+float2(
1.0, 0.0)*_MainTex_TexelSize.xy).xy);
176         nx = vmax(nx, tex2D(_MainTex, x_+float2(
1.0,-1.0)*_MainTex_TexelSize.xy).xy);
177         nx = vmax(nx, tex2D(_MainTex, x_+float2(
0.0, 1.0)*_MainTex_TexelSize.xy).xy);
178         nx = vmax(nx, tex2D(_MainTex, x_+float2(
0.0, 0.0)*_MainTex_TexelSize.xy).xy);
179         nx = vmax(nx, tex2D(_MainTex, x_+float2(
0.0,-1.0)*_MainTex_TexelSize.xy).xy);
180         nx = vmax(nx, tex2D(_MainTex, x_+float2(-
1.0, 1.0)*_MainTex_TexelSize.xy).xy);
181         nx = vmax(nx, tex2D(_MainTex, x_+float2(-
1.0, 0.0)*_MainTex_TexelSize.xy).xy);
182         nx = vmax(nx, tex2D(_MainTex, x_+float2(-
1.0,-1.0)*_MainTex_TexelSize.xy).xy);
183
184         
return float4(nx, 0, 0);
185     }
186             
187     float4 Debug(v2f i) : SV_Target
188     {
189         
return saturate( float4(tex2D(_MainTex, i.uv).x,abs(tex2D(_MainTex, i.uv).y),-tex2D(_MainTex, i.uv).xy) * _DisplayVelocityScale);
190     }
191
192     
// classification filters
193     
float cone(float2 px, float2 py, float2 v)
194     {
195         
return clamp(1.0 - (length(px - py) / length(v)), 0.0, 1.0);
196     }
197
198     
float cylinder(float2 x, float2 y, float2 v)
199     {
200         
float lv = length(v);
201         
return 1.0 - smoothstep(0.95*lv, 1.05*lv, length(x - y));
202     }
203
204     
// is zb closer than za?
205     
float softDepthCompare(float za, float zb)
206     {
207         
return clamp(1.0 - (za - zb) / _SoftZDistance, 0.0, 1.0);
208     }
209
210     float4 SimpleBlur (v2f i) : SV_Target
211     {
212         float2 x = i.uv;
213         float2 xf = x;
214
215         #
if UNITY_UV_STARTS_AT_TOP
216         
if (_MainTex_TexelSize.y < 0)
217             xf.y =
1 - xf.y;
218         #endif
219
220         float2 vx = tex2D(_VelTex, xf).xy;
// vel at x
221
222         float4 sum = float4(
0, 0, 0, 0);
223         
for(int l=0; l<NUM_SAMPLES; l++) {
224             
float t = l / (float) (NUM_SAMPLES - 1);
225             t = t-
0.5;
226             float2 y = x - vx*t;
227             float4 cy = tex2D(_MainTex, y);
228             sum += cy;
229         }
230         sum /= NUM_SAMPLES;
231         
return sum;
232     }
233
234     float4 ReconstructFilterBlur(v2f i) : SV_Target
235     {
236         
// uv's
237
238         float2 x = i.uv;
239         float2 xf = x;
240
241         #
if UNITY_UV_STARTS_AT_TOP
242         
if (_MainTex_TexelSize.y < 0)
243             xf.y =
1-xf.y;
244         #endif
245
246         float2 x2 = xf;
247         
248         float2 vn = tex2Dlod(_NeighbourMaxTex, float4(x2,
0,0)).xy; // largest velocity in neighbourhood
249         float4 cx = tex2Dlod(_MainTex, float4(x,
0,0)); // color at x
250         float2 vx = tex2Dlod(_VelTex, float4(xf,
0,0)).xy; // vel at x
251
252         
float zx = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(x,0,0));
253         zx = -Linear01Depth(zx);
254
255         
// random offset [-0.5, 0.5]
256         
float j = (tex2Dlod(_NoiseTex, float4(i.uv,0,0) * 11.0f).r*2-1) * _Jitter;
257
258         
// sample current pixel
259         
float weight = 0.75; // <= good start weight choice??
260         float4 sum = cx * weight;
261  
262         
int centerSample = (int)(NUM_SAMPLES-1)/2;
263  
264         
for(int l=0; l<NUM_SAMPLES; l++)
265         {
266             
float contrib = 1.0f;
267         #
if SHADER_API_D3D11
268             
if (l==centerSample) continue; // skip center sample
269         #
else
270             
if (l==centerSample) contrib = 0.0f; // skip center sample
271         #endif
272
273             
float t = lerp(-1.0, 1.0, (l + j) / (-1 + _Jitter + (float)NUM_SAMPLES));
274             
//float t = lerp(-1.0, 1.0, l / (float)(NUM_SAMPLES - 1));
275
276             float2 y = x + vn * t;
277
278             float2 yf = y;
279             #
if UNITY_UV_STARTS_AT_TOP
280             
if (_MainTex_TexelSize.y < 0)
281                 yf.y =
1-yf.y;
282             #endif
283
284             
// velocity at y
285             float2 vy = tex2Dlod(_VelTex, float4(yf,
0,0)).xy;
286
287             
float zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y,0,0));
288             zy = -Linear01Depth(zy);
289             
float f = softDepthCompare(zx, zy);
290             
float b = softDepthCompare(zy, zx);
291             
float alphay = b * cone(x, y, vx) + f * cone(y, x, vy) + cylinder(y, x, vy) * cylinder(x, y, vx) * 2.0;
292
293             float4 cy = tex2Dlod(_MainTex, float4(y,
0,0));
294             sum += cy * alphay * contrib;
295             weight += alphay * contrib;
296         }
297         sum /= weight;
298         
return sum;
299     }
300
301     float4 ReconstructionDiscBlur (v2f i) : SV_Target
302     {
303         float2 xf = i.uv;
304         float2 x = i.uv;
305
306         #
if UNITY_UV_STARTS_AT_TOP
307         
if (_MainTex_TexelSize.y < 0)
308             xf.y =
1 - xf.y;
309         #endif
310
311         float2 x2 = xf;
312
313         float2 vn = tex2Dlod(_NeighbourMaxTex, float4(x2,
0,0)).xy; // largest velocity in neighbourhood
314         float4 cx = tex2Dlod(_MainTex, float4(x,
0,0)); // color at x
315         float2 vx = tex2Dlod(_VelTex, float4(xf,
0,0)).xy; // vel at x
316
317         float4 noise = tex2Dlod(_NoiseTex, float4(i.uv,
0,0)*11.0f)*2-1;
318         
float zx = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(x,0,0));
319
320         zx = -Linear01Depth(zx);
321
322         noise *= _MainTex_TexelSize.xyxy * _Jitter;
323
324         
//return abs(blurDir.xyxy)*10 + centerTap;
325
326         
float weight = 1.0; // <- maybe tweak this: bluriness amount ...
327         float4 sum = cx * weight;
328         
329         float4 jitteredDir = vn.xyxy + noise.xyyz;
330 #ifdef SHADER_API_D3D11
331         jitteredDir = max(abs(jitteredDir.xyxy), _MainTex_TexelSize.xyxy * _MaxVelocity *
0.5) * sign(jitteredDir.xyxy) * float4(1,1,-1,-1);
332 #
else
333         jitteredDir = max(abs(jitteredDir.xyxy), _MainTex_TexelSize.xyxy * _MaxVelocity *
0.15) * sign(jitteredDir.xyxy) * float4(1,1,-1,-1);
334 #endif
335
336         
for(int l=0; l<SmallDiscKernelSamples; l++)
337         {
338             float4 y = i.uv.xyxy + jitteredDir.xyxy * SmallDiscKernel[l].xyxy * float4(
1,1,-1,-1);
339
340             float4 yf = y;
341             #
if UNITY_UV_STARTS_AT_TOP
342             
if (_MainTex_TexelSize.y < 0)
343                 yf.yw =
1-yf.yw;
344             #endif
345
346             
// velocity at y
347             float2 vy = tex2Dlod(_VelTex, float4(yf.xy,
0,0)).xy;
348
349             
float zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y.xy,0,0) );
350             zy = -Linear01Depth(zy);
351
352             
float f = softDepthCompare(zx, zy);
353             
float b = softDepthCompare(zy, zx);
354             
float alphay = b * cone(x, y.xy, vx) + f * cone(y.xy, x, vy) + cylinder(y.xy, x, vy) * cylinder(x, y.xy, vx) * 2.0;
355
356             float4 cy = tex2Dlod(_MainTex, float4(y.xy,
0,0));
357             sum += cy * alphay;
358             weight += alphay;
359
360 #ifdef SHADER_API_D3D11
361
362             vy = tex2Dlod(_VelTex, float4(yf.zw,
0,0)).xy;
363
364             zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y.zw,
0,0) );
365             zy = -Linear01Depth(zy);
366
367             f = softDepthCompare(zx, zy);
368             b = softDepthCompare(zy, zx);
369             alphay = b * cone(x, y.zw, vx) + f * cone(y.zw, x, vy) + cylinder(y.zw, x, vy) * cylinder(x, y.zw, vx) *
2.0;
370
371             cy = tex2Dlod(_MainTex, float4(y.zw,
0,0));
372             sum += cy * alphay;
373             weight += alphay;
374             
375 #endif
376         }
377
378         
return sum / weight;
379     }
380
381     float4 MotionVectorBlur (v2f i) : SV_Target
382     {
383         float2 x = i.uv;
384
385         float2 insideVector = (x*
2-1) * float2(1,_MainTex_TexelSize.w/_MainTex_TexelSize.z);
386         float2 rollVector = float2(insideVector.y, -insideVector.x);
387
388         float2 blurDir = _BlurDirectionPacked.x * float2(
0,1);
389         blurDir += _BlurDirectionPacked.y * float2(
1,0);
390         blurDir += _BlurDirectionPacked.z * rollVector;
391         blurDir += _BlurDirectionPacked.w * insideVector;
392         blurDir *= _VelocityScale;
393  
394         
// clamp to maximum velocity (in pixels)
395         
float velMag = length(blurDir);
396         
if (velMag > _MaxVelocity) {
397             blurDir *= (_MaxVelocity / velMag);
398             velMag = _MaxVelocity;
399         }
400
401         float4 centerTap = tex2D(_MainTex, x);
402         float4 sum = centerTap;
403
404         blurDir *= smoothstep(_MinVelocity *
0.25f, _MinVelocity * 2.5, velMag);
405
406         blurDir *= _MainTex_TexelSize.xy;
407         blurDir /= MOTION_SAMPLES;
408
409         
for(int i=0; i<MOTION_SAMPLES; i++) {
410             float4 tap = tex2D(_MainTex, x+i*blurDir);
411             sum += tap;
412         }
413
414         
return sum/(1+MOTION_SAMPLES);
415     }
416                                                                                                                          
417     ENDCG
418     
419 Subshader {
420  
421     
// pass 0
422     Pass {
423         ZTest Always Cull Off ZWrite On Blend Off
424
425         CGPROGRAM
426         #pragma target
3.0
427         #pragma vertex vert
428         #pragma fragment CameraVelocity
429
430         ENDCG
431     }
432
433     
// pass 1
434     Pass {
435         ZTest Always Cull Off ZWrite Off Blend Off
436
437         CGPROGRAM
438         #pragma target
3.0
439         #pragma vertex vert
440         #pragma fragment Debug
441
442         ENDCG
443     }
444
445     
// pass 2
446     Pass {
447         ZTest Always Cull Off ZWrite Off Blend Off
448
449         CGPROGRAM
450         #pragma target
3.0
451         #pragma vertex vert
452         #pragma fragment TileMax
453
454         ENDCG
455     }
456
457     
// pass 3
458     Pass {
459         ZTest Always Cull Off ZWrite Off Blend Off
460
461         CGPROGRAM
462         #pragma target
3.0
463         #pragma vertex vert
464         #pragma fragment NeighbourMax
465
466         ENDCG
467     }
468
469     
// pass 4
470     Pass {
471         ZTest Always Cull Off ZWrite Off Blend Off
472
473         CGPROGRAM
474         #pragma target
3.0
475         #pragma vertex vert
476         #pragma fragment ReconstructFilterBlur
477
478         ENDCG
479     }
480
481     
// pass 5
482     Pass {
483         ZTest Always Cull Off ZWrite Off Blend Off
484
485         CGPROGRAM
486         #pragma target
3.0
487         #pragma vertex vert
488         #pragma fragment SimpleBlur
489         ENDCG
490     }
491
492     
// pass 6
493     Pass {
494         ZTest Always Cull Off ZWrite Off Blend Off
495
496         CGPROGRAM
497         #pragma target
3.0
498         #pragma vertex vert
499         #pragma fragment MotionVectorBlur
500         ENDCG
501     }
502
503     
// pass 7
504     Pass {
505         ZTest Always Cull Off ZWrite Off Blend Off
506
507         CGPROGRAM
508         #pragma target
3.0
509         #pragma vertex vert
510         #pragma fragment ReconstructionDiscBlur
511         ENDCG
512     }
513   }
514
515 Fallback off
516 }


Gõ tìm kiếm nhanh...