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.

243 lines
7.7 KiB

  1. #ifndef __DEPTH_OF_FIELD__
  2. #define __DEPTH_OF_FIELD__
  3. #if SHADER_TARGET >= 50
  4. // Use separate texture/sampler objects on Shader Model 5.0
  5. #define SEPARATE_TEXTURE_SAMPLER
  6. #define DOF_DECL_TEX2D(tex) Texture2D tex; SamplerState sampler##tex
  7. #define DOF_TEX2D(tex, coord) tex.Sample(sampler##tex, coord)
  8. #else
  9. #define DOF_DECL_TEX2D(tex) sampler2D tex
  10. #define DOF_TEX2D(tex, coord) tex2D(tex, coord)
  11. #endif
  12. #include "Common.cginc"
  13. #include "DiskKernels.cginc"
  14. DOF_DECL_TEX2D(_CameraDepthTexture);
  15. DOF_DECL_TEX2D(_CameraMotionVectorsTexture);
  16. DOF_DECL_TEX2D(_CoCTex);
  17. // Camera parameters
  18. float _Distance;
  19. float _LensCoeff; // f^2 / (N * (S1 - f) * film_width * 2)
  20. float _MaxCoC;
  21. float _RcpMaxCoC;
  22. float _RcpAspect;
  23. half3 _TaaParams; // Jitter.x, Jitter.y, Blending
  24. struct VaryingsDOF
  25. {
  26. float4 pos : SV_POSITION;
  27. half2 uv : TEXCOORD0;
  28. half2 uvAlt : TEXCOORD1;
  29. };
  30. // Common vertex shader with single pass stereo rendering support
  31. VaryingsDOF VertDOF(AttributesDefault v)
  32. {
  33. half2 uvAlt = v.texcoord;
  34. #if UNITY_UV_STARTS_AT_TOP
  35. if (_MainTex_TexelSize.y < 0.0) uvAlt.y = 1.0 - uvAlt.y;
  36. #endif
  37. VaryingsDOF o;
  38. o.pos = UnityObjectToClipPos(v.vertex);
  39. #if defined(UNITY_SINGLE_PASS_STEREO)
  40. o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST);
  41. o.uvAlt = UnityStereoScreenSpaceUVAdjust(uvAlt, _MainTex_ST);
  42. #else
  43. o.uv = v.texcoord;
  44. o.uvAlt = uvAlt;
  45. #endif
  46. return o;
  47. }
  48. // CoC calculation
  49. half4 FragCoC(VaryingsDOF i) : SV_Target
  50. {
  51. float depth = LinearEyeDepth(DOF_TEX2D(_CameraDepthTexture, i.uv));
  52. half coc = (depth - _Distance) * _LensCoeff / max(depth, 1e-5);
  53. return saturate(coc * 0.5 * _RcpMaxCoC + 0.5);
  54. }
  55. // Temporal filter
  56. half4 FragTempFilter(VaryingsDOF i) : SV_Target
  57. {
  58. float3 uvOffs = _MainTex_TexelSize.xyy * float3(1, 1, 0);
  59. #if defined(SEPARATE_TEXTURE_SAMPLER)
  60. half4 cocTL = _CoCTex.GatherRed(sampler_CoCTex, i.uv - uvOffs.xy * 0.5); // top-left
  61. half4 cocBR = _CoCTex.GatherRed(sampler_CoCTex, i.uv + uvOffs.xy * 0.5); // bottom-right
  62. half coc1 = cocTL.x; // top
  63. half coc2 = cocTL.z; // left
  64. half coc3 = cocBR.x; // bottom
  65. half coc4 = cocBR.z; // right
  66. #else
  67. half coc1 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.xz).r; // top
  68. half coc2 = DOF_TEX2D(_CoCTex, i.uv - uvOffs.zy).r; // left
  69. half coc3 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.zy).r; // bottom
  70. half coc4 = DOF_TEX2D(_CoCTex, i.uv + uvOffs.xz).r; // right
  71. #endif
  72. // Dejittered center sample.
  73. half coc0 = DOF_TEX2D(_CoCTex, i.uv - _TaaParams.xy).r;
  74. // CoC dilation: determine the closest point in the four neighbors.
  75. float3 closest = float3(0, 0, coc0);
  76. closest = coc1 < closest.z ? float3(-uvOffs.xz, coc1) : closest;
  77. closest = coc2 < closest.z ? float3(-uvOffs.zy, coc2) : closest;
  78. closest = coc3 < closest.z ? float3(+uvOffs.zy, coc3) : closest;
  79. closest = coc4 < closest.z ? float3(+uvOffs.xz, coc4) : closest;
  80. // Sample the history buffer with the motion vector at the closest point.
  81. float2 motion = DOF_TEX2D(_CameraMotionVectorsTexture, i.uv + closest.xy).xy;
  82. half cocHis = DOF_TEX2D(_MainTex, i.uv - motion).r;
  83. // Neighborhood clamping.
  84. half cocMin = closest.z;
  85. half cocMax = max(max(max(max(coc0, coc1), coc2), coc3), coc4);
  86. cocHis = clamp(cocHis, cocMin, cocMax);
  87. // Blend with the history.
  88. return lerp(coc0, cocHis, _TaaParams.z);
  89. }
  90. // Prefilter: downsampling and premultiplying.
  91. half4 FragPrefilter(VaryingsDOF i) : SV_Target
  92. {
  93. #if defined(SEPARATE_TEXTURE_SAMPLER)
  94. // Sample source colors.
  95. half4 c_r = _MainTex.GatherRed (sampler_MainTex, i.uv);
  96. half4 c_g = _MainTex.GatherGreen(sampler_MainTex, i.uv);
  97. half4 c_b = _MainTex.GatherBlue (sampler_MainTex, i.uv);
  98. half3 c0 = half3(c_r.x, c_g.x, c_b.x);
  99. half3 c1 = half3(c_r.y, c_g.y, c_b.y);
  100. half3 c2 = half3(c_r.z, c_g.z, c_b.z);
  101. half3 c3 = half3(c_r.w, c_g.w, c_b.w);
  102. // Sample CoCs.
  103. half4 cocs = _CoCTex.Gather(sampler_CoCTex, i.uvAlt) * 2.0 - 1.0;
  104. half coc0 = cocs.x;
  105. half coc1 = cocs.y;
  106. half coc2 = cocs.z;
  107. half coc3 = cocs.w;
  108. #else
  109. float3 duv = _MainTex_TexelSize.xyx * float3(0.5, 0.5, -0.5);
  110. // Sample source colors.
  111. half3 c0 = DOF_TEX2D(_MainTex, i.uv - duv.xy).rgb;
  112. half3 c1 = DOF_TEX2D(_MainTex, i.uv - duv.zy).rgb;
  113. half3 c2 = DOF_TEX2D(_MainTex, i.uv + duv.zy).rgb;
  114. half3 c3 = DOF_TEX2D(_MainTex, i.uv + duv.xy).rgb;
  115. // Sample CoCs.
  116. half coc0 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.xy).r * 2.0 - 1.0;
  117. half coc1 = DOF_TEX2D(_CoCTex, i.uvAlt - duv.zy).r * 2.0 - 1.0;
  118. half coc2 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.zy).r * 2.0 - 1.0;
  119. half coc3 = DOF_TEX2D(_CoCTex, i.uvAlt + duv.xy).r * 2.0 - 1.0;
  120. #endif
  121. // Apply CoC and luma weights to reduce bleeding and flickering.
  122. float w0 = abs(coc0) / (Max3(c0) + 1.0);
  123. float w1 = abs(coc1) / (Max3(c1) + 1.0);
  124. float w2 = abs(coc2) / (Max3(c2) + 1.0);
  125. float w3 = abs(coc3) / (Max3(c3) + 1.0);
  126. // Weighted average of the color samples
  127. half3 avg = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3;
  128. avg /= max(w0 + w1 + w2 + w3, 1e-5);
  129. // Select the largest CoC value.
  130. half coc_min = Min4(coc0, coc1, coc2, coc3);
  131. half coc_max = Max4(coc0, coc1, coc2, coc3);
  132. half coc = (-coc_min > coc_max ? coc_min : coc_max) * _MaxCoC;
  133. // Premultiply CoC again.
  134. avg *= smoothstep(0, _MainTex_TexelSize.y * 2, abs(coc));
  135. #if defined(UNITY_COLORSPACE_GAMMA)
  136. avg = GammaToLinearSpace(avg);
  137. #endif
  138. return half4(avg, coc);
  139. }
  140. // Bokeh filter with disk-shaped kernels
  141. half4 FragBlur(VaryingsDOF i) : SV_Target
  142. {
  143. half4 samp0 = DOF_TEX2D(_MainTex, i.uv);
  144. half4 bgAcc = 0.0; // Background: far field bokeh
  145. half4 fgAcc = 0.0; // Foreground: near field bokeh
  146. UNITY_LOOP for (int si = 0; si < kSampleCount; si++)
  147. {
  148. float2 disp = kDiskKernel[si] * _MaxCoC;
  149. float dist = length(disp);
  150. float2 duv = float2(disp.x * _RcpAspect, disp.y);
  151. half4 samp = DOF_TEX2D(_MainTex, i.uv + duv);
  152. // BG: Compare CoC of the current sample and the center sample
  153. // and select smaller one.
  154. half bgCoC = max(min(samp0.a, samp.a), 0.0);
  155. // Compare the CoC to the sample distance.
  156. // Add a small margin to smooth out.
  157. const half margin = _MainTex_TexelSize.y * 2;
  158. half bgWeight = saturate((bgCoC - dist + margin) / margin);
  159. half fgWeight = saturate((-samp.a - dist + margin) / margin);
  160. // Cut influence from focused areas because they're darkened by CoC
  161. // premultiplying. This is only needed for near field.
  162. fgWeight *= step(_MainTex_TexelSize.y, -samp.a);
  163. // Accumulation
  164. bgAcc += half4(samp.rgb, 1.0) * bgWeight;
  165. fgAcc += half4(samp.rgb, 1.0) * fgWeight;
  166. }
  167. // Get the weighted average.
  168. bgAcc.rgb /= bgAcc.a + (bgAcc.a == 0.0); // zero-div guard
  169. fgAcc.rgb /= fgAcc.a + (fgAcc.a == 0.0);
  170. // BG: Calculate the alpha value only based on the center CoC.
  171. // This is a rather aggressive approximation but provides stable results.
  172. bgAcc.a = smoothstep(_MainTex_TexelSize.y, _MainTex_TexelSize.y * 2.0, samp0.a);
  173. // FG: Normalize the total of the weights.
  174. fgAcc.a *= UNITY_PI / kSampleCount;
  175. // Alpha premultiplying
  176. half alpha = saturate(fgAcc.a);
  177. half3 rgb = lerp(bgAcc.rgb, fgAcc.rgb, alpha);
  178. return half4(rgb, alpha);
  179. }
  180. // Postfilter blur
  181. half4 FragPostBlur(VaryingsDOF i) : SV_Target
  182. {
  183. // 9 tap tent filter with 4 bilinear samples
  184. const float4 duv = _MainTex_TexelSize.xyxy * float4(0.5, 0.5, -0.5, 0);
  185. half4 acc;
  186. acc = DOF_TEX2D(_MainTex, i.uv - duv.xy);
  187. acc += DOF_TEX2D(_MainTex, i.uv - duv.zy);
  188. acc += DOF_TEX2D(_MainTex, i.uv + duv.zy);
  189. acc += DOF_TEX2D(_MainTex, i.uv + duv.xy);
  190. return acc / 4.0;
  191. }
  192. #endif // __DEPTH_OF_FIELD__