opengl_fragment.glsl 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #define exposure texture0
  2. #define screen texture1
  3. struct ExposureParams {
  4. float luminanceMin;
  5. float luminanceMax;
  6. float exposureCorrection;
  7. float luminanceKey;
  8. float speedDarkBright;
  9. float speedBrightDark;
  10. float centerWeightPower;
  11. float compensationFactor;
  12. };
  13. uniform sampler2D exposure;
  14. uniform sampler2D screen;
  15. #ifdef ENABLE_BLOOM
  16. uniform float bloomStrength;
  17. #else
  18. const float bloomStrength = 1.0;
  19. #endif
  20. uniform ExposureParams exposureParams;
  21. uniform float animationTimerDelta;
  22. const vec3 luminanceFactors = vec3(0.213, 0.715, 0.072);
  23. float getLuminance(vec3 color)
  24. {
  25. return dot(color, luminanceFactors);
  26. }
  27. void main(void)
  28. {
  29. float previousExposure = texture2D(exposure, vec2(0.5, 0.5)).r;
  30. vec3 averageColor = vec3(0.);
  31. float n = 0.;
  32. // Scan the screen with center-weighting and sample average color
  33. for (float _x = 0.1; _x < 0.9; _x += 0.17) {
  34. float x = pow(_x, exposureParams.centerWeightPower);
  35. for (float _y = 0.1; _y < 0.9; _y += 0.17) {
  36. float y = pow(_y, exposureParams.centerWeightPower);
  37. averageColor += texture2D(screen, vec2(0.5 + 0.5 * x, 0.5 + 0.5 * y)).rgb;
  38. averageColor += texture2D(screen, vec2(0.5 + 0.5 * x, 0.5 - 0.5 * y)).rgb;
  39. averageColor += texture2D(screen, vec2(0.5 - 0.5 * x, 0.5 + 0.5 * y)).rgb;
  40. averageColor += texture2D(screen, vec2(0.5 - 0.5 * x, 0.5 - 0.5 * y)).rgb;
  41. n += 4.;
  42. }
  43. }
  44. float luminance = getLuminance(averageColor);
  45. luminance /= n;
  46. luminance /= pow(2., previousExposure) * bloomStrength * exposureParams.compensationFactor; // compensate for the configurable factors
  47. luminance = clamp(luminance, exposureParams.luminanceMin, exposureParams.luminanceMax);
  48. // From https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/course-notes-moving-frostbite-to-pbr-v2.pdf
  49. // 1. EV100 = log2(luminance * S / K) where S = 100, K = 0.125 = log2(luminance) + 3
  50. // 2. Lmax = 1.2 * 2 ^ (EV100 - EC)
  51. // => Lmax = 1.2 * 2^3 * luminance / 2^EC = 9.6 * luminance / 2^EC
  52. // 3. exposure = 1 / Lmax
  53. // => exposure = 2^EC / (9.6 * luminance)
  54. float wantedExposure = exposureParams.exposureCorrection - log(luminance)/0.693147180559945 - 3.263034405833794;
  55. if (wantedExposure < previousExposure)
  56. wantedExposure = mix(wantedExposure, previousExposure, exp(-animationTimerDelta * exposureParams.speedDarkBright)); // dark -> bright
  57. else
  58. wantedExposure = mix(wantedExposure, previousExposure, exp(-animationTimerDelta * exposureParams.speedBrightDark)); // bright -> dark
  59. gl_FragColor = vec4(vec3(wantedExposure), 1.);
  60. }