Effect Composer Gamma Output Difference

I’ve run into this problem before when dealing with post-processing, and I confess, even after several days of studying color spaces and the tone mapping code in three.js, the only way I’ve been able to solve it is by guesswork.

I do think that there are some bugs in the way tone mapping is handled in the post-processing code, or if not, then the workflow needs to be improved and have much better documentation because it’s very confusing at the moment.

In the end, I solved this by disabling all color correction in three.js and adding my own final pass which does tone mapping/brightness/contrast.

EDIT: looks like I should also add gamma correction (or rather, sRGB transform) into this, after tone mapping and before brightness/contrast.

/*
 * Combined post-processing pass
 *
 * ACESFilmic Tone mapping
 * Brightness
 * Contrast
 *
*/

const CombinedShader = {

  uniforms: {

    tDiffuse: { value: null },
    toneMappingExposure: { value: 1.0 },
    brightness: { value: 0 },
    contrast: { value: 0 },

  },

  vertexShader:

  /* glsl */`
    varying vec2 vUv;

    void main() {

      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

    }`,

  fragmentShader:

  /* glsl */`
    #define saturate(a) clamp( a, 0.0, 1.0 )

    uniform sampler2D tDiffuse;

    uniform float toneMappingExposure;

    uniform float brightness;
    uniform float contrast;

    varying vec2 vUv;

    vec3 ACESFilmicToneMapping( vec3 color ) {

      color *= toneMappingExposure;
      return saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );

    }

    void main() {

      gl_FragColor = texture2D( tDiffuse, vUv );
      gl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb );

      gl_FragColor.rgb += brightness;

      if (contrast > 0.0) {
        gl_FragColor.rgb = (gl_FragColor.rgb - 0.5) / (1.0 - contrast) + 0.5;
      } else {
        gl_FragColor.rgb = (gl_FragColor.rgb - 0.5) * (1.0 + contrast) + 0.5;
      }

    } `,

};

export default CombinedShader;

I intend to add color correction to this as well, I’ve held off on that as I’m not sure whether it does before or after tonemapping.

2 Likes