Three.js Color Space Conversion Guide
Managing color spaces correctly is crucial for achieving realistic
rendering in 3D web applications. This article provides a
straightforward guide on how to perform color space conversions using
the built-in Color class in Three.js, ensuring your colors
look consistent across different devices and render pipelines.
Modern Three.js Color Management
In modern Three.js (version r152 and later), color management is
enabled by default via
THREE.ColorManagement.enabled = true. This setting ensures
that Three.js automatically converts color inputs—such as CSS strings,
hex values, and RGB components—from the sRGB color space into the
Linear-sRGB working color space used for lighting calculations.
Manual Conversion with the Color Class
If you need to perform manual color space conversions, the
THREE.Color class provides built-in utility methods. These
are essential when working with raw shaders or legacy codebases where
automatic color management is disabled.
1. Converting sRGB to Linear Space
To convert a color from the standard sRGB space (used by most digital displays and image formats) to linear space for rendering calculations:
import * as THREE from 'three';
// Create a color using sRGB values (e.g., bright red)
const color = new THREE.Color('#ff0000');
// Convert the color from sRGB to Linear-sRGB
color.convertSRGBToLinear();2. Converting Linear to sRGB Space
To convert a color from the linear working space back to sRGB (useful for UI overlays, exporting data, or console logging):
// Convert the color from Linear-sRGB back to sRGB
color.convertLinearToSRGB();Best Practices for Textures and Renderer
For correct color space rendering, your manual conversions must align with your renderer and texture settings.
Renderer Configuration
Ensure your WebGLRenderer is configured to output the
sRGB color space:
const renderer = new THREE.WebGLRenderer();
renderer.outputColorSpace = THREE.SRGBColorSpace;Texture Color Space
Always specify the correct color space for your textures. Color maps
(such as diffuse or albedo textures) should use
SRGBColorSpace, while data-centric maps (such as normal,
roughness, or metalness maps) must remain in NoColorSpace
(linear):
const textureLoader = new THREE.TextureLoader();
// Color texture (requires sRGB conversion)
const colorTexture = textureLoader.load('color.jpg');
colorTexture.colorSpace = THREE.SRGBColorSpace;
// Normal map (remains linear)
const normalTexture = textureLoader.load('normal.jpg');
normalTexture.colorSpace = THREE.NoColorSpace;