sRGBEncoding with post-processing

I was reading this article Color management in three.js · GitHub which recommends our projects use renderer.outputEncoding = THREE.sRGBEncoding; for realistic color management. Everything was looking great, until I started adding the Bloom post-processing effect and FXAA via the effect composer.

  • Bloom with threshold = 1 should have no effect, yet it makes the scene.background color brighter.
  • FXAA makes everything really dark.

The article I linked to explains this behavior:

Renderer should have .outputEncoding = sRGBEncoding if no post-processing is used, otherwise use LinearEncoding and apply gamma correction (TBD) as last pass in post instead.

I used LinearEncoding, but everything looks dark & saturated now. So my question is, how do I enable this encoding in the post-processing pass? I see a function in both Unreal and FXAA shaders:

vec4 LinearTosRGB( in vec4 value ) {
    return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
}

… but it doesn’t get implemented anywhere.

1 Like

It’s not so clear in the docs but you can use the GammaCorrectionShader like so:

const gammaCorrectionPass = new ShaderPass( GammaCorrectionShader );
composer.addPass( gammaCorrectionPass );

Keep in mind it’s not exactly like outputEncoding = sRGBEncoding, though, because Fog and Scene.background need to be manually converted to linear color space otherwise they’ll look incorrect.

3 Likes

Have a look at this thread Effect Composer Gamma Output Difference

A lot of useful info relating color spaces and postprocessing was shared there, especially in some of Looee’s answers

2 Likes

I’m confused about the difference between

  • render.outputEncoding = THREE.sRGBEncoding
  • render.gammaFactor = 2.2;

Is sRGBencoding and 2.2 gamma just two different ways of describing the same color-space? If I say gamma 1.0, is it identical as saying “linear encoding”? I hear them used interchangeably all the time.

I made a pen that demonstrates the correct settings for rendering with either EffectComposer + GammaCorrectionPass, or plain WebGLRenderer:

If you have the settings right, then the sphere will blend perfectly into the packground AND the color will exactly match CSS #4285f4

It doesn’t cover textures or fog, but shows correct settings for the renderer, material.color and scene.background.

5 Likes

No, they are similar but not exactly the same. Gamma is just a really simple exponent curve. My understanding is that sRGB was created since simple gamma correction gives bad results in lower end (near black). So sRGB is (nearly?) the same as gamma 2.2 everywhere except in the blacks.

Gamma curve:

gamma_function_graph

The function linear to gamma 2.2 is really simple. Just do x^{\frac{1}{2.2}} where x is r,g and b.

sRGB curve:

512px-SRGB_gamma.svg

The function linear to sRGB is more complex and changes when the color is near black:

3 Likes

@looeee is there also a step we need to do to fix canvas textures?

sandbox: https://codesandbox.io/s/r3f-lod-50y03 (Shadow.js)

the shadows underneath the models are gradients, but as soon as i switch on effects and gamma correction they turn into circles.

I think they still are gradients, it’s just that it’s not obvious when the background is so dark.

Here’s a screenshots against a lighter background:

The only thing I changed was the background color:

scene.background = new THREE.Color('#555555')

There’s some banding in the canvas texture, not sure what’s causing that though.

I’m currently struggling with the colorCorrectionShader, to be precise it works fine on the mesh texture but washes out the saturation from the background (and also the shadow below the object).

Can you provide a code example for the manually conversion for the background color space? Thanks