Chapter 807: Color Management (Manual)
Core Idea
Three.js renders internally in a linear color space (Linear-sRGB) and converts to/from nonlinear sRGB at the input (textures, colors) and output (renderer) boundaries; getting this wrong makes a scene look uniformly too dark or too light, or subtly wrong under different lighting.
Key Concepts
- Color space: primaries + white point + transfer function together defining how numbers map to visible color.
- sRGB vs. Linear-sRGB: same gamut and primaries, different transfer function — sRGB is nonlinear and closer to human/display perception, Linear-sRGB is linear with respect to physical light.
- Working color space: the space lighting/shading math happens in — Linear-sRGB in three.js.
texture.colorSpace: tags a texture's input color space so it converts correctly into the working space.
WebGLRenderer.outputColorSpace: controls the conversion from the linear working space to the final display/output space.
THREE.ColorManagement: enabled by default; auto-converts hex and CSS colors (assumed sRGB) into the Linear-sRGB working space.
Code Examples
color.setHex(0x808080);
console.log(color.r); // linear value, not 0.5
color.setHex(0x808080, THREE.LinearSRGBColorSpace);
console.log(color.r); // → 0.5, no sRGB conversion applied
- What it demonstrates:
Color setters convert sRGB hex input to the linear working space by default, and accept an explicit color-space override.
Key Takeaways
- Lighting and shading calculations must happen in a linear color space; three.js's working space is Linear-sRGB.
- Textures and colors coming in, and the final rendered image going out, are usually nonlinear sRGB and need correct color-space tagging at each boundary.
- A misconfigured input or output color space shifts the whole scene uniformly darker or lighter; misconfiguring both at once can produce subtler, non-uniform color errors that don't show up as simple brightness problems.
- Custom
ShaderMaterial/RawShaderMaterial shaders must implement their own output color-space conversion — three.js won't do it for them automatically.
Connects To
- GLTFLoader: many older/non-glTF model formats don't reliably encode color-space info, which is a common source of color bugs.
- WebGLRenderer: owns
outputColorSpace.
- ShaderMaterial / RawShaderMaterial: need manual output color-space handling.