MotionBlur.shader 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. Shader "Hidden/PostProcessing/MotionBlur"
  2. {
  3. HLSLINCLUDE
  4. #pragma target 3.0
  5. #include "../StdLib.hlsl"
  6. TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
  7. float4 _MainTex_TexelSize;
  8. // Camera depth texture
  9. TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);
  10. // Camera motion vectors texture
  11. TEXTURE2D_SAMPLER2D(_CameraMotionVectorsTexture, sampler_CameraMotionVectorsTexture);
  12. float4 _CameraMotionVectorsTexture_TexelSize;
  13. // Packed velocity texture (2/10/10/10)
  14. TEXTURE2D_SAMPLER2D(_VelocityTex, sampler_VelocityTex);
  15. float2 _VelocityTex_TexelSize;
  16. // NeighborMax texture
  17. TEXTURE2D_SAMPLER2D(_NeighborMaxTex, sampler_NeighborMaxTex);
  18. float2 _NeighborMaxTex_TexelSize;
  19. // Velocity scale factor
  20. float _VelocityScale;
  21. // TileMax filter parameters
  22. int _TileMaxLoop;
  23. float2 _TileMaxOffs;
  24. // Maximum blur radius (in pixels)
  25. half _MaxBlurRadius;
  26. float _RcpMaxBlurRadius;
  27. // Filter parameters/coefficients
  28. half _LoopCount;
  29. // -----------------------------------------------------------------------------
  30. // Prefilter
  31. // Velocity texture setup
  32. half4 FragVelocitySetup(VaryingsDefault i) : SV_Target
  33. {
  34. // Sample the motion vector.
  35. float2 v = SAMPLE_TEXTURE2D(_CameraMotionVectorsTexture, sampler_CameraMotionVectorsTexture, i.texcoord).rg;
  36. // Apply the exposure time and convert to the pixel space.
  37. v *= (_VelocityScale * 0.5) * _CameraMotionVectorsTexture_TexelSize.zw;
  38. // Clamp the vector with the maximum blur radius.
  39. v /= max(1.0, length(v) * _RcpMaxBlurRadius);
  40. // Sample the depth of the pixel.
  41. half d = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoord));
  42. // Pack into 10/10/10/2 format.
  43. return half4((v * _RcpMaxBlurRadius + 1.0) * 0.5, d, 0.0);
  44. }
  45. half2 MaxV(half2 v1, half2 v2)
  46. {
  47. return dot(v1, v1) < dot(v2, v2) ? v2 : v1;
  48. }
  49. // TileMax filter (2 pixel width with normalization)
  50. half4 FragTileMax1(VaryingsDefault i) : SV_Target
  51. {
  52. float4 d = _MainTex_TexelSize.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
  53. half2 v1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xy).rg;
  54. half2 v2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.zy).rg;
  55. half2 v3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xw).rg;
  56. half2 v4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.zw).rg;
  57. v1 = (v1 * 2.0 - 1.0) * _MaxBlurRadius;
  58. v2 = (v2 * 2.0 - 1.0) * _MaxBlurRadius;
  59. v3 = (v3 * 2.0 - 1.0) * _MaxBlurRadius;
  60. v4 = (v4 * 2.0 - 1.0) * _MaxBlurRadius;
  61. return half4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0);
  62. }
  63. // TileMax filter (2 pixel width)
  64. half4 FragTileMax2(VaryingsDefault i) : SV_Target
  65. {
  66. float4 d = _MainTex_TexelSize.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
  67. half2 v1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xy).rg;
  68. half2 v2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.zy).rg;
  69. half2 v3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xw).rg;
  70. half2 v4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.zw).rg;
  71. return half4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0);
  72. }
  73. // TileMax filter (variable width)
  74. half4 FragTileMaxV(VaryingsDefault i) : SV_Target
  75. {
  76. float2 uv0 = i.texcoord + _MainTex_TexelSize.xy * _TileMaxOffs.xy;
  77. float2 du = float2(_MainTex_TexelSize.x, 0.0);
  78. float2 dv = float2(0.0, _MainTex_TexelSize.y);
  79. half2 vo = 0.0;
  80. UNITY_LOOP
  81. for (int ix = 0; ix < _TileMaxLoop; ix++)
  82. {
  83. UNITY_LOOP
  84. for (int iy = 0; iy < _TileMaxLoop; iy++)
  85. {
  86. float2 uv = uv0 + du * ix + dv * iy;
  87. vo = MaxV(vo, SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv).rg);
  88. }
  89. }
  90. return half4(vo, 0.0, 0.0);
  91. }
  92. // NeighborMax filter
  93. half4 FragNeighborMax(VaryingsDefault i) : SV_Target
  94. {
  95. const half cw = 1.01; // Center weight tweak
  96. float4 d = _MainTex_TexelSize.xyxy * float4(1.0, 1.0, -1.0, 0.0);
  97. half2 v1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - d.xy).rg;
  98. half2 v2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - d.wy).rg;
  99. half2 v3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - d.zy).rg;
  100. half2 v4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - d.xw).rg;
  101. half2 v5 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord).rg * cw;
  102. half2 v6 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xw).rg;
  103. half2 v7 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.zy).rg;
  104. half2 v8 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.wy).rg;
  105. half2 v9 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + d.xy).rg;
  106. half2 va = MaxV(v1, MaxV(v2, v3));
  107. half2 vb = MaxV(v4, MaxV(v5, v6));
  108. half2 vc = MaxV(v7, MaxV(v8, v9));
  109. return half4(MaxV(va, MaxV(vb, vc)) * (1.0 / cw), 0.0, 0.0);
  110. }
  111. // -----------------------------------------------------------------------------
  112. // Reconstruction
  113. // Returns true or false with a given interval.
  114. bool Interval(half phase, half interval)
  115. {
  116. return frac(phase / interval) > 0.499;
  117. }
  118. // Jitter function for tile lookup
  119. float2 JitterTile(float2 uv)
  120. {
  121. float rx, ry;
  122. sincos(GradientNoise(uv + float2(2.0, 0.0)) * TWO_PI, ry, rx);
  123. return float2(rx, ry) * _NeighborMaxTex_TexelSize.xy * 0.25;
  124. }
  125. // Velocity sampling function
  126. half3 SampleVelocity(float2 uv)
  127. {
  128. half3 v = SAMPLE_TEXTURE2D_LOD(_VelocityTex, sampler_VelocityTex, uv, 0.0).xyz;
  129. return half3((v.xy * 2.0 - 1.0) * _MaxBlurRadius, v.z);
  130. }
  131. // Reconstruction filter
  132. half4 FragReconstruction(VaryingsDefault i) : SV_Target
  133. {
  134. // Color sample at the center point
  135. const half4 c_p = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
  136. // Velocity/Depth sample at the center point
  137. const half3 vd_p = SampleVelocity(i.texcoord);
  138. const half l_v_p = max(length(vd_p.xy), 0.5);
  139. const half rcp_d_p = 1.0 / vd_p.z;
  140. // NeighborMax vector sample at the center point
  141. const half2 v_max = SAMPLE_TEXTURE2D(_NeighborMaxTex, sampler_NeighborMaxTex, i.texcoord + JitterTile(i.texcoord)).xy;
  142. const half l_v_max = length(v_max);
  143. const half rcp_l_v_max = 1.0 / l_v_max;
  144. // Escape early if the NeighborMax vector is small enough.
  145. if (l_v_max < 2.0) return c_p;
  146. // Use V_p as a secondary sampling direction except when it's too small
  147. // compared to V_max. This vector is rescaled to be the length of V_max.
  148. const half2 v_alt = (l_v_p * 2.0 > l_v_max) ? vd_p.xy * (l_v_max / l_v_p) : v_max;
  149. // Determine the sample count.
  150. const half sc = floor(min(_LoopCount, l_v_max * 0.5));
  151. // Loop variables (starts from the outermost sample)
  152. const half dt = 1.0 / sc;
  153. const half t_offs = (GradientNoise(i.texcoord) - 0.5) * dt;
  154. half t = 1.0 - dt * 0.5;
  155. half count = 0.0;
  156. // Background velocity
  157. // This is used for tracking the maximum velocity in the background layer.
  158. half l_v_bg = max(l_v_p, 1.0);
  159. // Color accumlation
  160. half4 acc = 0.0;
  161. UNITY_LOOP
  162. while (t > dt * 0.25)
  163. {
  164. // Sampling direction (switched per every two samples)
  165. const half2 v_s = Interval(count, 4.0) ? v_alt : v_max;
  166. // Sample position (inverted per every sample)
  167. const half t_s = (Interval(count, 2.0) ? -t : t) + t_offs;
  168. // Distance to the sample position
  169. const half l_t = l_v_max * abs(t_s);
  170. // UVs for the sample position
  171. const float2 uv0 = i.texcoord + v_s * t_s * _MainTex_TexelSize.xy;
  172. const float2 uv1 = i.texcoord + v_s * t_s * _VelocityTex_TexelSize.xy;
  173. // Color sample
  174. const half3 c = SAMPLE_TEXTURE2D_LOD(_MainTex, sampler_MainTex, uv0, 0.0).rgb;
  175. // Velocity/Depth sample
  176. const half3 vd = SampleVelocity(uv1);
  177. // Background/Foreground separation
  178. const half fg = saturate((vd_p.z - vd.z) * 20.0 * rcp_d_p);
  179. // Length of the velocity vector
  180. const half l_v = lerp(l_v_bg, length(vd.xy), fg);
  181. // Sample weight
  182. // (Distance test) * (Spreading out by motion) * (Triangular window)
  183. const half w = saturate(l_v - l_t) / l_v * (1.2 - t);
  184. // Color accumulation
  185. acc += half4(c, 1.0) * w;
  186. // Update the background velocity.
  187. l_v_bg = max(l_v_bg, l_v);
  188. // Advance to the next sample.
  189. t = Interval(count, 2.0) ? t - dt : t;
  190. count += 1.0;
  191. }
  192. // Add the center sample.
  193. acc += half4(c_p.rgb, 1.0) * (1.2 / (l_v_bg * sc * 2.0));
  194. return half4(acc.rgb / acc.a, c_p.a);
  195. }
  196. ENDHLSL
  197. SubShader
  198. {
  199. Cull Off ZWrite Off ZTest Always
  200. // (0) Velocity texture setup
  201. Pass
  202. {
  203. HLSLPROGRAM
  204. #pragma vertex VertDefault
  205. #pragma fragment FragVelocitySetup
  206. ENDHLSL
  207. }
  208. // (1) TileMax filter (2 pixel width with normalization)
  209. Pass
  210. {
  211. HLSLPROGRAM
  212. #pragma vertex VertDefault
  213. #pragma fragment FragTileMax1
  214. ENDHLSL
  215. }
  216. // (2) TileMax filter (2 pixel width)
  217. Pass
  218. {
  219. HLSLPROGRAM
  220. #pragma vertex VertDefault
  221. #pragma fragment FragTileMax2
  222. ENDHLSL
  223. }
  224. // (3) TileMax filter (variable width)
  225. Pass
  226. {
  227. HLSLPROGRAM
  228. #pragma vertex VertDefault
  229. #pragma fragment FragTileMaxV
  230. ENDHLSL
  231. }
  232. // (4) NeighborMax filter
  233. Pass
  234. {
  235. HLSLPROGRAM
  236. #pragma vertex VertDefault
  237. #pragma fragment FragNeighborMax
  238. ENDHLSL
  239. }
  240. // (5) Reconstruction filter
  241. Pass
  242. {
  243. HLSLPROGRAM
  244. #pragma vertex VertDefault
  245. #pragma fragment FragReconstruction
  246. ENDHLSL
  247. }
  248. }
  249. }