depthOfField.fragment.fx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // BABYLON.JS Depth-of-field GLSL Shader
  2. // Author: Olivier Guyot
  3. // Does depth-of-field blur, edge blur
  4. // Inspired by Francois Tarlier & Martins Upitis
  5. #ifdef GL_ES
  6. precision highp float;
  7. #endif
  8. // samplers
  9. uniform sampler2D textureSampler;
  10. uniform sampler2D highlightsSampler;
  11. uniform sampler2D depthSampler;
  12. uniform sampler2D grainSampler;
  13. // uniforms
  14. uniform float grain_amount;
  15. uniform float maxZ;
  16. uniform bool blur_noise;
  17. uniform float screen_width;
  18. uniform float screen_height;
  19. uniform float distortion;
  20. uniform float focus_depth;
  21. uniform float aperture;
  22. uniform float edge_blur;
  23. uniform bool highlights;
  24. // varyings
  25. varying vec2 vUV;
  26. // constants
  27. #define PI 3.14159265
  28. // common calculations
  29. vec2 centered_screen_pos;
  30. float radius2;
  31. float radius;
  32. // applies edge distortion on texture coords
  33. vec2 getDistortedCoords(vec2 coords) {
  34. if (distortion == 0.0) { return coords; }
  35. vec2 direction = 1.0 * normalize(centered_screen_pos);
  36. vec2 dist_coords = vec2(0.5, 0.5);
  37. dist_coords.x = 0.5 + direction.x * radius2 * 1.0;
  38. dist_coords.y = 0.5 + direction.y * radius2 * 1.0;
  39. float dist_amount = clamp(distortion*0.23, 0.0, 1.0);
  40. dist_coords = mix(coords, dist_coords, dist_amount);
  41. return dist_coords;
  42. }
  43. // returns original screen color after blur
  44. vec4 getBlurColor(vec2 coords, float size) {
  45. vec4 col = texture2D(textureSampler, coords);
  46. if (size == 0.0) { return col; }
  47. // there are max. 30 samples; the number of samples chosen is dependant on the blur size
  48. // there can be 10, 20 or 30 samples chosen; levels of blur are then 1, 2 or 3
  49. float blur_level = min(3.0, ceil(size / 1.0));
  50. float w = (size / screen_width);
  51. float h = (size / screen_height);
  52. float total_weight = 1.0;
  53. col += texture2D(textureSampler, coords + vec2(-0.53*w, 0.15*h))*0.93;
  54. col += texture2D(textureSampler, coords + vec2(0.42*w, -0.69*h))*0.90;
  55. col += texture2D(textureSampler, coords + vec2(0.20*w, 1.00*h))*0.87;
  56. col += texture2D(textureSampler, coords + vec2(-0.97*w, -0.72*h))*0.85;
  57. col += texture2D(textureSampler, coords + vec2(1.37*w, -0.14*h))*0.83;
  58. col += texture2D(textureSampler, coords + vec2(-1.02*w, 1.16*h))*0.80;
  59. col += texture2D(textureSampler, coords + vec2(-0.03*w, -1.69*h))*0.78;
  60. col += texture2D(textureSampler, coords + vec2(1.27*w, 1.34*h))*0.76;
  61. col += texture2D(textureSampler, coords + vec2(-1.98*w, -0.14*h))*0.74;
  62. col += texture2D(textureSampler, coords + vec2(1.66*w, -1.32*h))*0.72;
  63. total_weight += 8.18;
  64. if (blur_level > 1.0) {
  65. col += texture2D(textureSampler, coords + vec2(-0.35*w, 2.22*h))*0.70;
  66. col += texture2D(textureSampler, coords + vec2(-1.31*w, -1.98*h))*0.67;
  67. col += texture2D(textureSampler, coords + vec2(2.42*w, 0.61*h))*0.65;
  68. col += texture2D(textureSampler, coords + vec2(-2.31*w, 1.25*h))*0.63;
  69. col += texture2D(textureSampler, coords + vec2(0.90*w, -2.59*h))*0.61;
  70. col += texture2D(textureSampler, coords + vec2(1.14*w, 2.62*h))*0.59;
  71. col += texture2D(textureSampler, coords + vec2(-2.72*w, -1.21*h))*0.56;
  72. col += texture2D(textureSampler, coords + vec2(2.93*w, -0.98*h))*0.54;
  73. col += texture2D(textureSampler, coords + vec2(-1.56*w, 2.80*h))*0.52;
  74. col += texture2D(textureSampler, coords + vec2(-0.77*w, -3.22*h))*0.49;
  75. total_weight += 5.96;
  76. }
  77. if (blur_level > 2.0) {
  78. col += texture2D(textureSampler, coords + vec2(2.83*w, 1.92*h))*0.46;
  79. col += texture2D(textureSampler, coords + vec2(-3.49*w, 0.51*h))*0.44;
  80. col += texture2D(textureSampler, coords + vec2(2.30*w, -2.82*h))*0.41;
  81. col += texture2D(textureSampler, coords + vec2(0.22*w, 3.74*h))*0.38;
  82. col += texture2D(textureSampler, coords + vec2(-2.76*w, -2.68*h))*0.34;
  83. col += texture2D(textureSampler, coords + vec2(3.95*w, 0.11*h))*0.31;
  84. col += texture2D(textureSampler, coords + vec2(-3.07*w, 2.65*h))*0.26;
  85. col += texture2D(textureSampler, coords + vec2(0.48*w, -4.13*h))*0.22;
  86. col += texture2D(textureSampler, coords + vec2(2.49*w, 3.46*h))*0.15;
  87. total_weight += 2.97;
  88. }
  89. col /= total_weight; // scales color according to weights
  90. col.a = 1.0;
  91. // blur levels debug
  92. // if(blur_level == 1.0) { col.b = 0.0; }
  93. // if(blur_level == 2.0) { col.r = 0.0; }
  94. // if(blur_level == 3.0) { col.g = 0.0; }
  95. return col;
  96. }
  97. // on-the-fly constant noise
  98. vec2 rand(vec2 co)
  99. {
  100. float noise1 = (fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453));
  101. float noise2 = (fract(sin(dot(co, vec2(12.9898, 78.233)*2.0)) * 43758.5453));
  102. return clamp(vec2(noise1, noise2), 0.0, 1.0);
  103. }
  104. void main(void)
  105. {
  106. // Common calc
  107. centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
  108. radius2 = centered_screen_pos.x*centered_screen_pos.x + centered_screen_pos.y*centered_screen_pos.y;
  109. radius = sqrt(radius2);
  110. vec4 final_color;
  111. vec2 distorted_coords = getDistortedCoords(vUV);
  112. vec2 texels_coords = vec2(vUV.x * screen_width, vUV.y * screen_height); // varies from 0 to SCREEN_WIDTH or _HEIGHT
  113. // blur from depth of field effect
  114. float dof_blur_amount = 0.0;
  115. float depth_bias = 0.0; // positive if the pixel is further than focus depth; negative if closer
  116. if (focus_depth != -1.0) {
  117. vec4 depth_sample = texture2D(depthSampler, distorted_coords);
  118. float depth = depth_sample.r;
  119. depth_bias = depth - focus_depth;
  120. // compute blur amount with distance
  121. if (depth_bias > 0.0) { dof_blur_amount = depth_bias * aperture * 2.2; }
  122. else { dof_blur_amount = depth_bias * depth_bias * aperture * 30.0; }
  123. if (dof_blur_amount < 0.05) { dof_blur_amount = 0.0; } // no blur at all
  124. }
  125. // blur from edge blur effect
  126. float edge_blur_amount = 0.0;
  127. if (edge_blur > 0.0) {
  128. edge_blur_amount = clamp((radius*2.0 - 1.0 + 0.15*edge_blur) * 1.5, 0.0, 1.0) * 1.3;
  129. }
  130. // total blur amount
  131. float blur_amount = max(edge_blur_amount, dof_blur_amount);
  132. // apply blur if necessary
  133. if (blur_amount == 0.0) {
  134. gl_FragColor = texture2D(textureSampler, distorted_coords);
  135. }
  136. else {
  137. // add blurred color
  138. gl_FragColor = getBlurColor(distorted_coords, blur_amount * 1.7);
  139. // if further than focus depth & we have computed highlights: enhance highlights
  140. if (depth_bias > 0.0 && highlights) {
  141. gl_FragColor += clamp(dof_blur_amount, 0.0, 1.0)*texture2D(highlightsSampler, distorted_coords);
  142. }
  143. if (blur_noise) {
  144. // we put a slight amount of noise in the blurred color
  145. vec2 noise = rand(distorted_coords) * 0.01 * blur_amount;
  146. vec2 blurred_coord = vec2(distorted_coords.x + noise.x, distorted_coords.y + noise.y);
  147. gl_FragColor = 0.04 * texture2D(textureSampler, blurred_coord) + 0.96 * gl_FragColor;
  148. }
  149. }
  150. // apply grain
  151. if (grain_amount > 0.0) {
  152. vec4 grain_color = texture2D(grainSampler, texels_coords*0.003);
  153. gl_FragColor.rgb += (-0.5 + grain_color.rgb) * 0.20;
  154. }
  155. }