bokeh_dof.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright 2021 elven cache. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #ifndef BOKEH_DOF_SH
  6. #define BOKEH_DOF_SH
  7. #define TWO_PI (6.28318531)
  8. #define GOLDEN_ANGLE (2.39996323)
  9. #define MAX_BLUR_SIZE (20.0)
  10. #define RADIUS_SCALE (0.5)
  11. float ShadertoyNoise (vec2 uv) {
  12. return fract(sin(dot(uv.xy, vec2(12.9898,78.233))) * 43758.5453123);
  13. }
  14. float GetCircleOfConfusion (float depth, float focusPoint, float focusScale)
  15. {
  16. // if depth is less than focusPoint, result will be negative. want to keep this
  17. // relationship so comparison of (signed) blur size is same as comparing depth.
  18. return clamp((1.0/focusPoint - 1.0/depth) * focusScale, -1.0, 1.0);
  19. }
  20. float GetBlurSize (float depth, float focusPoint, float focusScale)
  21. {
  22. float circleOfConfusion = GetCircleOfConfusion(depth, focusPoint, focusScale);
  23. return circleOfConfusion * u_maxBlurSize;
  24. }
  25. // this is the function at bottom of blog post...
  26. //vec3 OriginalDepthOfField (vec2 texCoord, float focusPoint, float focusScale)
  27. //{
  28. // float depth = texture2D(s_depth, texCoord).x;
  29. // float centerSize = GetBlurSize(depth, focusPoint, focusScale);
  30. // vec3 color = texture2D(s_color, texCoord).xyz;
  31. //
  32. // float total = 1.0;
  33. // float radius = RADIUS_SCALE;
  34. // for (float theta = 0.0; radius < MAX_BLUR_SIZE; theta += GOLDEN_ANGLE)
  35. // {
  36. // vec2 spiralCoord = texCoord + vec2(cos(theta), sin(theta)) * u_viewTexel.xy * radius;
  37. // vec3 sampleColor = texture2D(s_color, spiralCoord).xyz;
  38. // float sampleDepth = texture2D(s_depth, spiralCoord).x;
  39. //
  40. // float sampleSize = GetBlurSize(sampleDepth, focusPoint, focusScale);
  41. // if (sampleDepth > depth)
  42. // {
  43. // sampleSize = clamp(sampleSize, 0.0, centerSize*2.0);
  44. // }
  45. // float m = smoothstep(radius-0.5, radius+0.5, sampleSize);
  46. // color += mix(color/total, sampleColor, m);
  47. // total += 1.0;
  48. // radius += RADIUS_SCALE/radius;
  49. // }
  50. // return color * (1.0/total);
  51. //}
  52. void GetColorAndBlurSize (
  53. sampler2D samplerColor,
  54. sampler2D samplerDepth,
  55. vec2 texCoord,
  56. float focusPoint,
  57. float focusScale,
  58. out vec3 outColor,
  59. out float outBlurSize
  60. ) {
  61. #if USE_PACKED_COLOR_AND_BLUR
  62. vec4 colorAndBlurSize = texture2DLod(samplerColor, texCoord, 0);
  63. vec3 color = colorAndBlurSize.xyz;
  64. float blurSize = colorAndBlurSize.w;
  65. outColor = color;
  66. outBlurSize = blurSize;
  67. #else
  68. vec3 color = texture2DLod(samplerColor, texCoord, 0).xyz;
  69. float depth = texture2DLod(samplerDepth, texCoord, 0).x;
  70. float blurSize = GetBlurSize(depth, focusPoint, focusScale);
  71. outColor = color;
  72. outBlurSize = blurSize;
  73. #endif
  74. }
  75. float BokehShapeFromAngle (float lobeCount, float radiusMin, float radiusDelta2x, float rotation, float angle)
  76. {
  77. // don't shape for 0, 1 blades...
  78. if (lobeCount <= 1.0f)
  79. {
  80. return 1.0f;
  81. }
  82. // divide edge into some number of lobes
  83. float invPeriod = lobeCount / (2.0 * 3.1415926);
  84. float periodFraction = fract(angle * invPeriod + rotation);
  85. // apply triangle shape to each lobe to approximate blades of a camera aperture
  86. periodFraction = abs(periodFraction - 0.5);
  87. return periodFraction*radiusDelta2x + radiusMin;
  88. }
  89. vec4 DepthOfField(
  90. sampler2D samplerColor,
  91. sampler2D samplerDepth,
  92. vec2 texCoord,
  93. float focusPoint,
  94. float focusScale
  95. ) {
  96. vec3 color;
  97. float centerSize;
  98. GetColorAndBlurSize(
  99. samplerColor,
  100. samplerDepth,
  101. texCoord,
  102. focusPoint,
  103. focusScale,
  104. /*out*/color,
  105. /*out*/centerSize);
  106. float absCenterSize = abs(centerSize);
  107. // as sample count gets lower, visible banding. disrupt with noise.
  108. // use a better random/noise/dither function than this..
  109. vec2 pixelCoord = texCoord.xy * u_viewRect.zw;
  110. float random = ShadertoyNoise(pixelCoord + vec2(314.0, 159.0)*u_frameIdx);
  111. float theta = random * TWO_PI;
  112. float thetaStep = GOLDEN_ANGLE;
  113. float total = 1.0;
  114. float totalSampleSize = 0.0;
  115. float loopValue = u_radiusScale;
  116. float loopEnd = u_maxBlurSize;
  117. while (loopValue < loopEnd)
  118. {
  119. float radius = loopValue;
  120. float shapeScale = BokehShapeFromAngle(
  121. u_lobeCount,
  122. u_lobeRadiusMin,
  123. u_lobeRadiusDelta2x,
  124. u_lobeRotation,
  125. theta);
  126. vec2 spiralCoord = texCoord + vec2(cos(theta), sin(theta)) * u_viewTexel.xy * (radius * shapeScale);
  127. vec3 sampleColor;
  128. float sampleSize;
  129. GetColorAndBlurSize(
  130. samplerColor,
  131. samplerDepth,
  132. spiralCoord,
  133. focusPoint,
  134. focusScale,
  135. /*out*/sampleColor,
  136. /*out*/sampleSize);
  137. float absSampleSize = abs(sampleSize);
  138. // using signed sample size as proxy for depth comparison
  139. if (sampleSize > centerSize)
  140. {
  141. absSampleSize = clamp(absSampleSize, 0.0, absCenterSize*2.0);
  142. }
  143. float m = smoothstep(radius-0.5, radius+0.5, absSampleSize);
  144. color += mix(color/total, sampleColor, m);
  145. totalSampleSize += absSampleSize;
  146. total += 1.0;
  147. theta += thetaStep;
  148. loopValue += (u_radiusScale/loopValue);
  149. }
  150. color *= 1.0/total;
  151. float averageSampleSize = totalSampleSize / (total-1.0);
  152. return vec4(color, averageSampleSize);
  153. }
  154. #endif