Transitioning to an sRGB workflow

Hello everyone,

I’m in the process of updating three.js in our app to r151, currently in r148, about to move to r149. As a part of that, I want to move from using a non-linear workflow - where the textures and the renderer both have LinearEncoding set - to a linear (sRBG) workflow - where the have sRGBEncoding.

Forgive me if I mix the terms incorrectly, I’ve seen the term “linear workflow” used for both options…

On some objects, I get the same results in terms of colors, but for others, the colors look darker after the transition.

Attached is an example of such an object. It has a map and lightmap.

floor_original.json (7.2 MB)
floor_changed_incorect.json (7.2 MB)

Both files are the same, except for the encoding of the map and lightmap set to 3001 (sRGBEncoding) instead of 3000 (LinearEncoding).

I’ll note that I my scenes have no lights, and I work only with MeshBasicMaterial with lightmaps baked in.

I would appreciate any help on the subject, whether it explaining what I’m doing wrong or explaining if and why this result is expected.


You might find it saves time to jump directly to r152+. Some names and default settings were changed in r152, making the linear workflow the default.

In any case. It’s very likely that your is sRGB, and in the linear workflow you’ll need to annotate that texture with .encoding = sRGBEncoding, equivalent to .colorSpace = SRGBColorSpace in r152+. With a lightmap, either sRGB or Linear-sRGB are valid choices. Ideally we’d know which was selected when exporting the lightmap, without knowing it might require trial and error.

The settings of your renderer also matter a lot – have you seen the guide at Updates to Color Management in three.js r152 ? That would be good to read through, if not. The ‘correct’ settings for textures will look wrong, if the renderer is not also configured correctly. In r152+ you do not need to change the renderer defaults.

Aside – If you’re using post-processing, you’ll need OutputPass in newer three.js versions, or GammaCorrectionShader in older versions. Ideally sharing a simple demo can help to identify any other pieces of the problem that would matter to your app.


Thanks for your reply @donmccurdy.

I have indeed read the guide you mentioned, and also “The Importance of Being Linear” NVIDIA article it refers to (though admittedly it may require more readings before I fully understand it).

I can’t update right now to r152 because our app is dependent on another app which uses r151 unfortunately.

My texture data is indeed sRGB, and I have annotated both the texture’s encoding as sRGB, and the renderer’s output encoding.

I believe the problem lies with the lightmap, and/or its combination with the lightmapIntensity multiplier.

The lightmaps are baked in 3Ds Max so they are SRGB as far as I understand. I have tried both keeping the lightmap’s encoding linear and changing it to SRGB (while changing the diffuse map encoding to sRGB in both cases) and neither produced the correct color exactly.

Thank you,
I will provide a live example when I can.

Here’s the JSfiddle:

Non-linear workflow
Linear Workflow (Renderer and textures set to sRGBEncoding)

If anyone can examine the live example and help me sort out the issue, I would greatly appreciate it :slightly_smiling_face:

You may also want to set:

THREE.ColorManagement.legacyMode = false;

In r152+, legacyMode = false is replaced by .enabled = true and is set by default.

Keep in mind that changing to a linear working color space does mean that the same lighting will give different results. If you disable the lightmap and just use MeshBasicMaterial or ambient lighting, you’ll see the results are very close, so I think it’s mostly just the lightmap left, and could be improved by boosting the lightmap intensity slightly.

Thanks, I’ll try that.

If we are talking about multiple objects with different light maps, Is the boost needed for the light maps expected to be the same approximately ? Or is it expected to vary widely between different light maps?

Is the boost needed for the light maps expected to be the same approximately?

If the lightmaps were sRGB encoded, then, we’re compensating for change in gamma power function with a linear scalar, and as such there is no “correct” multiplier. But if your lightmaps have roughly the same overall brightness, I believe the factor should be pretty similar across them. That’s likely to be true for non-HDR lightmaps like these.