DepthOfField.hlsl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #ifndef UNITY_POSTFX_DEPTH_OF_FIELD
  2. #define UNITY_POSTFX_DEPTH_OF_FIELD
  3. #include "../StdLib.hlsl"
  4. #include "../Colors.hlsl"
  5. #include "DiskKernels.hlsl"
  6. TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
  7. float4 _MainTex_TexelSize;
  8. TEXTURE2D_SAMPLER2D(_CameraDepthTexture, sampler_CameraDepthTexture);
  9. TEXTURE2D_SAMPLER2D(_CameraMotionVectorsTexture, sampler_CameraMotionVectorsTexture);
  10. TEXTURE2D_SAMPLER2D(_CoCTex, sampler_CoCTex);
  11. TEXTURE2D_SAMPLER2D(_DepthOfFieldTex, sampler_DepthOfFieldTex);
  12. float4 _DepthOfFieldTex_TexelSize;
  13. // Camera parameters
  14. float _Distance;
  15. float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
  16. float _MaxCoC;
  17. float _RcpMaxCoC;
  18. float _RcpAspect;
  19. half3 _TaaParams; // Jitter.x, Jitter.y, Blending
  20. // CoC calculation
  21. half4 FragCoC(VaryingsDefault i) : SV_Target
  22. {
  23. float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo));
  24. half coc = (depth - _Distance) * _LensCoeff / max(depth, 1e-5);
  25. return saturate(coc * 0.5 * _RcpMaxCoC + 0.5);
  26. }
  27. // Temporal filter
  28. half4 FragTempFilter(VaryingsDefault i) : SV_Target
  29. {
  30. float3 uvOffs = _MainTex_TexelSize.xyy * float3(1.0, 1.0, 0.0);
  31. #if UNITY_GATHER_SUPPORTED
  32. half4 cocTL = GATHER_RED_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord - uvOffs.xy * 0.5)); // top-left
  33. half4 cocBR = GATHER_RED_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord + uvOffs.xy * 0.5)); // bottom-right
  34. half coc1 = cocTL.x; // top
  35. half coc2 = cocTL.z; // left
  36. half coc3 = cocBR.x; // bottom
  37. half coc4 = cocBR.z; // right
  38. #else
  39. half coc1 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord - uvOffs.xz)).r; // top
  40. half coc2 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord - uvOffs.zy)).r; // left
  41. half coc3 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord + uvOffs.zy)).r; // bottom
  42. half coc4 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord + uvOffs.xz)).r; // right
  43. #endif
  44. // Dejittered center sample.
  45. half coc0 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, UnityStereoTransformScreenSpaceTex(i.texcoord - _TaaParams.xy)).r;
  46. // CoC dilation: determine the closest point in the four neighbors
  47. float3 closest = float3(0.0, 0.0, coc0);
  48. closest = coc1 < closest.z ? float3(-uvOffs.xz, coc1) : closest;
  49. closest = coc2 < closest.z ? float3(-uvOffs.zy, coc2) : closest;
  50. closest = coc3 < closest.z ? float3( uvOffs.zy, coc3) : closest;
  51. closest = coc4 < closest.z ? float3( uvOffs.xz, coc4) : closest;
  52. // Sample the history buffer with the motion vector at the closest point
  53. float2 motion = SAMPLE_TEXTURE2D(_CameraMotionVectorsTexture, sampler_CameraMotionVectorsTexture, UnityStereoTransformScreenSpaceTex(i.texcoord + closest.xy)).xy;
  54. half cocHis = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - motion)).r;
  55. // Neighborhood clamping
  56. half cocMin = closest.z;
  57. half cocMax = Max3(Max3(coc0, coc1, coc2), coc3, coc4);
  58. cocHis = clamp(cocHis, cocMin, cocMax);
  59. // Blend with the history
  60. return lerp(coc0, cocHis, _TaaParams.z);
  61. }
  62. // Prefilter: downsampling and premultiplying
  63. half4 FragPrefilter(VaryingsDefault i) : SV_Target
  64. {
  65. #if UNITY_GATHER_SUPPORTED
  66. // Sample source colors
  67. half4 c_r = GATHER_RED_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
  68. half4 c_g = GATHER_GREEN_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
  69. half4 c_b = GATHER_BLUE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
  70. half3 c0 = half3(c_r.x, c_g.x, c_b.x);
  71. half3 c1 = half3(c_r.y, c_g.y, c_b.y);
  72. half3 c2 = half3(c_r.z, c_g.z, c_b.z);
  73. half3 c3 = half3(c_r.w, c_g.w, c_b.w);
  74. // Sample CoCs
  75. half4 cocs = GATHER_TEXTURE2D(_CoCTex, sampler_CoCTex, i.texcoordStereo) * 2.0 - 1.0;
  76. half coc0 = cocs.x;
  77. half coc1 = cocs.y;
  78. half coc2 = cocs.z;
  79. half coc3 = cocs.w;
  80. #else
  81. float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
  82. float2 uv0 = UnityStereoTransformScreenSpaceTex(i.texcoord - duv.xy);
  83. float2 uv1 = UnityStereoTransformScreenSpaceTex(i.texcoord - duv.zy);
  84. float2 uv2 = UnityStereoTransformScreenSpaceTex(i.texcoord + duv.zy);
  85. float2 uv3 = UnityStereoTransformScreenSpaceTex(i.texcoord + duv.xy);
  86. // Sample source colors
  87. half3 c0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv0).rgb;
  88. half3 c1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv1).rgb;
  89. half3 c2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv2).rgb;
  90. half3 c3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv3).rgb;
  91. // Sample CoCs
  92. half coc0 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, uv0).r * 2.0 - 1.0;
  93. half coc1 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, uv1).r * 2.0 - 1.0;
  94. half coc2 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, uv2).r * 2.0 - 1.0;
  95. half coc3 = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, uv3).r * 2.0 - 1.0;
  96. #endif
  97. // Apply CoC and luma weights to reduce bleeding and flickering
  98. float w0 = abs(coc0) / (Max3(c0.r, c0.g, c0.b) + 1.0);
  99. float w1 = abs(coc1) / (Max3(c1.r, c1.g, c1.b) + 1.0);
  100. float w2 = abs(coc2) / (Max3(c2.r, c2.g, c2.b) + 1.0);
  101. float w3 = abs(coc3) / (Max3(c3.r, c3.g, c3.b) + 1.0);
  102. // Weighted average of the color samples
  103. half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3;
  104. avg /= max(w0 + w1 + w2 + w3, 1e-5);
  105. // Select the largest CoC value
  106. half coc_min = min(coc0, Min3(coc1, coc2, coc3));
  107. half coc_max = max(coc0, Max3(coc1, coc2, coc3));
  108. half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC;
  109. // Premultiply CoC again
  110. avg *= smoothstep(0, _MainTex_TexelSize.y * 2, abs(coc));
  111. #if defined(UNITY_COLORSPACE_GAMMA)
  112. avg = SRGBToLinear(avg);
  113. #endif
  114. return half4(avg, coc);
  115. }
  116. // Bokeh filter with disk-shaped kernels
  117. half4 FragBlur(VaryingsDefault i) : SV_Target
  118. {
  119. half4 samp0 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
  120. half4 bgAcc = 0.0; // Background: far field bokeh
  121. half4 fgAcc = 0.0; // Foreground: near field bokeh
  122. UNITY_LOOP
  123. for (int si = 0; si < kSampleCount; si++)
  124. {
  125. float2 disp = kDiskKernel[si] * _MaxCoC;
  126. float dist = length(disp);
  127. float2 duv = float2(disp.x * _RcpAspect, disp.y);
  128. half4 samp = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + duv));
  129. // BG: Compare CoC of the current sample and the center sample
  130. // and select smaller one.
  131. half bgCoC = max(min(samp0.a, samp.a), 0.0);
  132. // Compare the CoC to the sample distance.
  133. // Add a small margin to smooth out.
  134. const half margin = _MainTex_TexelSize.y * 2;
  135. half bgWeight = saturate((bgCoC - dist + margin) / margin);
  136. half fgWeight = saturate((-samp.a - dist + margin) / margin);
  137. // Cut influence from focused areas because they're darkened by CoC
  138. // premultiplying. This is only needed for near field.
  139. fgWeight *= step(_MainTex_TexelSize.y, -samp.a);
  140. // Accumulation
  141. bgAcc += half4(samp.rgb, 1.0) * bgWeight;
  142. fgAcc += half4(samp.rgb, 1.0) * fgWeight;
  143. }
  144. // Get the weighted average.
  145. bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard
  146. fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0);
  147. // BG: Calculate the alpha value only based on the center CoC.
  148. // This is a rather aggressive approximation but provides stable results.
  149. bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a);
  150. // FG: Normalize the total of the weights.
  151. fgAcc.a *= PI / kSampleCount;
  152. // Alpha premultiplying
  153. half alpha = saturate(fgAcc.a);
  154. half3 rgb = lerp(bgAcc.rgb, fgAcc.rgb, alpha);
  155. return half4(rgb, alpha);
  156. }
  157. // Postfilter blur
  158. half4 FragPostBlur(VaryingsDefault i) : SV_Target
  159. {
  160. // 9 tap tent filter with 4 bilinear samples
  161. const float4 duv = _MainTex_TexelSize.xyxy * float4(0.5, 0.5, -0.5, 0);
  162. half4 acc;
  163. acc = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - duv.xy));
  164. acc += SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord - duv.zy));
  165. acc += SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + duv.zy));
  166. acc += SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, UnityStereoTransformScreenSpaceTex(i.texcoord + duv.xy));
  167. return acc / 4.0;
  168. }
  169. // Combine with source
  170. half4 FragCombine(VaryingsDefault i) : SV_Target
  171. {
  172. half4 dof = SAMPLE_TEXTURE2D(_DepthOfFieldTex, sampler_DepthOfFieldTex, i.texcoordStereo);
  173. half coc = SAMPLE_TEXTURE2D(_CoCTex, sampler_CoCTex, i.texcoordStereo).r;
  174. coc = (coc - 0.5) * 2.0 * _MaxCoC;
  175. // Convert CoC to far field alpha value.
  176. float ffa = smoothstep(_MainTex_TexelSize.y * 2.0, _MainTex_TexelSize.y * 4.0, coc);
  177. half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo);
  178. #if defined(UNITY_COLORSPACE_GAMMA)
  179. color = SRGBToLinear(color);
  180. #endif
  181. half alpha = Max3(dof.r, dof.g, dof.b);
  182. // lerp(lerp(color, dof, ffa), dof, dof.a)
  183. color = lerp(color, float4(dof.rgb, alpha), ffa + dof.a - ffa * dof.a);
  184. #if defined(UNITY_COLORSPACE_GAMMA)
  185. color = LinearToSRGB(color);
  186. #endif
  187. return color;
  188. }
  189. // Debug overlay
  190. half4 FragDebugOverlay(VaryingsDefault i) : SV_Target
  191. {
  192. half3 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoordStereo).rgb;
  193. // Calculate the radiuses of CoC.
  194. half4 src = SAMPLE_TEXTURE2D(_DepthOfFieldTex, sampler_DepthOfFieldTex, i.texcoordStereo);
  195. float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo));
  196. float coc = (depth - _Distance) * _LensCoeff / depth;
  197. coc *= 80;
  198. // Visualize CoC (white -> red -> gray)
  199. half3 rgb = lerp(half3(1.0, 0.0, 0.0), half3(1.0, 1.0, 1.0), saturate(-coc));
  200. rgb = lerp(rgb, half3(0.4, 0.4, 0.4), saturate(coc));
  201. // Black and white image overlay
  202. rgb *= Luminance(color) + 0.5;
  203. // Gamma correction
  204. #if !UNITY_COLORSPACE_GAMMA
  205. rgb = SRGBToLinear(rgb);
  206. #endif
  207. return half4(rgb, 1.0);
  208. }
  209. #endif // UNITY_POSTFX_DEPTH_OF_FIELD