1 /*
2 NOTES: see CameraMotionBlur.shader
3 */
4
5 Shader "Hidden/CameraMotionBlurDX11" {
6 Properties {
7 _MainTex ("-", 2D) = "" {}
8 _NoiseTex ("-", 2D) = "grey" {}
9 _VelTex ("-", 2D) = "black" {}
10 _NeighbourMaxTex ("-", 2D) = "black" {}
11 }
12
13 CGINCLUDE
14
15 #include "UnityCG.cginc"
16
17 // 'k' in paper
18 float _MaxRadiusOrKInPaper;
19 // 's' in paper
20 #define NUM_SAMPLES (19)
21
22 struct v2f {
23 float4 pos : SV_POSITION;
24 float2 uv : TEXCOORD0;
25 };
26
27 sampler2D _MainTex;
28 sampler2D_float _CameraDepthTexture;
29 sampler2D _VelTex;
30 sampler2D _NeighbourMaxTex;
31 sampler2D _NoiseTex;
32
33 float4 _MainTex_TexelSize;
34 float4 _CameraDepthTexture_TexelSize;
35 float4 _VelTex_TexelSize;
36
37 float4x4 _InvViewProj; // inverse view-projection matrix
38 float4x4 _PrevViewProj; // previous view-projection matrix
39 float4x4 _ToPrevViewProjCombined; // combined
40
41 float _Jitter;
42
43 float _VelocityScale;
44 float _DisplayVelocityScale;
45
46 float _MinVelocity;
47
48 float _SoftZDistance;
49
50 v2f vert(appdata_img v)
51 {
52 v2f o;
53 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
54 o.uv = v.texcoord.xy;
55 return o;
56 }
57
58 // returns vector with largest magnitude
59 float2 vmax(float2 a, float2 b)
60 {
61 float ma = dot(a, a);
62 float mb = dot(b, b);
63 return (ma > mb) ? a : b;
64 }
65
66 // find dominant velocity in each tile
67 float4 TileMax(v2f i) : SV_Target
68 {
69 float2 tilemax = float2(0.0, 0.0);
70 float2 srcPos = i.uv - _MainTex_TexelSize.xy * _MaxRadiusOrKInPaper * 0.5;
71
72 for(int y=0; y<(int)_MaxRadiusOrKInPaper; y++) {
73 for(int x=0; x<(int)_MaxRadiusOrKInPaper; x++) {
74 float2 v = tex2D(_MainTex, srcPos + float2(x,y) * _MainTex_TexelSize.xy).xy;
75 tilemax = vmax(tilemax, v);
76 }
77 }
78 return float4(tilemax, 0, 1);
79 }
80
81 // find maximum velocity in any adjacent tile
82 float4 NeighbourMax(v2f i) : SV_Target
83 {
84 float2 maxvel = float2(0.0, 0.0);
85 for(int y=-1; y<=1; y++) {
86 for(int x=-1; x<=1; x++) {
87 float2 v = tex2D(_MainTex, i.uv + float2(x,y) * _MainTex_TexelSize.xy).xy;
88 maxvel = vmax(maxvel, v);
89 }
90 }
91 return float4(maxvel, 0, 1);
92 }
93
94 float cone(float2 px, float2 py, float2 v)
95 {
96 return clamp(1.0 - (length(px - py) / length(v)), 0.0, 1.0);
97 }
98
99 float cylinder(float2 x, float2 y, float2 v)
100 {
101 float lv = length(v);
102 return 1.0 - smoothstep(0.95*lv, 1.05*lv, length(x - y));
103 }
104
105 float softDepthCompare(float za, float zb)
106 {
107 return clamp(1.0 - (za - zb) / _SoftZDistance, 0.0, 1.0);
108 }
109
110 float4 ReconstructFilterBlur(v2f i) : SV_Target
111 {
112 float2 x = i.uv;
113 float2 xf = x;
114
115 #if UNITY_UV_STARTS_AT_TOP
116 if (_MainTex_TexelSize.y < 0)
117 xf.y = 1-xf.y;
118 #endif
119
120 float2 x2 = xf;
121
122 float2 vn = tex2D(_NeighbourMaxTex, x2).xy; // largest velocity in neighbourhood
123 float4 cx = tex2D(_MainTex, x); // color at x
124
125 float zx = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, x);
126 zx = -Linear01Depth(zx); // depth at x
127 float2 vx = tex2D(_VelTex, xf).xy; // vel at x
128
129 // random offset [-0.5, 0.5]
130 float j = (tex2D(_NoiseTex, i.uv * 11.0f ).r*2-1) * _Jitter;
131
132 // sample current pixel
133 float weight = 1.0;
134 float4 sum = cx * weight;
135
136 int centerSample = (int)(NUM_SAMPLES-1) / 2;
137
138 // in DX11 county we take more samples and interleave with sampling along vx direction to break up "patternized" look
139
140 for(int l=0; l<NUM_SAMPLES; l++)
141 {
142 if (l==centerSample) continue; // skip center sample
143
144 // Choose evenly placed filter taps along +-vN,
145 // but jitter the whole filter to prevent ghosting
146
147 float t = lerp(-1.0, 1.0, (l + j) / (-1 + _Jitter + (float)NUM_SAMPLES));
148 //float t = lerp(-1.0, 1.0, l / (float)(NUM_SAMPLES - 1));
149
150 float2 velInterlaved = lerp(vn, min(vx, normalize(vx) * _MainTex_TexelSize.xy * _MaxRadiusOrKInPaper), l%2==0);
151 float2 y = x + velInterlaved * t;
152
153 float2 yf = y;
154 #if UNITY_UV_STARTS_AT_TOP
155 if (_MainTex_TexelSize.y < 0)
156 yf.y = 1-yf.y;
157 #endif
158
159 // velocity at y
160 float2 vy = tex2Dlod(_VelTex, float4(yf,0,0)).xy;
161
162 float zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y,0,0));
163 zy = -Linear01Depth(zy);
164 float f = softDepthCompare(zx, zy);
165 float b = softDepthCompare(zy, zx);
166 float alphay = f * cone(y, x, vy) + // blurry y in front of any x
167 b * cone(x, y, vx) + // any y behing blurry x; estimate background
168 cylinder(y, x, vy) * cylinder(x, y, vx) * 2.0; // simultaneous blurry x and y
169
170 float4 cy = tex2Dlod(_MainTex, float4(y,0,0));
171 sum += cy * alphay;
172 weight += alphay;
173 }
174 sum /= weight;
175 return sum;
176 }
177
178
179 ENDCG
180
181 Subshader {
182
183 // pass 0
184 Pass {
185 ZTest Always Cull Off ZWrite Off
186
187 CGPROGRAM
188 #pragma target 5.0
189 #pragma vertex vert
190 #pragma fragment TileMax
191
192 ENDCG
193 }
194
195 // pass 1
196 Pass {
197 ZTest Always Cull Off ZWrite Off
198
199 CGPROGRAM
200 #pragma target 5.0
201 #pragma vertex vert
202 #pragma fragment NeighbourMax
203
204 ENDCG
205 }
206
207 // pass 2
208 Pass {
209 ZTest Always Cull Off ZWrite Off
210
211 CGPROGRAM
212 #pragma target 5.0
213 #pragma vertex vert
214 #pragma fragment ReconstructFilterBlur
215
216 ENDCG
217 }
218 }
219
220 Fallback off
221 }