THREE.NoColorSpace error

In three.js r157, when I added the following line of code:
[renderer.outputColorSpace = THREE.NoColorSpace;]

It resulted in an error when using renderer.render . However, when I changed it to:
renderer.outputColorSpace = THREE.SRGBColorSpace;

In r154, this error did not occur.

If it’s not a bug, I apologize for any inconvenience. :cat:

For reproduction: three.js dev template - module - JSFiddle - Code Playground

@donmccurdy I guess we did not anticipate someone would assign THREE.NoColorSpace to WebGLRenderer.outputColorSpace. IMO, outputColorSpace should only support color spaces which are compatible to the default framebuffer/canvas. Since we always display colors, THREE.NoColorSpace doesn’t make sense.

1 Like

Thank you for your response. I have prepared an image for reference. I prefer the color representation of NoColorSpace, but if it’s going to be discontinued, I’m considering using r154.

1 Like

Do you mind demonstrating with a live example what you are doing in your code?

Thank you very much. I forgot to mention that I mainly use MMDLoader for modeling and display. I have turned the code into an image.

Sorry, this isn’t a live example.

Besides, you should never share screenshots of code. This is a no-go in developer communities.

I’m not very familiar with programming, so I apologize. I don’t understand the term “live example.” :crying_cat_face:

I’ll go with r154 for now.

Thank you so much.

(I’m really sorry, I don’t speak English, so I’ve been using ChatGPT for translation.)
I’ve been working with Next.js, and because the output code has become hard to read, I’ll prepare a simple program within the next few days and provide a link. If you’d be willing, I’d appreciate it if you could take a look and find it helpful.

1 Like

A live example is something like this: three.js dev template - module - JSFiddle - Code Playground

It is editable, so we can easily apply fixes or test different solutions.

Since you experience a different behavior after the upgrade from r154, I suspect you have to apply the migration tasks mentioned in Updates to lighting in three.js r155.

Meaning increasing the directional and ambient light intensities should maybe fix your issue.

1 Like

I have placed files on my server to enable code comparison between r157, r154, and the new version.
The following is reference code for MMDLoader, with minor changes made only to the color space.

■r157:NoColorSpace (error)
https://try-on.net/cs/r157/nocolorspace_error.html

■r157:sRGBColorSpace
https://try-on.net/cs/r157/srgbcolorspace.html

■r157:LinearsRGBColorSpace
https://try-on.net/cs/r157/linearsrgbcolorspace.html

■r154:NoColorSpace(i like)
https://try-on.net/cs/r154/nocolorspace.html

I experimented with color settings using [r157 srgbColorSpace] and found that I could achieve colors similar to [r154 noColorSpace], which led to a temporary self-resolution.

■r157:sRGBColorSpace2
https://try-on.net/cs/r157/srgbcolorspace2.html

I do wish that NoColorSpace, which can produce colors using only ambient light, could be reinstated if possible. However, when I want to use it, I think I can simply use r154. Thank you for all the various clarifications and assistance.

I suspect the visual result you’re seeing in the NoColorSpace demo is not actually a difference in the output transformation. There should be no difference between NoColorSpace and LinearSRGBColorSpace (the working color space) in the shader output transform.

But clearly something is different here. I think we may need to figure out what was previously happening when NoColorSpace was used. It wasn’t intended to be supported, but I bet there are ways to create the same look with one of the other output color spaces.

2 Likes

Thank you for getting in touch. Here are the settings that roughly match the colors:

■ r154 noColorSpace (ambient light: 0xffffff 0.9) (directional light: 0xffffff 0.1)
https://try-on.net/cs/r154/nocolorspace.html

■ r157 sRGBColorSpace (ambient light: 0xaaaaaa 2.4) (directional light: 0xffffff 2.2)
https://try-on.net/cs/r157/srgbcolorspace2.html

I hope you can find them useful as a reference.
(This is a translation by ChatGPT. If the text seems odd, I apologize.)

I’ve also been having a hard time understanding what is going on with color in the latest releases.

Literally kinda just waiting for it all to be sorted out… and in the meantime living with washed out colors/messing with post exposure to “fix” (not really) it.

We need some kind of color space for dummies doc or something…

@dora I agree… its all pretty confusing.

edit: I know it’s good stuff! I’m just slow on the uptake…

3 Likes

I have thought about putting a “quickstart” section at the top of the color management guide. Or something like that. If there are particular questions you’d hope to see answered, let me know!

3 Likes

Nice ya! I guess just like… confirmations of some basic scenarios… like…

Q1:
I drag a picture of a dog off google image search. I load using TextureLoader and put it on a basicmaterial.map. I create renderer as renderer=new WebGLRenderer()

I don’t have to do anything to the renderer outputencoding or texture encoding etc to see it like it looks on the original webpage yeah?

Q2:
I’m loading a normalmap using TextureLoader. assuming I then need to set texture.colorspace or encoding to Linear somehow “linear” THREE.LinearEncoding… ?? :frowning:
(Or maybe I don’t because I got the normalmap off google image search so its already srgb?)
(Or maybe I do because I rendered it out of blender as a png?)

