Depth of Field.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /******************************************************************************/
  2. #include "!Header.h"
  3. /******************************************************************************
  4. TODO: add slow but high quality circular bokeh DoF
  5. -create small / quarter res (or maybe even smaller) RT containing info about biggest blur radius
  6. -in the blur function iterate "radius x radius" using BRANCH/LOOP and the small RT image (perhaps need to use 'SamplerPoint')
  7. -sample intensity should be based on Length2(sample_distance)<=Sqr(sample_range) (making bool true/false)
  8. -probably should divide this by sample area "intensity / Sqr(sample_range)" (samples covering more areas are stretched and their intensity spreaded?)
  9. /******************************************************************************/
  10. #define SHOW_BLUR 0
  11. #define SHOW_SMOOTH_BLUR 0
  12. #define SHOW_BLURRED 0
  13. #define FRONT_EXTEND 0 // 0 or 1, method for extending the front, default=0
  14. #define DEPTH_TOLERANCE (FRONT_EXTEND ? 1.5f : 1.0f) // 1..2 are reasonable
  15. #define FINAL_MODE 1 // 1(default)=maximize smooth blur only if it's closer, 0=always maximize smooth blur
  16. #define FINAL_SCALE 4.0f // final blur scale, increases transition between sharp and blurred in 0..1/FINAL_SCALE step, instead of 0..1
  17. /******************************************************************************/
  18. BUFFER(Dof)
  19. Vec4 DofParams; // Intensity, Focus, SimpleMulAdd
  20. BUFFER_END
  21. inline Flt DofIntensity() {return DofParams.x;}
  22. inline Flt DofFocus () {return DofParams.y;}
  23. inline Flt DofMul () {return DofParams.z;}
  24. inline Flt DofAdd () {return DofParams.w;}
  25. /******************************************************************************/
  26. inline Flt Blur(Flt z, uniform Bool realistic)
  27. {
  28. if(realistic)
  29. {
  30. #if 0 // F makes almost no difference
  31. Flt F=0.075f; return DofIntensity() /* * F */ * (z - DofFocus()) / (z * (DofFocus() - F));
  32. #else
  33. return DofIntensity()*(z-DofFocus())/(z*DofFocus()); // 'DofRange' ignored
  34. #endif
  35. }else return DofIntensity()*Mid(z*DofMul() + DofAdd(), -1, 1); // (z-DofFocus())/DofRange, z/DofRange - DofFocus()/DofRange
  36. }
  37. /******************************************************************************/
  38. Vec4 DofDS_PS(NOPERSP Vec2 inTex:TEXCOORD,
  39. uniform Bool do_clamp ,
  40. uniform Bool realistic ,
  41. uniform Bool half ,
  42. uniform Bool gather ):COLOR
  43. {
  44. Vec4 ret; // RGB=col, W=Blur
  45. if(half)
  46. {
  47. ret.rgb=TexLod(Col, UVClamp(inTex, do_clamp)).rgb; // use linear filtering because we're downsampling
  48. #if MODEL>=SM_4
  49. if(gather)ret.w=DEPTH_MIN(Depth.Gather(SamplerPoint, inTex));else
  50. #endif
  51. {
  52. Vec2 tex_min=inTex-ColSize.xy*0.5f,
  53. tex_max=inTex+ColSize.xy*0.5f;
  54. ret.w=DEPTH_MIN(TexDepthRawPoint(Vec2(tex_min.x, tex_min.y)),
  55. TexDepthRawPoint(Vec2(tex_max.x, tex_min.y)),
  56. TexDepthRawPoint(Vec2(tex_min.x, tex_max.y)),
  57. TexDepthRawPoint(Vec2(tex_max.x, tex_max.y)));
  58. }
  59. }else // quarter
  60. {
  61. Vec2 tex_min=UVClamp(inTex-ColSize.xy, do_clamp),
  62. tex_max=UVClamp(inTex+ColSize.xy, do_clamp);
  63. Vec2 t00=Vec2(tex_min.x, tex_min.y),
  64. t10=Vec2(tex_max.x, tex_min.y),
  65. t01=Vec2(tex_min.x, tex_max.y),
  66. t11=Vec2(tex_max.x, tex_max.y);
  67. // use linear filtering because we're downsampling
  68. ret.rgb=(TexLod(Col, t00).rgb
  69. +TexLod(Col, t10).rgb
  70. +TexLod(Col, t01).rgb
  71. +TexLod(Col, t11).rgb)/4;
  72. #if MODEL>=SM_4
  73. if(gather)ret.w=DEPTH_MIN(DEPTH_MIN(Depth.Gather(SamplerPoint, t00)),
  74. DEPTH_MIN(Depth.Gather(SamplerPoint, t10)),
  75. DEPTH_MIN(Depth.Gather(SamplerPoint, t01)),
  76. DEPTH_MIN(Depth.Gather(SamplerPoint, t11)));else
  77. #endif
  78. {
  79. // this is approximation because we would have to take 16 samples
  80. ret.w=DEPTH_MIN(TexDepthRawPoint(t00),
  81. TexDepthRawPoint(t10),
  82. TexDepthRawPoint(t01),
  83. TexDepthRawPoint(t11));
  84. }
  85. }
  86. ret.w=Blur(LinearizeDepth(ret.w), realistic)*0.5f+0.5f;
  87. return ret;
  88. }
  89. /******************************************************************************/
  90. inline Flt Center(Flt center_blur_u) // center_blur_u=0..1 (0.5=focus) here we can offload some of the calculation done for each sample, by making necessary adjustments to 'center_blur_u'
  91. {
  92. return center_blur_u*2-1;
  93. }
  94. inline Flt Weight(Flt center_blur, Flt test_blur_u,
  95. #if MODEL!=SM_GL // have to forget about uniform because it will fail on Mac
  96. uniform
  97. #endif
  98. Int dist, uniform Int range) // center_blur=-1..1 (0=focus), center_blur_u=0..1 (0.5=focus), test_blur_u=0..1 (0.5=focus)
  99. {
  100. Flt f=dist/Flt(range+1),
  101. //center_blur=center_blur_u*2-1, // -1..1, we've already done this in 'Center'
  102. test_blur= test_blur_u*2-1, // -1..1
  103. cb=Abs(center_blur), // 0..1
  104. tb=Abs( test_blur), // 0..1
  105. b=Max(tb, cb // have to extend search radius for cases when center is in the front
  106. *Sat(FRONT_EXTEND ? (tb-center_blur)*DEPTH_TOLERANCE+1 : -center_blur*DEPTH_TOLERANCE)) // skip if: test focused and center in the back, or apply if: center in front
  107. *Sat((cb-test_blur)*DEPTH_TOLERANCE+1); // skip if: center focused and test in the back
  108. if(!b)return 0; // this check is needed only for low precision devices, or when using high precision RT's. Low precision unsigned RT's don't have exact zero, however we scale 'b' above and zero could be reached?
  109. Flt x=f/b; // NaN
  110. x=Sat(x); // x=Min(x, 1); to prevent for returning 'LerpCube' values outside 0..1 range
  111. return (1-LerpCube(x))/b; // weight, divide by 'b' to make narrower ranges more intense to preserve total intensity
  112. // !! if changing from 'LerpCube' to another function then we need to change 'WeightSum' as well !!
  113. }
  114. inline Flt FinalBlur(Flt blur, Flt blur_smooth) // 'blur'=-Inf .. Inf, 'blur_smooth'=0..1
  115. {
  116. if(SHOW_BLURRED)return 1;
  117. //blur_smooth=(FINAL_MODE ? Sat(blur_smooth*-2+1) : Abs(blur_smooth*2-1)); already done in 'DofBlurY_PS'
  118. return Sat(Max(Abs(blur), blur_smooth)*FINAL_SCALE);
  119. }
  120. inline Flt WeightSum(uniform Int range) {return range+1;} // Sum of all weights for all "-range..range" steps, calculated using "Flt weight=0; for(Int dist=-range; dist<=range; dist++)weight+=BlendSmoothCube(dist/Flt(range+1));"
  121. /******************************************************************************/
  122. #define SCALE 0.5f // at the end we need 0 .. 0.5 range, and since we start with 0..1 we need to scale by "0.5"
  123. Vec4 DofBlurX_PS(NOPERSP Vec2 inTex:TEXCOORD,
  124. uniform Int range ):COLOR
  125. { // INPUT: Col: RGB , Blur
  126. // OUTPUT: RGB BlurredX, BlurSmooth
  127. Vec4 center=TexPoint(Col, inTex);
  128. Flt center_blur=Center(center.a),
  129. weight=0,
  130. blur_abs=0;
  131. Vec4 color =0;
  132. Vec2 t; t.y=inTex.y;
  133. UNROLL for(Int i=-range; i<=range; i++)if(i)
  134. {
  135. t.x=inTex.x+ColSize.x*i;
  136. Vec4 c=TexPoint(Col, t);
  137. Flt test_blur=c.a,
  138. #if MODEL==SM_GL
  139. w=Weight(center_blur, test_blur, (i>=0) ? i : -i, range);
  140. #else
  141. w=Weight(center_blur, test_blur, Abs(i), range);
  142. #endif
  143. weight +=w;
  144. color +=w* c;
  145. blur_abs+=w*Abs(c.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
  146. }
  147. Flt b=Abs(center_blur),
  148. w=Lerp(WeightSum(range)-weight, 1, b);
  149. color +=w* center;
  150. blur_abs+=w*Abs(center.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
  151. weight +=w;
  152. blur_abs/=weight;
  153. //return Vec4(color.rgb/weight, color.a/weight);
  154. return Vec4(color.rgb/weight, (color.a>=0.5f*weight) ? 0.5f+blur_abs : 0.5f-blur_abs); // color.a/weight>=0.5f ? .. : ..
  155. }
  156. #undef SCALE
  157. #define SCALE 1.0f // at the end we need 0..1 range, and since we start with 0..1 we need to scale by "1"
  158. Vec4 DofBlurY_PS(NOPERSP Vec2 inTex:TEXCOORD,
  159. uniform Int range ):COLOR
  160. { // INPUT: Col: RGB BlurredX , BlurSmooth
  161. // OUTPUT: RGB BlurredXY, BlurSmooth
  162. Vec4 center=TexPoint(Col, inTex);
  163. Flt center_blur=Center(center.a),
  164. weight=0,
  165. blur_abs=0;
  166. Vec4 color =0;
  167. Vec2 t; t.x=inTex.x;
  168. UNROLL for(Int i=-range; i<=range; i++)if(i)
  169. {
  170. t.y=inTex.y+ColSize.y*i;
  171. Vec4 c=TexPoint(Col, t);
  172. Flt test_blur=c.a,
  173. #if MODEL==SM_GL
  174. w=Weight(center_blur, test_blur, (i>=0) ? i : -i, range);
  175. #else
  176. w=Weight(center_blur, test_blur, Abs(i), range);
  177. #endif
  178. weight +=w;
  179. color +=w* c;
  180. blur_abs+=w*Abs(c.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
  181. }
  182. Flt b=Abs(center_blur),
  183. w=Lerp(WeightSum(range)-weight, 1, b);
  184. color +=w* center;
  185. blur_abs+=w*Abs(center.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
  186. weight +=w;
  187. blur_abs/=weight;
  188. //color.a =((color.a>=0.5f*weight) ? 0.5f+blur_abs : 0.5f-blur_abs); // color.a/weight>=0.5f ? .. : ..
  189. return Vec4(color.rgb/weight, FINAL_MODE ? ((color.a>=0.5f*weight) ? 0 : blur_abs) : blur_abs);
  190. }
  191. /******************************************************************************/
  192. Vec4 Dof_PS(NOPERSP Vec2 inTex:TEXCOORD,
  193. NOPERSP PIXEL ,
  194. uniform Bool dither ,
  195. uniform Bool realistic ):COLOR
  196. {
  197. Flt z=TexDepthPoint(inTex),
  198. b=Blur(z, realistic);
  199. #if SHOW_BLUR
  200. b=1-Abs(b); return Vec4(b, b, b, 1);
  201. #endif
  202. Vec4 focus=TexLod(Col , inTex), // can't use 'TexPoint' because 'Col' can be supersampled
  203. blur =TexLod(Col1, inTex), // use linear filtering because 'Col1' may be smaller RT
  204. col;
  205. #if SHOW_SMOOTH_BLUR
  206. col.rgb=blur.a;
  207. #else
  208. col.rgb=Lerp(focus.rgb, blur.rgb, FinalBlur(b, blur.a));
  209. #endif
  210. col.a=1; // force full alpha so back buffer effects can work ok
  211. if(dither)col.rgb+=DitherValueColor(pixel);
  212. return col;
  213. }
  214. /******************************************************************************/
  215. // TECHNIQUES
  216. /******************************************************************************/
  217. TECHNIQUE (DofDS , Draw_VS(), DofDS_PS(false, false, false, false));
  218. TECHNIQUE (DofDSC , Draw_VS(), DofDS_PS(true , false, false, false));
  219. TECHNIQUE (DofDSR , Draw_VS(), DofDS_PS(false, true , false, false));
  220. TECHNIQUE (DofDSCR , Draw_VS(), DofDS_PS(true , true , false, false));
  221. TECHNIQUE (DofDSH , Draw_VS(), DofDS_PS(false, false, true , false));
  222. TECHNIQUE (DofDSCH , Draw_VS(), DofDS_PS(true , false, true , false));
  223. TECHNIQUE (DofDSRH , Draw_VS(), DofDS_PS(false, true , true , false));
  224. TECHNIQUE (DofDSCRH , Draw_VS(), DofDS_PS(true , true , true , false));
  225. TECHNIQUE_4_1(DofDSG , Draw_VS(), DofDS_PS(false, false, false, true ));
  226. TECHNIQUE_4_1(DofDSCG , Draw_VS(), DofDS_PS(true , false, false, true ));
  227. TECHNIQUE_4_1(DofDSRG , Draw_VS(), DofDS_PS(false, true , false, true ));
  228. TECHNIQUE_4_1(DofDSCRG , Draw_VS(), DofDS_PS(true , true , false, true ));
  229. TECHNIQUE_4_1(DofDSHG , Draw_VS(), DofDS_PS(false, false, true , true ));
  230. TECHNIQUE_4_1(DofDSCHG , Draw_VS(), DofDS_PS(true , false, true , true ));
  231. TECHNIQUE_4_1(DofDSRHG , Draw_VS(), DofDS_PS(false, true , true , true ));
  232. TECHNIQUE_4_1(DofDSCRHG, Draw_VS(), DofDS_PS(true , true , true , true ));
  233. #define DOF_BLUR(range) TECHNIQUE(DofBlurX##range, Draw_VS(), DofBlurX_PS(range)); TECHNIQUE(DofBlurY##range, Draw_VS(), DofBlurY_PS(range));
  234. DOF_BLUR(2)
  235. DOF_BLUR(3)
  236. DOF_BLUR(4)
  237. DOF_BLUR(5)
  238. DOF_BLUR(6)
  239. DOF_BLUR(7)
  240. DOF_BLUR(8)
  241. DOF_BLUR(9)
  242. DOF_BLUR(10)
  243. DOF_BLUR(11)
  244. DOF_BLUR(12)
  245. TECHNIQUE(Dof , Draw_VS(), Dof_PS(false, false));
  246. TECHNIQUE(DofD , Draw_VS(), Dof_PS(true , false));
  247. TECHNIQUE(DofR , Draw_VS(), Dof_PS(false, true ));
  248. TECHNIQUE(DofDR, Draw_VS(), Dof_PS(true , true ));
  249. /******************************************************************************/