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.

422 lines
11 KiB

5 years ago
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2. // Copyright (c) <2015> <Playdead>
  3. // This file is subject to the MIT License as seen in the root of this folder structure (LICENSE.TXT)
  4. // AUTHOR: Lasse Jon Fuglsang Pedersen <lasse@playdead.com>
  5. Shader "Hidden/TAA"
  6. {
  7. Properties
  8. {
  9. _MainTex ("Base (RGB)", 2D) = "white" {}
  10. }
  11. CGINCLUDE
  12. //--- program begin
  13. #pragma only_renderers ps4 xboxone d3d11 d3d9 xbox360 opengl glcore gles3 metal vulkan
  14. #pragma target 3.0
  15. #pragma multi_compile CAMERA_PERSPECTIVE CAMERA_ORTHOGRAPHIC
  16. #pragma multi_compile MINMAX_3X3 MINMAX_3X3_ROUNDED MINMAX_4TAP_VARYING
  17. #pragma multi_compile __ UNJITTER_COLORSAMPLES
  18. #pragma multi_compile __ UNJITTER_NEIGHBORHOOD
  19. #pragma multi_compile __ UNJITTER_REPROJECTION
  20. #pragma multi_compile __ USE_YCOCG
  21. #pragma multi_compile __ USE_CLIPPING
  22. #pragma multi_compile __ USE_DILATION
  23. #pragma multi_compile __ USE_MOTION_BLUR
  24. #pragma multi_compile __ USE_MOTION_BLUR_NEIGHBORMAX
  25. #pragma multi_compile __ USE_OPTIMIZATIONS
  26. #include "UnityCG.cginc"
  27. #include "IncDepth.cginc"
  28. #include "IncNoise.cginc"
  29. #if SHADER_API_MOBILE
  30. static const float FLT_EPS = 0.0001f;
  31. #else
  32. static const float FLT_EPS = 0.00000001f;
  33. #endif
  34. uniform float4 _JitterUV;// frustum jitter uv deltas, where xy = current frame, zw = previous
  35. uniform sampler2D _MainTex;
  36. uniform float4 _MainTex_TexelSize;
  37. uniform sampler2D_half _VelocityBuffer;
  38. uniform sampler2D _VelocityNeighborMax;
  39. uniform sampler2D _PrevTex;
  40. uniform float _FeedbackMin;
  41. uniform float _FeedbackMax;
  42. uniform float _MotionScale;
  43. struct v2f
  44. {
  45. float4 cs_pos : SV_POSITION;
  46. float2 ss_txc : TEXCOORD0;
  47. };
  48. v2f vert(appdata_img IN)
  49. {
  50. v2f OUT;
  51. #if UNITY_VERSION < 540
  52. OUT.cs_pos = UnityObjectToClipPos(IN.vertex);
  53. #else
  54. OUT.cs_pos = UnityObjectToClipPos(IN.vertex);
  55. #endif
  56. #if UNITY_SINGLE_PASS_STEREO
  57. OUT.ss_txc = UnityStereoTransformScreenSpaceTex(IN.texcoord.xy);
  58. #else
  59. OUT.ss_txc = IN.texcoord.xy;
  60. #endif
  61. return OUT;
  62. }
  63. // https://software.intel.com/en-us/node/503873
  64. float3 RGB_YCoCg(float3 c)
  65. {
  66. // Y = R/4 + G/2 + B/4
  67. // Co = R/2 - B/2
  68. // Cg = -R/4 + G/2 - B/4
  69. return float3(
  70. c.x/4.0 + c.y/2.0 + c.z/4.0,
  71. c.x/2.0 - c.z/2.0,
  72. -c.x/4.0 + c.y/2.0 - c.z/4.0
  73. );
  74. }
  75. // https://software.intel.com/en-us/node/503873
  76. float3 YCoCg_RGB(float3 c)
  77. {
  78. // R = Y + Co - Cg
  79. // G = Y + Cg
  80. // B = Y - Co - Cg
  81. return saturate(float3(
  82. c.x + c.y - c.z,
  83. c.x + c.z,
  84. c.x - c.y - c.z
  85. ));
  86. }
  87. float4 sample_color(sampler2D tex, float2 uv)
  88. {
  89. #if USE_YCOCG
  90. float4 c = tex2D(tex, uv);
  91. return float4(RGB_YCoCg(c.rgb), c.a);
  92. #else
  93. return tex2D(tex, uv);
  94. #endif
  95. }
  96. float4 resolve_color(float4 c)
  97. {
  98. #if USE_YCOCG
  99. return float4(YCoCg_RGB(c.rgb).rgb, c.a);
  100. #else
  101. return c;
  102. #endif
  103. }
  104. float4 clip_aabb(float3 aabb_min, float3 aabb_max, float4 p, float4 q)
  105. {
  106. #if USE_OPTIMIZATIONS
  107. // note: only clips towards aabb center (but fast!)
  108. float3 p_clip = 0.5 * (aabb_max + aabb_min);
  109. float3 e_clip = 0.5 * (aabb_max - aabb_min) + FLT_EPS;
  110. float4 v_clip = q - float4(p_clip, p.w);
  111. float3 v_unit = v_clip.xyz / e_clip;
  112. float3 a_unit = abs(v_unit);
  113. float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z));
  114. if (ma_unit > 1.0)
  115. return float4(p_clip, p.w) + v_clip / ma_unit;
  116. else
  117. return q;// point inside aabb
  118. #else
  119. float4 r = q - p;
  120. float3 rmax = aabb_max - p.xyz;
  121. float3 rmin = aabb_min - p.xyz;
  122. const float eps = FLT_EPS;
  123. if (r.x > rmax.x + eps)
  124. r *= (rmax.x / r.x);
  125. if (r.y > rmax.y + eps)
  126. r *= (rmax.y / r.y);
  127. if (r.z > rmax.z + eps)
  128. r *= (rmax.z / r.z);
  129. if (r.x < rmin.x - eps)
  130. r *= (rmin.x / r.x);
  131. if (r.y < rmin.y - eps)
  132. r *= (rmin.y / r.y);
  133. if (r.z < rmin.z - eps)
  134. r *= (rmin.z / r.z);
  135. return p + r;
  136. #endif
  137. }
  138. float2 sample_velocity_dilated(sampler2D tex, float2 uv, int support)
  139. {
  140. float2 du = float2(_MainTex_TexelSize.x, 0.0);
  141. float2 dv = float2(0.0, _MainTex_TexelSize.y);
  142. float2 mv = 0.0;
  143. float rmv = 0.0;
  144. int end = support + 1;
  145. for (int i = -support; i != end; i++)
  146. {
  147. for (int j = -support; j != end; j++)
  148. {
  149. float2 v = tex2D(tex, uv + i * dv + j * du).xy;
  150. float rv = dot(v, v);
  151. if (rv > rmv)
  152. {
  153. mv = v;
  154. rmv = rv;
  155. }
  156. }
  157. }
  158. return mv;
  159. }
  160. float4 sample_color_motion(sampler2D tex, float2 uv, float2 ss_vel)
  161. {
  162. const float2 v = 0.5 * ss_vel;
  163. const int taps = 3;// on either side!
  164. float srand = PDsrand(uv + _SinTime.xx);
  165. float2 vtap = v / taps;
  166. float2 pos0 = uv + vtap * (0.5 * srand);
  167. float4 accu = 0.0;
  168. float wsum = 0.0;
  169. [unroll]
  170. for (int i = -taps; i <= taps; i++)
  171. {
  172. float w = 1.0;// box
  173. //float w = taps - abs(i) + 1;// triangle
  174. //float w = 1.0 / (1 + abs(i));// pointy triangle
  175. accu += w * sample_color(tex, pos0 + i * vtap);
  176. wsum += w;
  177. }
  178. return accu / wsum;
  179. }
  180. float4 temporal_reprojection(float2 ss_txc, float2 ss_vel, float vs_dist)
  181. {
  182. // read texels
  183. #if UNJITTER_COLORSAMPLES
  184. float4 texel0 = sample_color(_MainTex, ss_txc - _JitterUV.xy);
  185. #else
  186. float4 texel0 = sample_color(_MainTex, ss_txc);
  187. #endif
  188. float4 texel1 = sample_color(_PrevTex, ss_txc - ss_vel);
  189. // calc min-max of current neighbourhood
  190. #if UNJITTER_NEIGHBORHOOD
  191. float2 uv = ss_txc - _JitterUV.xy;
  192. #else
  193. float2 uv = ss_txc;
  194. #endif
  195. #if MINMAX_3X3 || MINMAX_3X3_ROUNDED
  196. float2 du = float2(_MainTex_TexelSize.x, 0.0);
  197. float2 dv = float2(0.0, _MainTex_TexelSize.y);
  198. float4 ctl = sample_color(_MainTex, uv - dv - du);
  199. float4 ctc = sample_color(_MainTex, uv - dv);
  200. float4 ctr = sample_color(_MainTex, uv - dv + du);
  201. float4 cml = sample_color(_MainTex, uv - du);
  202. float4 cmc = sample_color(_MainTex, uv);
  203. float4 cmr = sample_color(_MainTex, uv + du);
  204. float4 cbl = sample_color(_MainTex, uv + dv - du);
  205. float4 cbc = sample_color(_MainTex, uv + dv);
  206. float4 cbr = sample_color(_MainTex, uv + dv + du);
  207. float4 cmin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr))))))));
  208. float4 cmax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr))))))));
  209. #if MINMAX_3X3_ROUNDED || USE_YCOCG || USE_CLIPPING
  210. float4 cavg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0;
  211. #endif
  212. #if MINMAX_3X3_ROUNDED
  213. float4 cmin5 = min(ctc, min(cml, min(cmc, min(cmr, cbc))));
  214. float4 cmax5 = max(ctc, max(cml, max(cmc, max(cmr, cbc))));
  215. float4 cavg5 = (ctc + cml + cmc + cmr + cbc) / 5.0;
  216. cmin = 0.5 * (cmin + cmin5);
  217. cmax = 0.5 * (cmax + cmax5);
  218. cavg = 0.5 * (cavg + cavg5);
  219. #endif
  220. #elif MINMAX_4TAP_VARYING// this is the method used in v2 (PDTemporalReprojection2)
  221. const float _SubpixelThreshold = 0.5;
  222. const float _GatherBase = 0.5;
  223. const float _GatherSubpixelMotion = 0.1666;
  224. float2 texel_vel = ss_vel / _MainTex_TexelSize.xy;
  225. float texel_vel_mag = length(texel_vel) * vs_dist;
  226. float k_subpixel_motion = saturate(_SubpixelThreshold / (FLT_EPS + texel_vel_mag));
  227. float k_min_max_support = _GatherBase + _GatherSubpixelMotion * k_subpixel_motion;
  228. float2 ss_offset01 = k_min_max_support * float2(-_MainTex_TexelSize.x, _MainTex_TexelSize.y);
  229. float2 ss_offset11 = k_min_max_support * float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y);
  230. float4 c00 = sample_color(_MainTex, uv - ss_offset11);
  231. float4 c10 = sample_color(_MainTex, uv - ss_offset01);
  232. float4 c01 = sample_color(_MainTex, uv + ss_offset01);
  233. float4 c11 = sample_color(_MainTex, uv + ss_offset11);
  234. float4 cmin = min(c00, min(c10, min(c01, c11)));
  235. float4 cmax = max(c00, max(c10, max(c01, c11)));
  236. #if USE_YCOCG || USE_CLIPPING
  237. float4 cavg = (c00 + c10 + c01 + c11) / 4.0;
  238. #endif
  239. #else
  240. #error "missing keyword MINMAX_..."
  241. #endif
  242. // shrink chroma min-max
  243. #if USE_YCOCG
  244. float2 chroma_extent = 0.25 * 0.5 * (cmax.r - cmin.r);
  245. float2 chroma_center = texel0.gb;
  246. cmin.yz = chroma_center - chroma_extent;
  247. cmax.yz = chroma_center + chroma_extent;
  248. cavg.yz = chroma_center;
  249. #endif
  250. // clamp to neighbourhood of current sample
  251. #if USE_CLIPPING
  252. texel1 = clip_aabb(cmin.xyz, cmax.xyz, clamp(cavg, cmin, cmax), texel1);
  253. #else
  254. texel1 = clamp(texel1, cmin, cmax);
  255. #endif
  256. // feedback weight from unbiased luminance diff (t.lottes)
  257. #if USE_YCOCG
  258. float lum0 = texel0.r;
  259. float lum1 = texel1.r;
  260. #else
  261. float lum0 = Luminance(texel0.rgb);
  262. float lum1 = Luminance(texel1.rgb);
  263. #endif
  264. float unbiased_diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2));
  265. float unbiased_weight = 1.0 - unbiased_diff;
  266. float unbiased_weight_sqr = unbiased_weight * unbiased_weight;
  267. float k_feedback = lerp(_FeedbackMin, _FeedbackMax, unbiased_weight_sqr);
  268. // output
  269. return lerp(texel0, texel1, k_feedback);
  270. }
  271. struct f2rt
  272. {
  273. fixed4 buffer : SV_Target0;
  274. fixed4 screen : SV_Target1;
  275. };
  276. f2rt frag(v2f IN)
  277. {
  278. f2rt OUT;
  279. #if UNJITTER_REPROJECTION
  280. float2 uv = IN.ss_txc - _JitterUV.xy;
  281. #else
  282. float2 uv = IN.ss_txc;
  283. #endif
  284. #if USE_DILATION
  285. //--- 3x3 norm (sucks)
  286. //float2 ss_vel = sample_velocity_dilated(_VelocityBuffer, uv, 1);
  287. //float vs_dist = depth_sample_linear(uv);
  288. //--- 5 tap nearest (decent)
  289. //float3 c_frag = find_closest_fragment_5tap(uv);
  290. //float2 ss_vel = tex2D(_VelocityBuffer, c_frag.xy).xy;
  291. //float vs_dist = depth_resolve_linear(c_frag.z);
  292. //--- 3x3 nearest (good)
  293. float3 c_frag = find_closest_fragment_3x3(uv);
  294. float2 ss_vel = tex2D(_VelocityBuffer, c_frag.xy).xy;
  295. float vs_dist = depth_resolve_linear(c_frag.z);
  296. #else
  297. float2 ss_vel = tex2D(_VelocityBuffer, uv).xy;
  298. float vs_dist = depth_sample_linear(uv);
  299. #endif
  300. // temporal resolve
  301. float4 color_temporal = temporal_reprojection(IN.ss_txc, ss_vel, vs_dist);
  302. // prepare outputs
  303. float4 to_buffer = resolve_color(color_temporal);
  304. #if USE_MOTION_BLUR
  305. #if USE_MOTION_BLUR_NEIGHBORMAX
  306. ss_vel = _MotionScale * tex2D(_VelocityNeighborMax, IN.ss_txc).xy;
  307. #else
  308. ss_vel = _MotionScale * ss_vel;
  309. #endif
  310. float vel_mag = length(ss_vel * _MainTex_TexelSize.zw);
  311. const float vel_trust_full = 2.0;
  312. const float vel_trust_none = 15.0;
  313. const float vel_trust_span = vel_trust_none - vel_trust_full;
  314. float trust = 1.0 - clamp(vel_mag - vel_trust_full, 0.0, vel_trust_span) / vel_trust_span;
  315. #if UNJITTER_COLORSAMPLES
  316. float4 color_motion = sample_color_motion(_MainTex, IN.ss_txc - _JitterUV.xy, ss_vel);
  317. #else
  318. float4 color_motion = sample_color_motion(_MainTex, IN.ss_txc, ss_vel);
  319. #endif
  320. float4 to_screen = resolve_color(lerp(color_motion, color_temporal, trust));
  321. #else
  322. float4 to_screen = resolve_color(color_temporal);
  323. #endif
  324. //// NOTE: velocity debug
  325. //to_screen.g += 100.0 * length(ss_vel);
  326. //to_screen = float4(100.0 * abs(ss_vel), 0.0, 0.0);
  327. // add noise
  328. float4 noise4 = PDsrand4(IN.ss_txc + _SinTime.x + 0.6959174) / 510.0;
  329. OUT.buffer = saturate(to_buffer /*+ noise4*/);
  330. //OUT.screen = saturate(to_screen + noise4);
  331. OUT.screen = saturate(to_screen /*+ noise4*/)/* * float4(1,.2,0,1)*/;
  332. //OUT.screen = float4(vs_dist, vs_dist, vs_dist,1);
  333. // done
  334. return OUT;
  335. }
  336. //--- program end
  337. ENDCG
  338. SubShader
  339. {
  340. ZTest Always Cull Off ZWrite Off
  341. Fog { Mode off }
  342. Pass
  343. {
  344. CGPROGRAM
  345. #pragma vertex vert
  346. #pragma fragment frag
  347. ENDCG
  348. }
  349. }
  350. Fallback off
  351. }