Q3:
I add EffectComposer to the mix… do I need to change the renderer output or will composer take care of it somehow?
My texture loading doesn’t need to change yea?

Q4:
Ok so maybe I have a hard time telling the difference between correct and incorrect color…
Is there some way to detect whether rendered output looks “correct”… perhaps by some statistical guess based on a histogram or something?

Like a widget that says:
Your color output is washed out… check output encoding…
Your color output looks like over/under exposed…
Your color output looks like daytime… || nightttime
Your color output looks monochrome but the whites are grey…
Your normal maps look like the wrong colorspace…

I feel like I need more tools to understand/interact with/inspect color somehow…

I just feel like I never know what is “right” , and I end up just tweaking random stuff until it looks “good”…
I’m just thinking out loud/venting here… apologies if none of this makes sense…

Take this case for example… I don’t know if my texture encoding is f’ed up… or if its my lighting… or both… or what…

1 Like

Thanks! These are good things to have quick answers to in docs, great points, I’ll think about how to handle that.

Quick responses here, for now, though:

Q1: Default renderer settings are good, just consider adding tone mapping for lit scenes, which improves dynamic range (reduces harsh highlights and shadows). However, you will need to set the texture encoding in most cases, see Q2.

Q2: In general texture.colorSpace needs to be set by the user, three.js cannot infer that. The default is NoColorSpace, which is correct for non-color textures like .normalMap but not for .map. See Updates to Color Management in three.js r152 - #61 by donmccurdy for more on this.

Q3: Renderer settings can be left as-is, just add THREE.OutputPass as the last pass in your effect stack. No difference on textures. I’m not sure on the current settings for the external postprocessing npm package, would see their docs for current recommendations.

Q4: I’d love to know the answer on this, too!

I agree the terrain in the screenshot does not look quite right. The three.js sky/water shaders were written before all this color management and might need further updates. If these are non-default renderer settings, I wonder if the sky/water shader is forcing you to choose those settings, and then running the terrain lighting with incorrect gamma.

@manthrax
Thank you for your response. I’ll keep an eye on it as it seems there are ongoing discussions about the colors.

1 Like

That seems counterintuitive to me. In absense of a specific directive, I feel like threejs should reasonably infer/assume sRGB ? principle of least surprise / less typing / etc.

I suspect the vast majority of users don’t know or care about color space/encoding or even what it means, and 99.99% of images available on the web are sRGB. (This includes a lot of normalmaps from tutorial sites as well i think?)

That means that now, 99% of the time I have to add a load callback (texture)=>texture.encoding = ‘something’, and in the extreeemely rare case that I’m manually loading an actual linear colorspace texture acquired from some 3d modelling pipeline, I would not need a callback? That sounds backwards. (This case being even more rare since most often when I am using normalmaps, they are packed in with a model via GLB which knows what the encodings are truly are from the source modeller?)

It makes sense to me that EXRLoader assumes linear by default, but TextureLoader should assume sRGB?

… and as I peruse the sources you linked… I see that I am not alone in my confusion. :slight_smile:

It feels like some of these details are being force-pushed into userspace, when in the past, we were still able to make decent looking stuff, now all the old threejs code is invalid with the latest versions, and have to be hand modified to make them work as they did before.

It somewhat reminds me of the switch from Geometry type to BufferGeometry, but with less immediate tangible benefit. (improved performance). I was resistant to that switch initially, and especially the deprecation of the old style Geometry, but finally grew to accept it (after a year or 2).

I feel like the new color handling could somehow be more opt-in than it is?

Appreciate anyone reading this far along and… I don’t need an answer to any of these questions… but wanted to share my internal dialog as someone who is reasonably skilled at 3d generally, but still experiences confusion about these aspects.

1 Like

Unfortunately no … normal maps very often contain sRGB ICC profiles, but are never actually sRGB data. In a typical PBR scene, most of your textures are probably THREE.NoColorSpace. But the bigger reasons for this default (IMO) are:

  1. It’s relatively easy to see when your colors are wrong, but much harder to understand the problem when your normal, AO, roughness, metalness, clearcoat, sheen, transmission, anisotropy, and other PBR textures go wrong. Changing the default to sRGB would break all of these.

  2. If it does become possible to infer color space from textures someday, I’d rather not force a migration by changing defaults in the meantime.

Same situation in Blender, users have to tag sRGB and non-color textures. Browsers don’t let us access image ICC Profiles, and even then ICC profiles are pretty unreliable… so there’s no quick fix on the horizon here.

I agree that sRGB would also be a reasonable default, but I think the amount of texture.colorSpace = X you’d need would be similar, but harder to diagnose, so (personally) I haven’t felt I could make a case for changing the default.


But yes, I hear you on the migration pain here, and sorry for that! :frowning:

In one form or another, color management was opt-in from 2015 (at least?) until 2023. I don’t feel that we rushed this, and keeping it opt-in for longer is not a pleasant thing to imagine for me.

The list of things you previously had to do to make three.js handle color correctly is the most popular post on by website by far, and (with the exception of textures) it’s all pretty automatic now! This makes a much better foundation for things like realism-effects, and mostly eliminates the “I loaded a model and the colors are wrong” issue that beginners frequently ran into.

Related:

2 Likes