暫無描述
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.

TemporalAA.hlsl 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #ifndef UNIVERSAL_TEMPORAL_AA
  2. #define UNIVERSAL_TEMPORAL_AA
  3. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
  4. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  5. #include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
  6. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
  7. #ifndef TAA_YCOCG
  8. #define TAA_YCOCG 1
  9. #endif
  10. #ifndef TAA_GAMMA_SPACE_POST
  11. #if UNITY_NO_LINEAR_COLORSPACE
  12. #define TAA_GAMMA_SPACE_POST 1
  13. else
  14. #define TAA_GAMMA_SPACE_POST 0
  15. #endif
  16. #endif
  17. #ifndef TAA_PERCEPTUAL_SPACE
  18. #define TAA_PERCEPTUAL_SPACE 1
  19. #endif
  20. TEXTURE2D_X(_TaaMotionVectorTex);
  21. TEXTURE2D_X(_TaaAccumulationTex);
  22. CBUFFER_START(TemporalAAData)
  23. float4 _TaaMotionVectorTex_TexelSize; // (1/w, 1/h, w, h)
  24. float4 _TaaAccumulationTex_TexelSize; // (1/w, 1/h, w, h)
  25. float _TaaFilterWeights[9];
  26. half _TaaFrameInfluence;
  27. half _TaaVarianceClampScale;
  28. CBUFFER_END
  29. // Per-pixel camera backwards velocity
  30. half2 GetVelocityWithOffset(float2 uv, half2 depthOffsetUv)
  31. {
  32. // Unity motion vectors are forward motion vectors in screen UV space
  33. half2 offsetUv = SAMPLE_TEXTURE2D_X(_TaaMotionVectorTex, sampler_LinearClamp, uv + _TaaMotionVectorTex_TexelSize.xy * depthOffsetUv).xy;
  34. return -offsetUv;
  35. }
  36. void AdjustBestDepthOffset(inout half bestDepth, inout half bestX, inout half bestY, float2 uv, half currX, half currY)
  37. {
  38. // Half precision should be fine, as we are only concerned about choosing the better value along sharp edges, so it's
  39. // acceptable to have banding on continuous surfaces
  40. half depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_PointClamp, uv.xy + _BlitTexture_TexelSize.xy * half2(currX, currY)).r;
  41. #if UNITY_REVERSED_Z
  42. depth = 1.0 - depth;
  43. #endif
  44. bool isBest = depth < bestDepth;
  45. bestDepth = isBest ? depth : bestDepth;
  46. bestX = isBest ? currX : bestX;
  47. bestY = isBest ? currY : bestY;
  48. }
  49. float GetLuma(float3 color)
  50. {
  51. #if TAA_YCOCG
  52. // We work in YCoCg hence the luminance is in the first channel.
  53. return color.x;
  54. #else
  55. return Luminance(color.xyz);
  56. #endif
  57. }
  58. float PerceptualWeight(float3 c)
  59. {
  60. #if TAA_PERCEPTUAL_SPACE
  61. return rcp(GetLuma(c) + 1.0);
  62. #else
  63. return 1;
  64. #endif
  65. }
  66. float PerceptualInvWeight(float3 c)
  67. {
  68. #if TAA_PERCEPTUAL_SPACE
  69. return rcp(1.0 - GetLuma(c));
  70. #else
  71. return 1;
  72. #endif
  73. }
  74. float4 WorkingToPerceptual(float4 c)
  75. {
  76. float scale = PerceptualWeight(c.xyz);
  77. return c * scale;
  78. }
  79. float4 PerceptualToWorking(float4 c)
  80. {
  81. float scale = PerceptualInvWeight(c.xyz);
  82. return c * scale;
  83. }
  84. half4 PostFxSpaceToLinear(float4 src)
  85. {
  86. // gamma 2.0 is a good enough approximation
  87. #if TAA_GAMMA_SPACE_POST
  88. return half4(src.xyz * src.xyz, src.w);
  89. #else
  90. return src;
  91. #endif
  92. }
  93. half4 LinearToPostFxSpace(float4 src)
  94. {
  95. #if TAA_GAMMA_SPACE_POST
  96. return half4(sqrt(src.xyz), src.w);
  97. #else
  98. return src;
  99. #endif
  100. }
  101. // Working Space: The color space that we will do the calculation in.
  102. // Scene: The incoming/outgoing scene color. Either linear or gamma space
  103. half4 SceneToWorkingSpace(half4 src)
  104. {
  105. half4 linColor = PostFxSpaceToLinear(src);
  106. #if TAA_YCOCG
  107. half4 dst = half4(RGBToYCoCg(linColor.xyz), linColor.w);
  108. #else
  109. half4 dst = src;
  110. #endif
  111. return dst;
  112. }
  113. half4 WorkingSpaceToScene(half4 src)
  114. {
  115. #if TAA_YCOCG
  116. half4 linColor = half4(YCoCgToRGB(src.xyz), src.w);
  117. #else
  118. half4 linColor = src;
  119. #endif
  120. half4 dst = LinearToPostFxSpace(linColor);
  121. return dst;
  122. }
  123. half4 SampleColorPoint(float2 uv, float2 texelOffset)
  124. {
  125. return SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, uv + _BlitTexture_TexelSize.xy * texelOffset);
  126. }
  127. half4 SampleColorLinear(float2 uv, float2 texelOffset)
  128. {
  129. return SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv + _BlitTexture_TexelSize.xy * texelOffset);
  130. }
  131. void AdjustColorBox(inout half4 boxMin, inout half4 boxMax, inout half4 moment1, inout half4 moment2, float2 uv, half currX, half currY)
  132. {
  133. half4 color = SceneToWorkingSpace(SampleColorPoint(uv, float2(currX, currY)));
  134. boxMin = min(color, boxMin);
  135. boxMax = max(color, boxMax);
  136. moment1 += color;
  137. moment2 += color * color;
  138. }
  139. half4 ApplyHistoryColorLerp(half4 workingAccumColor, half4 workingCenterColor, float t)
  140. {
  141. half4 perceptualAccumColor = WorkingToPerceptual(workingAccumColor);
  142. half4 perceptualCenterColor = WorkingToPerceptual(workingCenterColor);
  143. half4 perceptualDstColor = lerp(perceptualAccumColor, perceptualCenterColor, t);
  144. half4 workingDstColor = PerceptualToWorking(perceptualDstColor);
  145. return workingDstColor;
  146. }
  147. // From Filmic SMAA presentation[Jimenez 2016]
  148. // A bit more verbose that it needs to be, but makes it a bit better at latency hiding
  149. // (half version based on HDRP impl)
  150. half4 SampleBicubic5TapHalf(TEXTURE2D_X(sourceTexture), float2 UV, float4 sourceTexture_TexelSize)
  151. {
  152. const float2 sourceTextureSize = sourceTexture_TexelSize.zw;
  153. const float2 sourceTexelSize = sourceTexture_TexelSize.xy;
  154. float2 samplePos = UV * sourceTextureSize;
  155. float2 tc1 = floor(samplePos - 0.5) + 0.5;
  156. half2 f = samplePos - tc1;
  157. half2 f2 = f * f;
  158. half2 f3 = f * f2;
  159. half c = 0.5;
  160. half2 w0 = -c * f3 + 2.0 * c * f2 - c * f;
  161. half2 w1 = (2.0 - c) * f3 - (3.0 - c) * f2 + 1.0;
  162. half2 w2 = -(2.0 - c) * f3 + (3.0 - 2.0 * c) * f2 + c * f;
  163. half2 w3 = c * f3 - c * f2;
  164. half2 w12 = w1 + w2;
  165. float2 tc0 = sourceTexelSize * (tc1 - 1.0);
  166. float2 tc3 = sourceTexelSize * (tc1 + 2.0);
  167. float2 tc12 = sourceTexelSize * (tc1 + w2 / w12);
  168. half4 s0 = SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(sourceTexture, sampler_LinearClamp, float2(tc12.x, tc0.y)));
  169. half4 s1 = SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(sourceTexture, sampler_LinearClamp, float2(tc0.x, tc12.y)));
  170. half4 s2 = SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(sourceTexture, sampler_LinearClamp, float2(tc12.x, tc12.y)));
  171. half4 s3 = SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(sourceTexture, sampler_LinearClamp, float2(tc3.x, tc12.y)));
  172. half4 s4 = SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(sourceTexture, sampler_LinearClamp, float2(tc12.x, tc3.y)));
  173. half cw0 = (w12.x * w0.y);
  174. half cw1 = (w0.x * w12.y);
  175. half cw2 = (w12.x * w12.y);
  176. half cw3 = (w3.x * w12.y);
  177. half cw4 = (w12.x * w3.y);
  178. s0 *= cw0;
  179. s1 *= cw1;
  180. s2 *= cw2;
  181. s3 *= cw3;
  182. s4 *= cw4;
  183. half4 historyFiltered = s0 + s1 + s2 + s3 + s4;
  184. half weightSum = cw0 + cw1 + cw2 + cw3 + cw4;
  185. half4 filteredVal = historyFiltered * rcp(weightSum);
  186. return filteredVal;
  187. }
  188. // From Playdead's TAA
  189. // (half version of HDRP impl)
  190. //
  191. // Small color-volume min size seems to produce flicker/noise in YCoCg space, that can't be seen in RGB,
  192. // when using low precision (RGB111110f) color textures.
  193. half4 ClipToAABBCenter(half4 history, half4 minimum, half4 maximum)
  194. {
  195. // note: only clips towards aabb center (but fast!)
  196. half4 center = 0.5 * (maximum + minimum);
  197. half4 extents = max(0.5 * (maximum - minimum), HALF_MIN); // Epsilon to avoid precision issues with empty volume.
  198. // This is actually `distance`, however the keyword is reserved
  199. half4 offset = history - center;
  200. half3 v_unit = offset.xyz / extents.xyz;
  201. half3 absUnit = abs(v_unit);
  202. half maxUnit = Max3(absUnit.x, absUnit.y, absUnit.z);
  203. if (maxUnit > 1.0)
  204. return center + (offset / maxUnit);
  205. else
  206. return history;
  207. }
  208. // Based on HDRP
  209. half4 FilterColor(float2 uv, float weights[9])
  210. {
  211. half4 filtered = weights[0] * PostFxSpaceToLinear(SampleColorPoint(uv, float2(0.0, 0.0f)));
  212. filtered += weights[1] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(0.0f, 1.0)));
  213. filtered += weights[2] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(1.0f, 0.0f)));
  214. filtered += weights[3] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(-1.0f, 0.0f)));
  215. filtered += weights[4] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(0.0f, -1.0f)));
  216. filtered += weights[5] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(-1.0f, 1.0f)));
  217. filtered += weights[6] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(1.0f, -1.0f)));
  218. filtered += weights[7] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(1.0f, 1.0f)));
  219. filtered += weights[8] * PostFxSpaceToLinear(SampleColorPoint(uv,float2(-1.0f, -1.0f)));
  220. #if TAA_YCOCG
  221. return half4(RGBToYCoCg(filtered.xyz), filtered.w);
  222. #else
  223. return filtered;
  224. #endif
  225. }
  226. // clampQuality:
  227. // 0: Cross (5 taps)
  228. // 1: 3x3 (9 taps)
  229. // 2: Variance + MinMax 3x3 (9 taps)
  230. // 3: Variance Clipping
  231. //
  232. // motionQuality:
  233. // 0: None
  234. // 1: 5 taps
  235. // 2: 9 taps
  236. // historyQuality:
  237. // 0: Bilinear
  238. // 1: Bilinear + discard history for UVs out of buffer
  239. // 2: Bicubic (5 taps)
  240. half4 DoTemporalAA(Varyings input, int clampQuality, int motionQuality, int historyQuality, int centralFiltering)
  241. {
  242. UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
  243. // uv is exactly on input pixel center (x + 0.5, y + 0.5)
  244. float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord);
  245. half4 colorCenter;
  246. if(centralFiltering >= 1)
  247. colorCenter = FilterColor(uv, _TaaFilterWeights);
  248. else
  249. colorCenter = SceneToWorkingSpace(SampleColorPoint( uv, float2(0,0))); // Point == Linear as uv == input pixel center.
  250. half4 boxMax = colorCenter;
  251. half4 boxMin = colorCenter;
  252. half4 moment1 = colorCenter;
  253. half4 moment2 = colorCenter * colorCenter;
  254. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, 0.0f, -1.0f);
  255. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, -1.0f, 0.0f);
  256. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, 1.0f, 0.0f);
  257. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, 0.0f, 1.0f);
  258. if (clampQuality >= 1)
  259. {
  260. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, -1.0f, -1.0f);
  261. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, 1.0f, -1.0f);
  262. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, -1.0f, 1.0f);
  263. AdjustColorBox(boxMin, boxMax, moment1, moment2, uv, 1.0f, 1.0f);
  264. }
  265. if(clampQuality >= 2)
  266. {
  267. half perSample = 1 / half(9);
  268. half4 mean = moment1 * perSample;
  269. half4 stdDev = sqrt(abs(moment2 * perSample - mean * mean));
  270. half devScale = _TaaVarianceClampScale;
  271. half4 devMin = mean - devScale * stdDev;
  272. half4 devMax = mean + devScale * stdDev;
  273. // Ensure that the variance color box is not worse than simple neighborhood color box.
  274. boxMin = max(boxMin, devMin);
  275. boxMax = min(boxMax, devMax);
  276. }
  277. half bestOffsetX = 0.0f;
  278. half bestOffsetY = 0.0f;
  279. half bestDepth = 1.0f;
  280. if (motionQuality >= 1)
  281. {
  282. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, 0.0f);
  283. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, 0.0f);
  284. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, -1.0f);
  285. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, 0.0f);
  286. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 0.0f, 1.0f);
  287. }
  288. if (motionQuality >= 2)
  289. {
  290. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, -1.0f);
  291. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, -1.0f);
  292. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, -1.0f, 1.0f);
  293. AdjustBestDepthOffset(bestDepth, bestOffsetX, bestOffsetY, uv, 1.0f, 1.0f);
  294. }
  295. half2 depthOffsetUv = half2(bestOffsetX, bestOffsetY);
  296. half2 velocity = GetVelocityWithOffset(uv, depthOffsetUv);
  297. float2 historyUv = uv + velocity * float2(1, 1);
  298. half4 accumulation = (historyQuality >= 2) ?
  299. SampleBicubic5TapHalf(_TaaAccumulationTex, historyUv, _TaaAccumulationTex_TexelSize.xyzw) :
  300. SceneToWorkingSpace(SAMPLE_TEXTURE2D_X(_TaaAccumulationTex, sampler_LinearClamp, historyUv));
  301. half4 clampedAccumulation = (clampQuality >= 3) ? ClipToAABBCenter(accumulation, boxMin, boxMax) : clamp(accumulation, boxMin, boxMax);
  302. // Discard (some) history when outside of history buffer (e.g. camera jump)
  303. half frameInfluence = ((historyQuality >= 1) && any(abs(uv - 0.5 + velocity) > 0.5)) ? 1 : _TaaFrameInfluence;
  304. half4 workingColor = ApplyHistoryColorLerp(clampedAccumulation, colorCenter, frameInfluence);
  305. half4 dstSceneColor = WorkingSpaceToScene(workingColor);
  306. #if _ENABLE_ALPHA_OUTPUT
  307. return max(dstSceneColor, 0.0);
  308. #else
  309. // NOTE: The compiler should eliminate .w computation since it doesn't affect the output.
  310. return half4(max(dstSceneColor.xyz, 0.0), 1.0);
  311. #endif
  312. }
  313. half4 DoCopy(Varyings input)
  314. {
  315. UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
  316. float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord.xy);
  317. half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, uv);
  318. return color;
  319. }
  320. #endif