depthOfField.fragment.fx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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 bool blur_noise;
  16. uniform float screen_width;
  17. uniform float screen_height;
  18. uniform float distortion;
  19. uniform bool dof_enabled;
  20. //uniform float focus_distance; // not needed; already used to compute screen distance
  21. uniform float screen_distance; // precomputed screen distance from lens center; based on focal length & desired focus distance
  22. uniform float aperture;
  23. uniform float darken;
  24. uniform float edge_blur;
  25. uniform bool highlights;
  26. // preconputed uniforms (not effect parameters)
  27. uniform float near;
  28. uniform float far;
  29. // varyings
  30. varying vec2 vUV;
  31. // constants
  32. #define PI 3.14159265
  33. #define TWOPI 6.28318530
  34. #define inverse_focal_length 0.1 // a property of the lens used
  35. // common calculations
  36. vec2 centered_screen_pos;
  37. vec2 distorted_coords;
  38. float radius2;
  39. float radius;
  40. // on-the-fly constant noise
  41. vec2 rand(vec2 co)
  42. {
  43. float noise1 = (fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453));
  44. float noise2 = (fract(sin(dot(co, vec2(12.9898, 78.233)*2.0)) * 43758.5453));
  45. return clamp(vec2(noise1, noise2), 0.0, 1.0);
  46. }
  47. // applies edge distortion on texture coords
  48. vec2 getDistortedCoords(vec2 coords) {
  49. if (distortion == 0.0) { return coords; }
  50. vec2 direction = 1.0 * normalize(centered_screen_pos);
  51. vec2 dist_coords = vec2(0.5, 0.5);
  52. dist_coords.x = 0.5 + direction.x * radius2 * 1.0;
  53. dist_coords.y = 0.5 + direction.y * radius2 * 1.0;
  54. float dist_amount = clamp(distortion*0.23, 0.0, 1.0);
  55. dist_coords = mix(coords, dist_coords, dist_amount);
  56. return dist_coords;
  57. }
  58. // sample screen with an offset (randomize offset angle for better smothness), returns partial sample weight
  59. float sampleScreen(inout vec4 color, const in vec2 offset, const in float weight) {
  60. // compute coords with offset (a random angle is added)
  61. vec2 coords = distorted_coords;
  62. float angle = rand(coords * 100.0).x * TWOPI;
  63. coords += vec2(offset.x * cos(angle) - offset.y * sin(angle), offset.x * sin(angle) + offset.y * cos(angle));
  64. color += texture2D(textureSampler, coords)*weight;
  65. return weight;
  66. }
  67. // returns blur level according to blur size required
  68. float getBlurLevel(float size) {
  69. return min(3.0, ceil(size / 1.0));
  70. }
  71. // returns original screen color after blur
  72. vec4 getBlurColor(float size) {
  73. vec4 col = texture2D(textureSampler, distorted_coords);
  74. if (size == 0.0) { return col; }
  75. // there are max. 30 samples; the number of samples chosen is dependant on the blur size
  76. // there can be 10, 20 or 30 samples chosen; levels of blur are then 1, 2 or 3
  77. float blur_level = getBlurLevel(size);
  78. float w = (size / screen_width);
  79. float h = (size / screen_height);
  80. float total_weight = 1.0;
  81. vec2 sample_coords;
  82. total_weight += sampleScreen(col, vec2(-0.50*w, 0.24*h), 0.93);
  83. total_weight += sampleScreen(col, vec2(0.30*w, -0.75*h), 0.90);
  84. total_weight += sampleScreen(col, vec2(0.36*w, 0.96*h), 0.87);
  85. total_weight += sampleScreen(col, vec2(-1.08*w, -0.55*h), 0.85);
  86. total_weight += sampleScreen(col, vec2(1.33*w, -0.37*h), 0.83);
  87. total_weight += sampleScreen(col, vec2(-0.82*w, 1.31*h), 0.80);
  88. total_weight += sampleScreen(col, vec2(-0.31*w, -1.67*h), 0.78);
  89. total_weight += sampleScreen(col, vec2(1.47*w, 1.11*h), 0.76);
  90. total_weight += sampleScreen(col, vec2(-1.97*w, 0.19*h), 0.74);
  91. total_weight += sampleScreen(col, vec2(1.42*w, -1.57*h), 0.72);
  92. if (blur_level > 1.0) {
  93. total_weight += sampleScreen(col, vec2(0.01*w, 2.25*h), 0.70);
  94. total_weight += sampleScreen(col, vec2(-1.62*w, -1.74*h), 0.67);
  95. total_weight += sampleScreen(col, vec2(2.49*w, 0.20*h), 0.65);
  96. total_weight += sampleScreen(col, vec2(-2.07*w, 1.61*h), 0.63);
  97. total_weight += sampleScreen(col, vec2(0.46*w, -2.70*h), 0.61);
  98. total_weight += sampleScreen(col, vec2(1.55*w, 2.40*h), 0.59);
  99. total_weight += sampleScreen(col, vec2(-2.88*w, -0.75*h), 0.56);
  100. total_weight += sampleScreen(col, vec2(2.73*w, -1.44*h), 0.54);
  101. total_weight += sampleScreen(col, vec2(-1.08*w, 3.02*h), 0.52);
  102. total_weight += sampleScreen(col, vec2(-1.28*w, -3.05*h), 0.49);
  103. }
  104. if (blur_level > 2.0) {
  105. total_weight += sampleScreen(col, vec2(3.11*w, 1.43*h), 0.46);
  106. total_weight += sampleScreen(col, vec2(-3.36*w, 1.08*h), 0.44);
  107. total_weight += sampleScreen(col, vec2(1.80*w, -3.16*h), 0.41);
  108. total_weight += sampleScreen(col, vec2(0.83*w, 3.65*h), 0.38);
  109. total_weight += sampleScreen(col, vec2(-3.16*w, -2.19*h), 0.34);
  110. total_weight += sampleScreen(col, vec2(3.92*w, -0.53*h), 0.31);
  111. total_weight += sampleScreen(col, vec2(-2.59*w, 3.12*h), 0.26);
  112. total_weight += sampleScreen(col, vec2(-0.20*w, -4.15*h), 0.22);
  113. total_weight += sampleScreen(col, vec2(3.02*w, 3.00*h), 0.15);
  114. }
  115. col /= total_weight; // scales color according to weights
  116. // darken if out of focus
  117. if(darken > 0.0) {
  118. col.rgb *= clamp(0.3, 1.0, 1.05-size*0.5*darken);
  119. }
  120. // blur levels debug
  121. // if(blur_level == 1.0) { col.b *= 0.5; }
  122. // if(blur_level == 2.0) { col.r *= 0.5; }
  123. // if(blur_level == 3.0) { col.g *= 0.5; }
  124. return col;
  125. }
  126. void main(void)
  127. {
  128. // Common calc: position relative to screen center, screen radius, distorted coords, position in texel space
  129. centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
  130. radius2 = centered_screen_pos.x*centered_screen_pos.x + centered_screen_pos.y*centered_screen_pos.y;
  131. radius = sqrt(radius2);
  132. distorted_coords = getDistortedCoords(vUV); // we distort the screen coordinates (lens "magnifying" effect)
  133. vec2 texels_coords = vec2(vUV.x * screen_width, vUV.y * screen_height); // varies from 0 to SCREEN_WIDTH or _HEIGHT
  134. float depth = texture2D(depthSampler, distorted_coords).r; // depth value from DepthRenderer: 0 to 1
  135. float distance = near + (far-near)*depth; // actual distance from the lens
  136. vec4 color = texture2D(textureSampler, vUV); // original raster
  137. // compute the circle of confusion size (CoC), i.e. blur radius depending on depth
  138. // screen_distance is precomputed in code
  139. float coc = abs( aperture * ( screen_distance * ( inverse_focal_length - 1.0 / distance ) - 1.0 ) );
  140. // disable blur
  141. if (dof_enabled == false || coc < 0.07) { coc = 0.0; }
  142. // blur from edge blur effect
  143. float edge_blur_amount = 0.0;
  144. if (edge_blur > 0.0) {
  145. edge_blur_amount = clamp((radius*2.0 - 1.0 + 0.15*edge_blur) * 1.5, 0.0, 1.0) * 1.3;
  146. }
  147. // total blur amount
  148. float blur_amount = max(edge_blur_amount, coc);
  149. // apply blur if necessary
  150. if (blur_amount == 0.0) {
  151. gl_FragColor = texture2D(textureSampler, distorted_coords);
  152. }
  153. else {
  154. // add blurred color
  155. gl_FragColor = getBlurColor(blur_amount * 1.7);
  156. // if we have computed highlights: enhance highlights
  157. if (highlights) {
  158. gl_FragColor.rgb += clamp(coc, 0.0, 1.0)*texture2D(highlightsSampler, distorted_coords).rgb;
  159. }
  160. if (blur_noise) {
  161. // we put a slight amount of noise in the blurred color
  162. vec2 noise = rand(distorted_coords) * 0.01 * blur_amount;
  163. vec2 blurred_coord = vec2(distorted_coords.x + noise.x, distorted_coords.y + noise.y);
  164. gl_FragColor = 0.04 * texture2D(textureSampler, blurred_coord) + 0.96 * gl_FragColor;
  165. }
  166. }
  167. // apply grain
  168. if (grain_amount > 0.0) {
  169. vec4 grain_color = texture2D(grainSampler, texels_coords*0.003);
  170. gl_FragColor.rgb += (-0.5 + grain_color.rgb) * 0.30 * grain_amount;
  171. }
  172. }