Chaque espace couleur est une collection de plusieurs décisions de conception, choisies ensemble pour prendre en charge une vaste gamme de couleurs tout en satisfaisant aux contraintes techniques liées à la précision et aux technologies d'affichage. Lors de la création d'un actif 3D, ou de l'assemblage d'actifs 3D dans une scène, il est important de connaître ces propriétés et la façon dont les propriétés d'un espace couleur sont liées aux autres espaces couleur de la scène.
Considérez deux espaces couleur très courants : `SRGBColorSpace` ("sRGB") et `LinearSRGBColorSpace` ("Linear-sRGB"). Les deux utilisent les mêmes primaires et le même point blanc, et ont donc le même gamut de couleur. Les deux utilisent le modèle de couleur RGB. Ils ne diffèrent que par les fonctions de transfert — Linear-sRGB est linéaire par rapport à l'intensité lumineuse physique. sRGB utilise les fonctions de transfert sRGB non linéaires, et ressemble plus étroitement à la façon dont l'œil humain perçoit la lumière et à la réactivité des périphériques d'affichage courants.
Cette différence est importante. Les calculs d'éclairage et autres opérations de rendu doivent généralement avoir lieu dans un espace couleur linéaire. Cependant, les couleurs linéaires sont moins efficaces pour être stockées dans une image ou un framebuffer, et ne paraissent pas correctes lorsqu'elles sont visualisées par un observateur humain. En conséquence, les textures d'entrée et l'image finale rendue utiliseront généralement l'espace couleur sRGB non linéaire.
ℹ️ AVIS : Bien que certains écrans modernes prennent en charge des gamuts plus larges comme Display-P3, les API graphiques de la plateforme web reposent largement sur sRGB. Les applications utilisant three.js aujourd'hui utiliseront généralement uniquement les espaces couleur sRGB et Linear-sRGB.
Les flux de travail linéaires — requis pour les méthodes de rendu modernes — impliquent généralement plus d'un espace couleur, chacun assigné à un rôle particulier. Les espaces couleur linéaires et non linéaires sont appropriés pour différents rôles, expliqués ci-dessous.
Les couleurs fournies à three.js — à partir de sélecteurs de couleur, de textures, de modèles 3D et d'autres sources — ont chacune un espace couleur associé. Celles qui ne sont pas déjà dans l'espace couleur de travail Linear-sRGB doivent être converties, et les textures doivent recevoir l'affectation correcte texture.colorSpace. Certaines conversions (pour les couleurs hexadécimales et CSS en sRGB) peuvent être effectuées automatiquement si l'API THREE.ColorManagement est activée avant l'initialisation des couleurs :
THREE.ColorManagement.enabled = true;
THREE.ColorManagement est activé par défaut.
⚠️ AVERTISSEMENT : De nombreux formats de modèles 3D ne définissent pas correctement ou de manière cohérente les informations d'espace couleur. Bien que three.js tente de gérer la plupart des cas, les problèmes sont fréquents avec les anciens formats de fichiers. Pour de meilleurs résultats, utilisez glTF 2.0 (`GLTFLoader`) et testez les modèles 3D dans des visualiseurs en ligne tôt pour confirmer que l'actif lui-même est correct.
Le rendu, l'interpolation et de nombreuses autres opérations doivent être effectuées dans un espace couleur de travail linéaire en domaine ouvert, dans lequel les composants RGB sont proportionnels à l'illumination physique. Dans three.js, l'espace couleur de travail est Linear-sRGB.
La sortie vers un périphérique d'affichage, une image ou une vidéo peut impliquer une conversion de l'espace couleur de travail Linear-sRGB en domaine ouvert vers un autre espace couleur. La conversion est définie par (`WebGLRenderer.outputColorSpace`). Lors de l'utilisation du post-traitement, cela nécessite OutputPass.
⚠️ AVERTISSEMENT : Les cibles de rendu peuvent utiliser soit sRGB soit Linear-sRGB. sRGB utilise mieux la précision limitée. Dans le domaine fermé, 8 bits suffisent souvent pour sRGB tandis que ≥12 bits (half float) peuvent être nécessaires pour Linear-sRGB. Si les étapes ultérieures du pipeline nécessitent une entrée Linear-sRGB, les conversions supplémentaires peuvent entraîner un léger coût de performance.
Les matériaux personnalisés basés sur `ShaderMaterial` et `RawShaderMaterial` doivent implémenter leur propre conversion d'espace couleur de sortie. Pour les instances de `ShaderMaterial`, ajouter le chunk de shader `colorspace_fragment` à la fonction `main()` du shader de fragment devrait être suffisant.
Les méthodes lisant ou modifiant des instances `Color` supposent que les données sont déjà dans l'espace couleur de travail de three.js, Linear-sRGB. Les composants RGB et HSL sont des représentations directes des données stockées par l'instance Color, et ne sont jamais convertis implicitement. Les données de couleur peuvent être explicitement converties avec .convertLinearToSRGB() ou .convertSRGBToLinear().
// RGB components (no change). color.r = color.g = color.b = 0.5; console.log( color.r ); // → 0.5 // Manual conversion. color.r = 0.5; color.convertSRGBToLinear(); console.log( color.r ); // → 0.214041140
Avec ColorManagement.enabled = true (recommandé), certaines conversions sont effectuées automatiquement. Comme les couleurs hexadécimales et CSS sont généralement sRGB, les méthodes `Color` convertiront automatiquement ces entrées de sRGB vers Linear-sRGB dans les setters, ou convertiront de Linear-sRGB vers sRGB lors du retour d'une sortie hexadécimale ou CSS à partir des getters.
// Hexadecimal conversion. color.setHex( 0x808080 ); console.log( color.r ); // → 0.214041140 console.log( color.getHex() ); // → 0x808080 // CSS conversion. color.setStyle( 'rgb( 0.5, 0.5, 0.5 )' ); console.log( color.r ); // → 0.214041140 // Override conversion with 'colorSpace' argument. color.setHex( 0x808080, LinearSRGBColorSpace ); console.log( color.r ); // → 0.5 console.log( color.getHex( LinearSRGBColorSpace ) ); // → 0x808080 console.log( color.getHex( SRGBColorSpace ) ); // → 0xBCBCBC
Lorsqu'une couleur ou une texture individuelle est mal configurée, elle apparaîtra plus foncée ou plus claire que prévu. Lorsque l'espace couleur de sortie du renderer est mal configuré, toute la scène peut apparaître plus foncée (par exemple, conversion manquante vers sRGB) ou plus claire (par exemple, une double conversion vers sRGB avec post-traitement). Dans chaque cas, le problème peut ne pas être uniforme, et simplement augmenter/diminuer l'éclairage ne le résout pas.
Un problème plus subtil apparaît lorsque à la fois les espaces couleur d'entrée et les espaces couleur de sortie sont incorrects — les niveaux de luminosité globaux peuvent être corrects, mais les couleurs peuvent changer de manière inattendue sous différents éclairages, ou l'ombrage peut sembler plus brûlé et moins doux que prévu. Ces deux erreurs ne font pas une seule bonne chose, et il est important que l'espace couleur de travail soit linéaire ("référé à la scène") et l'espace couleur de sortie soit non linéaire ("référé à l'affichage").