You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

420 lines
12 KiB

  1. #ifndef __MOTION_BLUR__
  2. #define __MOTION_BLUR__
  3. #include "UnityCG.cginc"
  4. #include "Common.cginc"
  5. // Camera depth texture
  6. sampler2D_float _CameraDepthTexture;
  7. // Camera motion vectors texture
  8. sampler2D_half _CameraMotionVectorsTexture;
  9. float4 _CameraMotionVectorsTexture_TexelSize;
  10. // Packed velocity texture (2/10/10/10)
  11. sampler2D_half _VelocityTex;
  12. float2 _VelocityTex_TexelSize;
  13. // NeighborMax texture
  14. sampler2D_half _NeighborMaxTex;
  15. float2 _NeighborMaxTex_TexelSize;
  16. // Velocity scale factor
  17. float _VelocityScale;
  18. // TileMax filter parameters
  19. int _TileMaxLoop;
  20. float2 _TileMaxOffs;
  21. // Maximum blur radius (in pixels)
  22. half _MaxBlurRadius;
  23. float _RcpMaxBlurRadius;
  24. // Filter parameters/coefficients
  25. half _LoopCount;
  26. // History buffer for frame blending
  27. sampler2D _History1LumaTex;
  28. sampler2D _History2LumaTex;
  29. sampler2D _History3LumaTex;
  30. sampler2D _History4LumaTex;
  31. sampler2D _History1ChromaTex;
  32. sampler2D _History2ChromaTex;
  33. sampler2D _History3ChromaTex;
  34. sampler2D _History4ChromaTex;
  35. half _History1Weight;
  36. half _History2Weight;
  37. half _History3Weight;
  38. half _History4Weight;
  39. struct VaryingsMultitex
  40. {
  41. float4 pos : SV_POSITION;
  42. float2 uv0 : TEXCOORD0;
  43. float2 uv1 : TEXCOORD1;
  44. };
  45. VaryingsMultitex VertMultitex(AttributesDefault v)
  46. {
  47. VaryingsMultitex o;
  48. o.pos = UnityObjectToClipPos(v.vertex);
  49. o.uv0 = v.texcoord.xy;
  50. o.uv1 = v.texcoord.xy;
  51. #if UNITY_UV_STARTS_AT_TOP
  52. if (_MainTex_TexelSize.y < 0.0)
  53. o.uv1.y = 1.0 - v.texcoord.y;
  54. #endif
  55. return o;
  56. }
  57. // -----------------------------------------------------------------------------
  58. // Prefilter
  59. // Velocity texture setup
  60. half4 FragVelocitySetup(VaryingsDefault i) : SV_Target
  61. {
  62. // Sample the motion vector.
  63. float2 v = tex2D(_CameraMotionVectorsTexture, i.uv).rg;
  64. // Apply the exposure time and convert to the pixel space.
  65. v *= (_VelocityScale * 0.5) * _CameraMotionVectorsTexture_TexelSize.zw;
  66. // Clamp the vector with the maximum blur radius.
  67. v /= max(1.0, length(v) * _RcpMaxBlurRadius);
  68. // Sample the depth of the pixel.
  69. half d = LinearizeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
  70. // Pack into 10/10/10/2 format.
  71. return half4((v * _RcpMaxBlurRadius + 1.0) * 0.5, d, 0.0);
  72. }
  73. // TileMax filter (2 pixel width with normalization)
  74. half4 FragTileMax1(VaryingsDefault i) : SV_Target
  75. {
  76. float4 d = _MainTex_TexelSize.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
  77. half2 v1 = tex2D(_MainTex, i.uv + d.xy).rg;
  78. half2 v2 = tex2D(_MainTex, i.uv + d.zy).rg;
  79. half2 v3 = tex2D(_MainTex, i.uv + d.xw).rg;
  80. half2 v4 = tex2D(_MainTex, i.uv + d.zw).rg;
  81. v1 = (v1 * 2.0 - 1.0) * _MaxBlurRadius;
  82. v2 = (v2 * 2.0 - 1.0) * _MaxBlurRadius;
  83. v3 = (v3 * 2.0 - 1.0) * _MaxBlurRadius;
  84. v4 = (v4 * 2.0 - 1.0) * _MaxBlurRadius;
  85. return half4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0);
  86. }
  87. // TileMax filter (2 pixel width)
  88. half4 FragTileMax2(VaryingsDefault i) : SV_Target
  89. {
  90. float4 d = _MainTex_TexelSize.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
  91. half2 v1 = tex2D(_MainTex, i.uv + d.xy).rg;
  92. half2 v2 = tex2D(_MainTex, i.uv + d.zy).rg;
  93. half2 v3 = tex2D(_MainTex, i.uv + d.xw).rg;
  94. half2 v4 = tex2D(_MainTex, i.uv + d.zw).rg;
  95. return half4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0);
  96. }
  97. // TileMax filter (variable width)
  98. half4 FragTileMaxV(VaryingsDefault i) : SV_Target
  99. {
  100. float2 uv0 = i.uv + _MainTex_TexelSize.xy * _TileMaxOffs.xy;
  101. float2 du = float2(_MainTex_TexelSize.x, 0.0);
  102. float2 dv = float2(0, _MainTex_TexelSize.y);
  103. half2 vo = 0;
  104. UNITY_LOOP
  105. for (int ix = 0; ix < _TileMaxLoop; ix++)
  106. {
  107. UNITY_LOOP
  108. for (int iy = 0; iy < _TileMaxLoop; iy++)
  109. {
  110. float2 uv = uv0 + du * ix + dv * iy;
  111. vo = MaxV(vo, tex2D(_MainTex, uv).rg);
  112. }
  113. }
  114. return half4(vo, 0.0, 0.0);
  115. }
  116. // NeighborMax filter
  117. half4 FragNeighborMax(VaryingsDefault i) : SV_Target
  118. {
  119. const half cw = 1.01; // Center weight tweak
  120. float4 d = _MainTex_TexelSize.xyxy * float4(1.0, 1.0, -1.0, 0.0);
  121. half2 v1 = tex2D(_MainTex, i.uv - d.xy).rg;
  122. half2 v2 = tex2D(_MainTex, i.uv - d.wy).rg;
  123. half2 v3 = tex2D(_MainTex, i.uv - d.zy).rg;
  124. half2 v4 = tex2D(_MainTex, i.uv - d.xw).rg;
  125. half2 v5 = tex2D(_MainTex, i.uv).rg * cw;
  126. half2 v6 = tex2D(_MainTex, i.uv + d.xw).rg;
  127. half2 v7 = tex2D(_MainTex, i.uv + d.zy).rg;
  128. half2 v8 = tex2D(_MainTex, i.uv + d.wy).rg;
  129. half2 v9 = tex2D(_MainTex, i.uv + d.xy).rg;
  130. half2 va = MaxV(v1, MaxV(v2, v3));
  131. half2 vb = MaxV(v4, MaxV(v5, v6));
  132. half2 vc = MaxV(v7, MaxV(v8, v9));
  133. return half4(MaxV(va, MaxV(vb, vc)) * (1.0 / cw), 0.0, 0.0);
  134. }
  135. // -----------------------------------------------------------------------------
  136. // Reconstruction
  137. // Returns true or false with a given interval.
  138. bool Interval(half phase, half interval)
  139. {
  140. return frac(phase / interval) > 0.499;
  141. }
  142. // Jitter function for tile lookup
  143. float2 JitterTile(float2 uv)
  144. {
  145. float rx, ry;
  146. sincos(GradientNoise(uv + float2(2.0, 0.0)) * UNITY_PI_2, ry, rx);
  147. return float2(rx, ry) * _NeighborMaxTex_TexelSize.xy * 0.25;
  148. }
  149. // Velocity sampling function
  150. half3 SampleVelocity(float2 uv)
  151. {
  152. half3 v = tex2Dlod(_VelocityTex, float4(uv, 0.0, 0.0)).xyz;
  153. return half3((v.xy * 2.0 - 1.0) * _MaxBlurRadius, v.z);
  154. }
  155. // Reconstruction filter
  156. half4 FragReconstruction(VaryingsMultitex i) : SV_Target
  157. {
  158. // Color sample at the center point
  159. const half4 c_p = tex2D(_MainTex, i.uv0);
  160. // Velocity/Depth sample at the center point
  161. const half3 vd_p = SampleVelocity(i.uv1);
  162. const half l_v_p = max(length(vd_p.xy), 0.5);
  163. const half rcp_d_p = 1.0 / vd_p.z;
  164. // NeighborMax vector sample at the center point
  165. const half2 v_max = tex2D(_NeighborMaxTex, i.uv1 + JitterTile(i.uv1)).xy;
  166. const half l_v_max = length(v_max);
  167. const half rcp_l_v_max = 1.0 / l_v_max;
  168. // Escape early if the NeighborMax vector is small enough.
  169. if (l_v_max < 2.0) return c_p;
  170. // Use V_p as a secondary sampling direction except when it's too small
  171. // compared to V_max. This vector is rescaled to be the length of V_max.
  172. const half2 v_alt = (l_v_p * 2.0 > l_v_max) ? vd_p.xy * (l_v_max / l_v_p) : v_max;
  173. // Determine the sample count.
  174. const half sc = floor(min(_LoopCount, l_v_max * 0.5));
  175. // Loop variables (starts from the outermost sample)
  176. const half dt = 1.0 / sc;
  177. const half t_offs = (GradientNoise(i.uv0) - 0.5) * dt;
  178. half t = 1.0 - dt * 0.5;
  179. half count = 0.0;
  180. // Background velocity
  181. // This is used for tracking the maximum velocity in the background layer.
  182. half l_v_bg = max(l_v_p, 1.0);
  183. // Color accumlation
  184. half4 acc = 0.0;
  185. UNITY_LOOP while (t > dt * 0.25)
  186. {
  187. // Sampling direction (switched per every two samples)
  188. const half2 v_s = Interval(count, 4.0) ? v_alt : v_max;
  189. // Sample position (inverted per every sample)
  190. const half t_s = (Interval(count, 2.0) ? -t : t) + t_offs;
  191. // Distance to the sample position
  192. const half l_t = l_v_max * abs(t_s);
  193. // UVs for the sample position
  194. const float2 uv0 = i.uv0 + v_s * t_s * _MainTex_TexelSize.xy;
  195. const float2 uv1 = i.uv1 + v_s * t_s * _VelocityTex_TexelSize.xy;
  196. // Color sample
  197. const half3 c = tex2Dlod(_MainTex, float4(uv0, 0.0, 0.0)).rgb;
  198. // Velocity/Depth sample
  199. const half3 vd = SampleVelocity(uv1);
  200. // Background/Foreground separation
  201. const half fg = saturate((vd_p.z - vd.z) * 20.0 * rcp_d_p);
  202. // Length of the velocity vector
  203. const half l_v = lerp(l_v_bg, length(vd.xy), fg);
  204. // Sample weight
  205. // (Distance test) * (Spreading out by motion) * (Triangular window)
  206. const half w = saturate(l_v - l_t) / l_v * (1.2 - t);
  207. // Color accumulation
  208. acc += half4(c, 1.0) * w;
  209. // Update the background velocity.
  210. l_v_bg = max(l_v_bg, l_v);
  211. // Advance to the next sample.
  212. t = Interval(count, 2.0) ? t - dt : t;
  213. count += 1.0;
  214. }
  215. // Add the center sample.
  216. acc += half4(c_p.rgb, 1.0) * (1.2 / (l_v_bg * sc * 2.0));
  217. return half4(acc.rgb / acc.a, c_p.a);
  218. }
  219. // -----------------------------------------------------------------------------
  220. // Frame blending
  221. VaryingsDefault VertFrameCompress(AttributesDefault v)
  222. {
  223. VaryingsDefault o;
  224. o.pos = v.vertex;
  225. o.uvSPR = 0;
  226. #if UNITY_UV_STARTS_AT_TOP
  227. o.uv = v.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
  228. #else
  229. o.uv = v.texcoord;
  230. #endif
  231. return o;
  232. }
  233. #if !SHADER_API_GLES
  234. // MRT output struct for the compressor
  235. struct CompressorOutput
  236. {
  237. half4 luma : SV_Target0;
  238. half4 chroma : SV_Target1;
  239. };
  240. // Frame compression fragment shader
  241. CompressorOutput FragFrameCompress(VaryingsDefault i)
  242. {
  243. float sw = _ScreenParams.x; // Screen width
  244. float pw = _ScreenParams.z - 1; // Pixel width
  245. // RGB to YCbCr convertion matrix
  246. const half3 kY = half3( 0.299 , 0.587 , 0.114 );
  247. const half3 kCB = half3(-0.168736, -0.331264, 0.5 );
  248. const half3 kCR = half3( 0.5 , -0.418688, -0.081312);
  249. // 0: even column, 1: odd column
  250. half odd = frac(i.uv.x * sw * 0.5) > 0.5;
  251. // Calculate UV for chroma componetns.
  252. // It's between the even and odd columns.
  253. float2 uv_c = i.uv.xy;
  254. uv_c.x = (floor(uv_c.x * sw * 0.5) * 2.0 + 1.0) * pw;
  255. // Sample the source texture.
  256. half3 rgb_y = tex2D(_MainTex, i.uv).rgb;
  257. half3 rgb_c = tex2D(_MainTex, uv_c).rgb;
  258. #if !UNITY_COLORSPACE_GAMMA
  259. rgb_y = LinearToGammaSpace(rgb_y);
  260. rgb_c = LinearToGammaSpace(rgb_c);
  261. #endif
  262. // Convertion and subsampling
  263. CompressorOutput o;
  264. o.luma = dot(kY, rgb_y);
  265. o.chroma = dot(lerp(kCB, kCR, odd), rgb_c) + 0.5;
  266. return o;
  267. }
  268. #else
  269. // MRT might not be supported. Replace it with a null shader.
  270. half4 FragFrameCompress(VaryingsDefault i) : SV_Target
  271. {
  272. return 0;
  273. }
  274. #endif
  275. // Sample luma-chroma textures and convert to RGB
  276. half3 DecodeHistory(float2 uvLuma, float2 uvCb, float2 uvCr, sampler2D lumaTex, sampler2D chromaTex)
  277. {
  278. half y = tex2D(lumaTex, uvLuma).r;
  279. half cb = tex2D(chromaTex, uvCb).r - 0.5;
  280. half cr = tex2D(chromaTex, uvCr).r - 0.5;
  281. return y + half3(1.402 * cr, -0.34414 * cb - 0.71414 * cr, 1.772 * cb);
  282. }
  283. // Frame blending fragment shader
  284. half4 FragFrameBlending(VaryingsMultitex i) : SV_Target
  285. {
  286. float sw = _MainTex_TexelSize.z; // Texture width
  287. float pw = _MainTex_TexelSize.x; // Texel width
  288. // UV for luma
  289. float2 uvLuma = i.uv1;
  290. // UV for Cb (even columns)
  291. float2 uvCb = i.uv1;
  292. uvCb.x = (floor(uvCb.x * sw * 0.5) * 2.0 + 0.5) * pw;
  293. // UV for Cr (even columns)
  294. float2 uvCr = uvCb;
  295. uvCr.x += pw;
  296. // Sample from the source image
  297. half4 src = tex2D(_MainTex, i.uv0);
  298. // Sampling and blending
  299. #if UNITY_COLORSPACE_GAMMA
  300. half3 acc = src.rgb;
  301. #else
  302. half3 acc = LinearToGammaSpace(src.rgb);
  303. #endif
  304. acc += DecodeHistory(uvLuma, uvCb, uvCr, _History1LumaTex, _History1ChromaTex) * _History1Weight;
  305. acc += DecodeHistory(uvLuma, uvCb, uvCr, _History2LumaTex, _History2ChromaTex) * _History2Weight;
  306. acc += DecodeHistory(uvLuma, uvCb, uvCr, _History3LumaTex, _History3ChromaTex) * _History3Weight;
  307. acc += DecodeHistory(uvLuma, uvCb, uvCr, _History4LumaTex, _History4ChromaTex) * _History4Weight;
  308. acc /= 1.0 + _History1Weight + _History2Weight +_History3Weight +_History4Weight;
  309. #if !UNITY_COLORSPACE_GAMMA
  310. acc = GammaToLinearSpace(acc);
  311. #endif
  312. return half4(acc, src.a);
  313. }
  314. // Frame blending fragment shader (without chroma subsampling)
  315. half4 FragFrameBlendingRaw(VaryingsMultitex i) : SV_Target
  316. {
  317. half4 src = tex2D(_MainTex, i.uv0);
  318. half3 acc = src.rgb;
  319. acc += tex2D(_History1LumaTex, i.uv0) * _History1Weight;
  320. acc += tex2D(_History2LumaTex, i.uv0) * _History2Weight;
  321. acc += tex2D(_History3LumaTex, i.uv0) * _History3Weight;
  322. acc += tex2D(_History4LumaTex, i.uv0) * _History4Weight;
  323. acc /= 1.0 + _History1Weight + _History2Weight +_History3Weight +_History4Weight;
  324. return half4(acc, src.a);
  325. }
  326. #endif // __MOTION_BLUR__