sRGBEncoding Makes the Whole Scene White

As can be seen in the picture, I followed the GLTFLoader guide and set my renderer’s outputEncoding to THREE.sRGBEncoding, but the scene turned very bright/white. The model however looked great, but just the model.

Also, the blocks in the background and the sky aren’t lit by any light as they use their custom ShaderMaterial.

Here’s what it should’ve looked like:

Anyone have any idea what is going on?

It’s important to understand that sRGB is part of a larger color management workflow, it is not a standalone fix to make things look nice. If you’ve already chosen the other colors in your scene to look a certain way without the correct output encoding in place, they will certainly look wrong once you fix the output encoding.

Any colors that looked right before this change were, presumably, already sRGB colors. Because you’ve added a Linear-sRGB to sRGB transform at the end of the render process, you need to make sure those are converted to Linear-sRGB first. You can do this manually with methods like color.convertSRGBToLinear, or more automatically with…

THREE.ColorManagement.legacyMode = false;

… which ensures that any hexadecimal colors in your scene (e.g. 0xFFEEFF) are understood to be in the sRGB color space and converted accordingly. If you’re working with vertex colors here, making these adjustments may be a bit more involved.

Resources —

1 Like

Thank you for the reply.

THREE.ColorManagement.legacyMode = false;

This code snippet didn’t work for me, as it said that ColorManagement isn’t exported from THREE. What should I do instead? Thank you.

The ColorManagement export was added in three.js r139. In earlier versions, you’d need to either choose your material colors in Linear-sRGB color space to start, or convert them from sRGB to Linear-sRGB explicitly:

material.color.setHex( 0x4285f4 ).convertSRGBToLinear();


Does this mean I’m on r142? I don’t see it in the exports :confused:

Got it to work by setting the GLTF children’s material’s map to use THREE.LinearEncoding

Looking good!

There should be another entry for three, rather than @types/three. That version number is the one you want.

Got it to work by setting the GLTF children’s material’s map to use THREE.LinearEncoding

Ok, just be aware this is the “gamma-incorrect” workflow warned about in Color management in three.js as well as What every coder should know about gamma | John Novak. Games sometimes get away with it, but it does contribute to a plasticky look and less manageable lighting. It’s certainly harder to fix this later in the process, but if you start with sRGB outputEncoding, it’s easier to get the look you want later.

I did have “three” installed too, also on r142, but I don’t see ColorManagement exported.

that would be very odd, it is right there:

exports.ColorManagement = ColorManagement;

i think it might have bigger issues than color, probably wrong import syntax pulling in multiple threes with varying versions.

this will give you results close to what you see in blender:

THREE.ColorManagement.legacyMode = false

gl.outputEncoding = THREE.sRGBEndicong
gl.toneMapping = THREE.ACESFilmicToneMapping

and if you set a texture yourself:

texture.encoding = THREE.sRGBEncoding
material.toneMapped = false

i would also recommend weening off from LinearEncoding, to me this was the biggest key to good looking scenes, whereas before i struggled a lot with that fake cgi plastic look that i just couldn’t shake off.

1 Like

Butting in here to get this straight: using .convertSRGBToLinear(); is no longer necessary if we set legacyMode to false?

(Using three-fiber here, so it might be hidden elsewhere, but yeah)

With legacyMode=false (which i think R3F does by default now), three.js will automatically understand that hexadecimal and CSS-string colors are sRGB. So if you’re doing something like this…

// (A)
material.color.setHex( 0xFFEEEE );

// (B)
material.color = new THREE.Color( 0xFFEEEE );

// (C)
material.color = new THREE.Color( 'green' );

… then you don’t need to worry about including convertSRGBToLinear(), it happens automatically. If you’re working with the RGB components, like color.r = 0.5 then just understand you are working with Linear-sRGB components and no conversions are being made to those inputs.

1 Like