These are the maps in MeshPhysicalMaterial
:
map
aoMap
envMap
bumpMap
alphaMap
lightMap
normalMap
emissiveMap
clearcoatMap
roughnessMap
thicknessMap
metalnessMap
anisotropyMap
sheenColorMap
iridescenceMap
displacementMap
transmissionMap
specularColorMap
sheenRoughnessMap
clearcoatNormalMap
specularIntensityMap
clearcoatRoughnessMap
iridescenceThicknessMap
Which of these need to be in SRGBColorSpace
?
Which of them should be LinearSRGBColorSpace
?
Which of them should be NoColorSpace
?
The “Color Spaces” section of Core Constants mentions four of those maps are NoColorSpace
:
- normalMap
- roughnessMap
- metalnessMap
- ambientOcclusionMap
and other “data” textures (more may be inferred).
It then mentions to look at “Color management” (the mention is not linked), which mentions two more maps that need SRGBColorSpace
:
and two more that need LinearSRGBColorSpace
:
- sometimes envMap
- sometimes lightMap
The list is spread across two pages and not comprehensive. That’s 6, maybe 8, maps that we know the color space for.
When do envMap and lightMap not need LinearSRGBColorSpace
? How about the rest?
I would be great is MeshPhysicalMaterial
(and other materials) applied the correct color spaces by default, so that users don’t have to memorize all of them.
Either that, or the docs could have a definitive list of color spaces for all maps (default behavior would be nicer).
1 Like
So far I came up with this:
export const defaultColorSpaces = {
map: SRGBColorSpace, // ref: Color Management
aoMap: NoColorSpace, // ref: Core Constants
envMap: LinearSRGBColorSpace, // ref: Color Management
bumpMap: NoColorSpace,
alphaMap: NoColorSpace,
lightMap: LinearSRGBColorSpace, // ref: Color Management
normalMap: NoColorSpace, // ref: Core Constants
emissiveMap: SRGBColorSpace, // ref: Color Management
clearcoatMap: NoColorSpace,
roughnessMap: NoColorSpace, // ref: Core Constants
thicknessMap: NoColorSpace,
metalnessMap: NoColorSpace, // ref: Core Constants
anisotropyMap: NoColorSpace,
sheenColorMap: SRGBColorSpace,
iridescenceMap: NoColorSpace,
displacementMap: NoColorSpace,
transmissionMap: NoColorSpace,
specularColorMap: SRGBColorSpace,
sheenRoughnessMap: NoColorSpace,
clearcoatNormalMap: NoColorSpace,
specularIntensityMap: NoColorSpace,
clearcoatRoughnessMap: NoColorSpace,
iridescenceThicknessMap: NoColorSpace,
}
Is this correct?
1 Like
The only real requirement is that .colorSpace should tell three.js how the texture was exported. For example: it is entirely possible to export a .map
or .emissiveMap
texture using Linear-sRGB. Unusual, yes, but as long as you assign .colorSpace
accordingly, that’s fine!
But I think all of the material slot vs. color space mappings you listed do reflect the most common choices, and so if you’re not sure how the textures were exported, that’s a great starting point.
Personally, I think of it like this:
- non-color data: always
NoColorspace
- closed domain [0–1] color: typically
SRGBColorSpace
- open domain [0–infinity] color: typically
LinearSRGBColorSpace
That framing helps when thinking about color slots that can reasonably exceed [0–1], like .envMap, .lightMap, and .emissiveMap. If the texture’s format can represent values >1 (.exr, .hdr) then it’s very likely LinearSRGBColorSpace
. If the texture format is limited to [0–1] (PNG, JPG) then it’s very likely SRGBColorSpace
. But again, these are just heuristics to guess how the texture was likely exported.
6 Likes
That’s interesting. Thanks.
What I recall is that before the r151/r152 update that requires people manually specify .colorSpace
for every color texture, things were just easier for people getting into 3D with Three.js.
This easiness is reduced now, as colors aren’t exactly as good anymore without setting .colorSpace
manually IIRC.
Could it be worth having common color spaces be the default inside of Three.js to avoid having to always define them (makes Three.js easier to use out of the box), and let the experts opt into non-default values as they see fit?
Attempted and discussed in Material: Infer texture color space (WIP) by donmccurdy · Pull Request #25857 · mrdoob/three.js · GitHub. But I don’t really think there’s a path forward there, especially considering node-based materials and perhaps wide-gamut color in the future, which we cannot detect. It is necessary to keep track of which textures are used for color vs. for data and to set .colorSpace
accordingly. I do wish the web platform let us get color space metadata from the textures directly — which might help — but even then, the metadata is wildly unreliable.
You can turn all color management off, if you want to return to pre-r152 rendering, but that’s both technically and artistically worse for most use cases, in my opinion.
2 Likes