opengl_fragment.glsl 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #define rendered texture0
  2. #define depthmap texture1
  3. uniform sampler2D rendered;
  4. uniform sampler2D depthmap;
  5. uniform vec3 sunPositionScreen;
  6. uniform float sunBrightness;
  7. uniform vec3 moonPositionScreen;
  8. uniform float moonBrightness;
  9. uniform lowp float volumetricLightStrength;
  10. uniform vec3 dayLight;
  11. #ifdef ENABLE_DYNAMIC_SHADOWS
  12. uniform vec3 v_LightDirection;
  13. #else
  14. const vec3 v_LightDirection = vec3(0.0, -1.0, 0.0);
  15. #endif
  16. #ifdef GL_ES
  17. varying mediump vec2 varTexCoord;
  18. #else
  19. centroid varying vec2 varTexCoord;
  20. #endif
  21. const float far = 1000.;
  22. float mapDepth(float depth)
  23. {
  24. return min(1., 1. / (1.00001 - depth) / far);
  25. }
  26. float noise(vec3 uvd) {
  27. return fract(dot(sin(uvd * vec3(13041.19699, 27723.29171, 61029.77801)), vec3(73137.11101, 37312.92319, 10108.89991)));
  28. }
  29. float sampleVolumetricLight(vec2 uv, vec3 lightVec, float rawDepth)
  30. {
  31. lightVec = 0.5 * lightVec / lightVec.z + 0.5;
  32. const float samples = 30.;
  33. float result = texture2D(depthmap, uv).r < 1. ? 0.0 : 1.0;
  34. float bias = noise(vec3(uv, rawDepth));
  35. vec2 samplepos;
  36. for (float i = 1.; i < samples; i++) {
  37. samplepos = mix(uv, lightVec.xy, (i + bias) / samples);
  38. if (min(samplepos.x, samplepos.y) > 0. && max(samplepos.x, samplepos.y) < 1.)
  39. result += texture2D(depthmap, samplepos).r < 1. ? 0.0 : 1.0;
  40. }
  41. // We use the depth map to approximate the effect of depth on the light intensity.
  42. // The exponent was chosen based on aesthetic preference.
  43. return result / samples * pow(texture2D(depthmap, uv).r, 128.0);
  44. }
  45. vec3 getDirectLightScatteringAtGround(vec3 v_LightDirection)
  46. {
  47. // Based on talk at 2002 Game Developers Conference by Naty Hoffman and Arcot J. Preetham
  48. const float beta_r0 = 1e-5; // Rayleigh scattering beta
  49. // These factors are calculated based on expected value of scattering factor of 1e-5
  50. // for Nitrogen at 532nm (green), 2e25 molecules/m3 in atmosphere
  51. const vec3 beta_r0_l = vec3(3.3362176e-01, 8.75378289198826e-01, 1.95342379700656) * beta_r0; // wavelength-dependent scattering
  52. const float atmosphere_height = 15000.; // height of the atmosphere in meters
  53. // sun/moon light at the ground level, after going through the atmosphere
  54. return exp(-beta_r0_l * atmosphere_height / (1e-5 - dot(v_LightDirection, vec3(0., 1., 0.))));
  55. }
  56. vec3 applyVolumetricLight(vec3 color, vec2 uv, float rawDepth)
  57. {
  58. vec3 lookDirection = normalize(vec3(uv.x * 2. - 1., uv.y * 2. - 1., rawDepth));
  59. const float boost = 4.0;
  60. float brightness = 0.;
  61. vec3 sourcePosition = vec3(-1., -1., -1);
  62. if (sunPositionScreen.z > 0. && sunBrightness > 0.) {
  63. brightness = sunBrightness;
  64. sourcePosition = sunPositionScreen;
  65. }
  66. else if (moonPositionScreen.z > 0. && moonBrightness > 0.) {
  67. brightness = moonBrightness * 0.05;
  68. sourcePosition = moonPositionScreen;
  69. }
  70. float cameraDirectionFactor = pow(clamp(dot(sourcePosition, vec3(0., 0., 1.)), 0.0, 0.7), 2.5);
  71. float viewAngleFactor = pow(max(0., dot(sourcePosition, lookDirection)), 8.);
  72. float lightFactor = brightness * sampleVolumetricLight(uv, sourcePosition, rawDepth) *
  73. (0.05 * cameraDirectionFactor + 0.95 * viewAngleFactor);
  74. color = mix(color, boost * getDirectLightScatteringAtGround(v_LightDirection) * dayLight, lightFactor);
  75. // a factor of 5 tested well
  76. color *= volumetricLightStrength * 5.0;
  77. // if (sunPositionScreen.z < 0.)
  78. // color.rg += 1. - clamp(abs((2. * uv.xy - 1.) - sunPositionScreen.xy / sunPositionScreen.z) * 1000., 0., 1.);
  79. // if (moonPositionScreen.z < 0.)
  80. // color.rg += 1. - clamp(abs((2. * uv.xy - 1.) - moonPositionScreen.xy / moonPositionScreen.z) * 1000., 0., 1.);
  81. return color;
  82. }
  83. void main(void)
  84. {
  85. vec2 uv = varTexCoord.st;
  86. vec3 color = texture2D(rendered, uv).rgb;
  87. // translate to linear colorspace (approximate)
  88. color = pow(color, vec3(2.2));
  89. if (volumetricLightStrength > 0.0) {
  90. float rawDepth = texture2D(depthmap, uv).r;
  91. color = applyVolumetricLight(color, uv, rawDepth);
  92. }
  93. gl_FragColor = vec4(color, 1.0); // force full alpha to avoid holes in the image.
  94. }