CameraMotionBlur.shader 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2. /*
  3. CAMERA MOTION BLUR IMAGE EFFECTS
  4. Reconstruction Filter:
  5. Based on "Plausible Motion Blur"
  6. http://graphics.cs.williams.edu/papers/MotionBlurI3D12/
  7. CameraMotion:
  8. Based on Alex Vlacho's technique in
  9. http://www.valvesoftware.com/publications/2008/GDC2008_PostProcessingInTheOrangeBox.pdf
  10. SimpleBlur:
  11. Straightforward sampling along velocities
  12. ScatterFromGather:
  13. Combines Reconstruction with depth of field type defocus
  14. */
  15. Shader "Hidden/CameraMotionBlur" {
  16. Properties {
  17. _MainTex ("-", 2D) = "" {}
  18. _NoiseTex ("-", 2D) = "grey" {}
  19. _VelTex ("-", 2D) = "black" {}
  20. _NeighbourMaxTex ("-", 2D) = "black" {}
  21. }
  22. CGINCLUDE
  23. #include "UnityCG.cginc"
  24. // 's' in paper (# of samples for reconstruction)
  25. #define NUM_SAMPLES (11)
  26. // # samples for valve style blur
  27. #define MOTION_SAMPLES (16)
  28. // 'k' in paper
  29. float _MaxRadiusOrKInPaper;
  30. static const int SmallDiscKernelSamples = 12;
  31. static const float2 SmallDiscKernel[SmallDiscKernelSamples] =
  32. {
  33. float2(-0.326212,-0.40581),
  34. float2(-0.840144,-0.07358),
  35. float2(-0.695914,0.457137),
  36. float2(-0.203345,0.620716),
  37. float2(0.96234,-0.194983),
  38. float2(0.473434,-0.480026),
  39. float2(0.519456,0.767022),
  40. float2(0.185461,-0.893124),
  41. float2(0.507431,0.064425),
  42. float2(0.89642,0.412458),
  43. float2(-0.32194,-0.932615),
  44. float2(-0.791559,-0.59771)
  45. };
  46. struct v2f
  47. {
  48. float4 pos : SV_POSITION;
  49. float2 uv : TEXCOORD0;
  50. };
  51. sampler2D _MainTex;
  52. sampler2D_float _CameraDepthTexture;
  53. sampler2D _VelTex;
  54. sampler2D _NeighbourMaxTex;
  55. sampler2D _NoiseTex;
  56. sampler2D _TileTexDebug;
  57. float4 _MainTex_TexelSize;
  58. float4 _CameraDepthTexture_TexelSize;
  59. float4 _VelTex_TexelSize;
  60. float4x4 _InvViewProj; // inverse view-projection matrix
  61. float4x4 _PrevViewProj; // previous view-projection matrix
  62. float4x4 _ToPrevViewProjCombined; // combined
  63. float _Jitter;
  64. float _VelocityScale;
  65. float _DisplayVelocityScale;
  66. float _MaxVelocity;
  67. float _MinVelocity;
  68. float4 _BlurDirectionPacked;
  69. float _SoftZDistance;
  70. v2f vert(appdata_img v)
  71. {
  72. v2f o;
  73. o.pos = UnityObjectToClipPos(v.vertex);
  74. o.uv = v.texcoord.xy;
  75. return o;
  76. }
  77. float4 CameraVelocity(v2f i) : SV_Target
  78. {
  79. float2 depth_uv = i.uv;
  80. #if UNITY_UV_STARTS_AT_TOP
  81. if (_MainTex_TexelSize.y < 0)
  82. depth_uv.y = 1 - depth_uv.y;
  83. #endif
  84. // read depth
  85. float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, depth_uv);
  86. // calculate position from pixel from depth
  87. float3 clipPos = float3(i.uv.x*2.0-1.0, (i.uv.y)*2.0-1.0, d);
  88. // only 1 matrix mul:
  89. float4 prevClipPos = mul(_ToPrevViewProjCombined, float4(clipPos, 1.0));
  90. prevClipPos.xyz /= prevClipPos.w;
  91. /*
  92. float4 ws = mul(_InvViewProj, float4(clipPos, 1.0));
  93. ws /= ws.w;
  94. prevClipPos = mul(_PrevViewProj,ws);
  95. prevClipPos.xyz /= prevClipPos.w;
  96. */
  97. /*
  98. float2 vel = _VelocityScale *(clipPos.xy - prevClipPos.xy) / 2.f;
  99. // clamp to maximum velocity (in pixels)
  100. float maxVel = length(_MainTex_TexelSize.xy*_MaxVelocity);
  101. if (length(vel) > maxVel) {
  102. vel = normalize(vel) * maxVel;
  103. }
  104. return float4(vel, 0.0, 0.0);
  105. */
  106. float2 vel = _MainTex_TexelSize.zw * _VelocityScale * (clipPos.xy - prevClipPos.xy) / 2.f;
  107. float vellen = length(vel);
  108. float maxVel = _MaxVelocity;
  109. float2 velOut = vel * max(0.5, min(vellen, maxVel)) / (vellen + 1e-2f);
  110. velOut *= _MainTex_TexelSize.xy;
  111. return float4(velOut, 0.0, 0.0);
  112. }
  113. // vector with largest magnitude
  114. float2 vmax(float2 a, float2 b)
  115. {
  116. float ma = dot(a, a);
  117. float mb = dot(b, b);
  118. return (ma > mb) ? a : b;
  119. }
  120. // find dominant velocity for each tile
  121. float4 TileMax(v2f i) : SV_Target
  122. {
  123. float2 uvCorner = i.uv - _MainTex_TexelSize.xy * (_MaxRadiusOrKInPaper * 0.5);
  124. float2 maxvel = float2(0,0);
  125. float4 baseUv = float4(uvCorner,0,0);
  126. float4 uvScale = float4(_MainTex_TexelSize.xy, 0, 0);
  127. for(int l=0; l<(int)_MaxRadiusOrKInPaper; l++)
  128. {
  129. for(int k=0; k<(int)_MaxRadiusOrKInPaper; k++)
  130. {
  131. maxvel = vmax(maxvel, tex2Dlod(_MainTex, baseUv + float4(l,k,0,0) * uvScale).xy);
  132. }
  133. }
  134. return float4(maxvel, 0, 1);
  135. }
  136. // find maximum velocity in any adjacent tile
  137. float4 NeighbourMax(v2f i) : SV_Target
  138. {
  139. float2 x_ = i.uv;
  140. // to fetch all neighbours, we need 3x3 point filtered samples
  141. float2 nx = tex2D(_MainTex, x_+float2(1.0, 1.0)*_MainTex_TexelSize.xy).xy;
  142. nx = vmax(nx, tex2D(_MainTex, x_+float2(1.0, 0.0)*_MainTex_TexelSize.xy).xy);
  143. nx = vmax(nx, tex2D(_MainTex, x_+float2(1.0,-1.0)*_MainTex_TexelSize.xy).xy);
  144. nx = vmax(nx, tex2D(_MainTex, x_+float2(0.0, 1.0)*_MainTex_TexelSize.xy).xy);
  145. nx = vmax(nx, tex2D(_MainTex, x_+float2(0.0, 0.0)*_MainTex_TexelSize.xy).xy);
  146. nx = vmax(nx, tex2D(_MainTex, x_+float2(0.0,-1.0)*_MainTex_TexelSize.xy).xy);
  147. nx = vmax(nx, tex2D(_MainTex, x_+float2(-1.0, 1.0)*_MainTex_TexelSize.xy).xy);
  148. nx = vmax(nx, tex2D(_MainTex, x_+float2(-1.0, 0.0)*_MainTex_TexelSize.xy).xy);
  149. nx = vmax(nx, tex2D(_MainTex, x_+float2(-1.0,-1.0)*_MainTex_TexelSize.xy).xy);
  150. return float4(nx, 0, 0);
  151. }
  152. float4 Debug(v2f i) : SV_Target
  153. {
  154. return saturate( float4(tex2D(_MainTex, i.uv).x,abs(tex2D(_MainTex, i.uv).y),-tex2D(_MainTex, i.uv).xy) * _DisplayVelocityScale);
  155. }
  156. // classification filters
  157. float cone(float2 px, float2 py, float2 v)
  158. {
  159. return clamp(1.0 - (length(px - py) / length(v)), 0.0, 1.0);
  160. }
  161. float cylinder(float2 x, float2 y, float2 v)
  162. {
  163. float lv = length(v);
  164. return 1.0 - smoothstep(0.95*lv, 1.05*lv, length(x - y));
  165. }
  166. // is zb closer than za?
  167. float softDepthCompare(float za, float zb)
  168. {
  169. return clamp(1.0 - (za - zb) / _SoftZDistance, 0.0, 1.0);
  170. }
  171. float4 SimpleBlur (v2f i) : SV_Target
  172. {
  173. float2 x = i.uv;
  174. float2 xf = x;
  175. #if UNITY_UV_STARTS_AT_TOP
  176. if (_MainTex_TexelSize.y < 0)
  177. xf.y = 1 - xf.y;
  178. #endif
  179. float2 vx = tex2D(_VelTex, xf).xy; // vel at x
  180. float4 sum = float4(0, 0, 0, 0);
  181. for(int l=0; l<NUM_SAMPLES; l++) {
  182. float t = l / (float) (NUM_SAMPLES - 1);
  183. t = t-0.5;
  184. float2 y = x - vx*t;
  185. float4 cy = tex2D(_MainTex, y);
  186. sum += cy;
  187. }
  188. sum /= NUM_SAMPLES;
  189. return sum;
  190. }
  191. float4 ReconstructFilterBlur(v2f i) : SV_Target
  192. {
  193. // uv's
  194. float2 x = i.uv;
  195. float2 xf = x;
  196. #if UNITY_UV_STARTS_AT_TOP
  197. if (_MainTex_TexelSize.y < 0)
  198. xf.y = 1-xf.y;
  199. #endif
  200. float2 x2 = xf;
  201. float2 vn = tex2Dlod(_NeighbourMaxTex, float4(x2,0,0)).xy; // largest velocity in neighbourhood
  202. float4 cx = tex2Dlod(_MainTex, float4(x,0,0)); // color at x
  203. float2 vx = tex2Dlod(_VelTex, float4(xf,0,0)).xy; // vel at x
  204. float zx = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(x,0,0));
  205. zx = -Linear01Depth(zx);
  206. // random offset [-0.5, 0.5]
  207. float j = (tex2Dlod(_NoiseTex, float4(i.uv,0,0) * 11.0f).r*2-1) * _Jitter;
  208. // sample current pixel
  209. float weight = 0.75; // <= good start weight choice??
  210. float4 sum = cx * weight;
  211. int centerSample = (int)(NUM_SAMPLES-1)/2;
  212. for(int l=0; l<NUM_SAMPLES; l++)
  213. {
  214. float contrib = 1.0f;
  215. #if SHADER_API_D3D11
  216. if (l==centerSample) continue; // skip center sample
  217. #else
  218. if (l==centerSample) contrib = 0.0f; // skip center sample
  219. #endif
  220. float t = lerp(-1.0, 1.0, (l + j) / (-1 + _Jitter + (float)NUM_SAMPLES));
  221. //float t = lerp(-1.0, 1.0, l / (float)(NUM_SAMPLES - 1));
  222. float2 y = x + vn * t;
  223. float2 yf = y;
  224. #if UNITY_UV_STARTS_AT_TOP
  225. if (_MainTex_TexelSize.y < 0)
  226. yf.y = 1-yf.y;
  227. #endif
  228. // velocity at y
  229. float2 vy = tex2Dlod(_VelTex, float4(yf,0,0)).xy;
  230. float zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y,0,0));
  231. zy = -Linear01Depth(zy);
  232. float f = softDepthCompare(zx, zy);
  233. float b = softDepthCompare(zy, zx);
  234. float alphay = b * cone(x, y, vx) + f * cone(y, x, vy) + cylinder(y, x, vy) * cylinder(x, y, vx) * 2.0;
  235. float4 cy = tex2Dlod(_MainTex, float4(y,0,0));
  236. sum += cy * alphay * contrib;
  237. weight += alphay * contrib;
  238. }
  239. sum /= weight;
  240. return sum;
  241. }
  242. float4 ReconstructionDiscBlur (v2f i) : SV_Target
  243. {
  244. float2 xf = i.uv;
  245. float2 x = i.uv;
  246. #if UNITY_UV_STARTS_AT_TOP
  247. if (_MainTex_TexelSize.y < 0)
  248. xf.y = 1 - xf.y;
  249. #endif
  250. float2 x2 = xf;
  251. float2 vn = tex2Dlod(_NeighbourMaxTex, float4(x2,0,0)).xy; // largest velocity in neighbourhood
  252. float4 cx = tex2Dlod(_MainTex, float4(x,0,0)); // color at x
  253. float2 vx = tex2Dlod(_VelTex, float4(xf,0,0)).xy; // vel at x
  254. float4 noise = tex2Dlod(_NoiseTex, float4(i.uv,0,0)*11.0f)*2-1;
  255. float zx = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(x,0,0));
  256. zx = -Linear01Depth(zx);
  257. noise *= _MainTex_TexelSize.xyxy * _Jitter;
  258. //return abs(blurDir.xyxy)*10 + centerTap;
  259. float weight = 1.0; // <- maybe tweak this: bluriness amount ...
  260. float4 sum = cx * weight;
  261. float4 jitteredDir = vn.xyxy + noise.xyyz;
  262. #ifdef SHADER_API_D3D11
  263. jitteredDir = max(abs(jitteredDir.xyxy), _MainTex_TexelSize.xyxy * _MaxVelocity * 0.5) * sign(jitteredDir.xyxy) * float4(1,1,-1,-1);
  264. #else
  265. jitteredDir = max(abs(jitteredDir.xyxy), _MainTex_TexelSize.xyxy * _MaxVelocity * 0.15) * sign(jitteredDir.xyxy) * float4(1,1,-1,-1);
  266. #endif
  267. for(int l=0; l<SmallDiscKernelSamples; l++)
  268. {
  269. float4 y = i.uv.xyxy + jitteredDir.xyxy * SmallDiscKernel[l].xyxy * float4(1,1,-1,-1);
  270. float4 yf = y;
  271. #if UNITY_UV_STARTS_AT_TOP
  272. if (_MainTex_TexelSize.y < 0)
  273. yf.yw = 1-yf.yw;
  274. #endif
  275. // velocity at y
  276. float2 vy = tex2Dlod(_VelTex, float4(yf.xy,0,0)).xy;
  277. float zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y.xy,0,0) );
  278. zy = -Linear01Depth(zy);
  279. float f = softDepthCompare(zx, zy);
  280. float b = softDepthCompare(zy, zx);
  281. 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;
  282. float4 cy = tex2Dlod(_MainTex, float4(y.xy,0,0));
  283. sum += cy * alphay;
  284. weight += alphay;
  285. #ifdef SHADER_API_D3D11
  286. vy = tex2Dlod(_VelTex, float4(yf.zw,0,0)).xy;
  287. zy = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, float4(y.zw,0,0) );
  288. zy = -Linear01Depth(zy);
  289. f = softDepthCompare(zx, zy);
  290. b = softDepthCompare(zy, zx);
  291. 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;
  292. cy = tex2Dlod(_MainTex, float4(y.zw,0,0));
  293. sum += cy * alphay;
  294. weight += alphay;
  295. #endif
  296. }
  297. return sum / weight;
  298. }
  299. float4 MotionVectorBlur (v2f i) : SV_Target
  300. {
  301. float2 x = i.uv;
  302. float2 insideVector = (x*2-1) * float2(1,_MainTex_TexelSize.w/_MainTex_TexelSize.z);
  303. float2 rollVector = float2(insideVector.y, -insideVector.x);
  304. float2 blurDir = _BlurDirectionPacked.x * float2(0,1);
  305. blurDir += _BlurDirectionPacked.y * float2(1,0);
  306. blurDir += _BlurDirectionPacked.z * rollVector;
  307. blurDir += _BlurDirectionPacked.w * insideVector;
  308. blurDir *= _VelocityScale;
  309. // clamp to maximum velocity (in pixels)
  310. float velMag = length(blurDir);
  311. if (velMag > _MaxVelocity) {
  312. blurDir *= (_MaxVelocity / velMag);
  313. velMag = _MaxVelocity;
  314. }
  315. float4 centerTap = tex2D(_MainTex, x);
  316. float4 sum = centerTap;
  317. blurDir *= smoothstep(_MinVelocity * 0.25f, _MinVelocity * 2.5, velMag);
  318. blurDir *= _MainTex_TexelSize.xy;
  319. blurDir /= MOTION_SAMPLES;
  320. for(int i=0; i<MOTION_SAMPLES; i++) {
  321. float4 tap = tex2D(_MainTex, x+i*blurDir);
  322. sum += tap;
  323. }
  324. return sum/(1+MOTION_SAMPLES);
  325. }
  326. ENDCG
  327. Subshader {
  328. // pass 0
  329. Pass {
  330. ZTest Always Cull Off ZWrite On Blend Off
  331. CGPROGRAM
  332. #pragma target 3.0
  333. #pragma vertex vert
  334. #pragma fragment CameraVelocity
  335. ENDCG
  336. }
  337. // pass 1
  338. Pass {
  339. ZTest Always Cull Off ZWrite Off Blend Off
  340. CGPROGRAM
  341. #pragma target 3.0
  342. #pragma vertex vert
  343. #pragma fragment Debug
  344. ENDCG
  345. }
  346. // pass 2
  347. Pass {
  348. ZTest Always Cull Off ZWrite Off Blend Off
  349. CGPROGRAM
  350. #pragma target 3.0
  351. #pragma vertex vert
  352. #pragma fragment TileMax
  353. ENDCG
  354. }
  355. // pass 3
  356. Pass {
  357. ZTest Always Cull Off ZWrite Off Blend Off
  358. CGPROGRAM
  359. #pragma target 3.0
  360. #pragma vertex vert
  361. #pragma fragment NeighbourMax
  362. ENDCG
  363. }
  364. // pass 4
  365. Pass {
  366. ZTest Always Cull Off ZWrite Off Blend Off
  367. CGPROGRAM
  368. #pragma target 3.0
  369. #pragma vertex vert
  370. #pragma fragment ReconstructFilterBlur
  371. ENDCG
  372. }
  373. // pass 5
  374. Pass {
  375. ZTest Always Cull Off ZWrite Off Blend Off
  376. CGPROGRAM
  377. #pragma target 3.0
  378. #pragma vertex vert
  379. #pragma fragment SimpleBlur
  380. ENDCG
  381. }
  382. // pass 6
  383. Pass {
  384. ZTest Always Cull Off ZWrite Off Blend Off
  385. CGPROGRAM
  386. #pragma target 3.0
  387. #pragma vertex vert
  388. #pragma fragment MotionVectorBlur
  389. ENDCG
  390. }
  391. // pass 7
  392. Pass {
  393. ZTest Always Cull Off ZWrite Off Blend Off
  394. CGPROGRAM
  395. #pragma target 3.0
  396. #pragma vertex vert
  397. #pragma fragment ReconstructionDiscBlur
  398. ENDCG
  399. }
  400. }
  401. Fallback off
  402. }