How to get the colors right for a simple texture with MeshBasicMaterial?


I’m trying to display this image with a meshBasicMaterial in this minimal demo (r155), but the colors are too pale when I don’t set the texture colorSpace, and too dark when I set it to THREE.SRGBColorSpace.

I’m confused because the colors were right in this demo using r125.

I feel stupid, what am I missing?


This post may help understanding changes that happened in latest releases - r125 is quite an old version of three, updating the example to r155 will require you to use colorSpace instead of encoding for textures and render targets / output.

Thanks for your reply.
I’m already familiar with the post you shared though.
I don’t know if you checked my demo, but I’m using colorSpace, not encoding, so that doesn’t answer my question, but thanks for trying to help!

(Also, I’m well aware that r125 is outdated; I merely used it as a reference because the colors were accurate there. I could also use the three.js editor since the colors are correct there as well, but I’m unsure which version it’s based on.)

This issue is unrelated to recent color management related changes to the engine. The change in behavior starts with r126:

r125: three.js dev template - module - JSFiddle - Code Playground
r126: three.js dev template - module - JSFiddle - Code Playground

Respective PR: WebGLRenderer: Avoid default color space conversion. by takahirox · Pull Request #21336 · mrdoob/three.js · GitHub

r125 and earlier versions set UNPACK_COLORSPACE_CONVERSION_WEBGL to BROWSER_DEFAULT_WEBGL which means embedded ICC profiles in images where honored. With r126, the configuration parameter was set to NONE to disable this behavior.

We wanted to stick to the glTF standard which states that any colorspace information (such as ICC profiles, intents, etc) from PNG or JPEG containers must be ignored. This was the motivation why the default of UNPACK_COLORSPACE_CONVERSION_WEBGL was changed globally.

@donmccurdy I evaluate this issue a bit differently compared to 2021. I wonder if we indeed need more flexibilty when defining textures. There was an intend to introduce a new texture property to control the UNPACK_COLORSPACE_CONVERSION_WEBGL flag (see Introduce Texture.colorSpaceConversion by takahirox · Pull Request #21324 · mrdoob/three.js · GitHub) but at this time it was decided to simply disable the default behavior. Do we need to revisit this issue? Could a new texture property be useful for Roadmap for supporting wide-gamut color workflows · Issue #26479 · mrdoob/three.js · GitHub?

1 Like

The source image uses the “ProPhoto RGB” wide gamut color space. It appears the web browser is able to do a lossy unpacking to sRGB, which (in older three.js versions) mapped the original wider gamut into sRGB, losing any data outside the smaller sRGB gamut. Now the wide-gamut data is treated as if it were already in sRGB, which results in the colors appearing muted.

I think our default is still OK, and that we cannot yet trust the browser or the source images to identify color spaces correctly. It’s very common to find non-color textures like normal maps, with an embedded ICC profile claiming otherwise. And in any case we need for texture.colorSpace to identify the color space correctly, which automatic browser inference would complicate.

I agree we’ll want the ability to enable unpack color space conversion, at least internally, as we begin to support wide gamut output color spaces. I’m not sure yet what that should look like, but we may not need a new property. Probably we can just look for the texture.colorSpace property, and if it uses a different gamut than ColorManagement.workingColorSpace, we enable unpack colorspace conversion. Examples that would require conversion:

  • texture.colorSpace = "srgb" + ColorManagement.workingColorSpace = "display-p3-linear"
  • texture.colorSpace = "display-p3" + ColorManagement.workingColorSpace = "srgb-linear"

In each case we unpack into the working color space gamut.

This should avoid breaking changes for existing scenes, but does mean that any users trying to get wide gamut rendering will need to be very careful about assigning texture.colorSpace correctly, AND using the matching ICC profile in their textures.


So if I understand correctly, if my image uses a wide gamut color space, the only solution for now would be to convert the image to sRGB (with Photoshop for instance).
It makes more sense to me now, and according to the test I just did, it works.
Thank you guys!

That’s correct for now, yes!

1 Like