Different texture colors between vite threejs , and vite r3f

i have created two working environments , one in vite three.js , and the other in vite react three fiber , and then I have loaded the same texture in both environments , and then added that texture on the meshBasicMaterial using the map property (nothing else ) , i got two different colors for the same texture ,


then I changed the colorSpace in both textures to srgb , in three js I got exactly the same color as the one that I have in the jpg image, but nothing has been changed in the texture color under r3f env

R3F sets texture.colorSpace to SRGBColorSpace by default; three.js defaults to NoColorSpace. Personally I would suggest always setting the texture color space explicitly, whichever library you are using.

There’s also tone mapping enabled by default in R3F, but not in three.js, so you may want to check that if you’re still seeing differences after setting the color space.

2 Likes

Yeah , the solution was basically changing the tonemapping to no tone mapping ,

1 Like

i have a question if you excuse me , if i kept the gl r3f outputColorspace to the default which is srgbColorSpace does that mean the data texture will automatically be converted to srgb ? , second question, when keeping the default outputColorSpace in r3f gl to srgb doesn’t that mean we don’t have to change the diffusecolor texture color space to srgb cause it will be automatically converted ?

In three.js or R3F, the implicit “working color space” within the render process is Linear-sRGB. At the end of the render process, we convert from the working color space to the output color space (renderer.outputColorSpace).

The texture.colorSpace property tells three.js what that texture contains, so it can be converted into the working color space (Linear-sRGB) correctly before rendering. Most color textures are sRGB, but non-color data textures (like normal and roughness maps) have no color space and need no conversion. So…

:white_check_mark: Good: Set texture.colorSpace = SRGBColorSpace, it’s converted from sRGB to Linear-sRGB before rendering, and with renderer.outputColorSpace = SRGBColorSpace the output is converted back to sRGB for display.

:cross_mark: Bad: Set texture.colorSpace = NoColorSpace then it doesn’t get converted, stays in sRGB, but the output step thinks everything is Linear-sRGB and does a “Linear-sRGB to sRGB” conversion, so your colors will just be wrong.

More details in the color management guide.

3 Likes

I’m a bit hazy on why the working colorspace is called Linear-sRGB and not just Linear?

And… is nocolorspace different than linearcolorspace?

edit: nvm i think i just need to read that color management guide better. :smiley:

Mainly I’m just trying to be more explicit. When someone writes “convert to linear” they usually mean converting to the color space with Rec. 709 (“sRGB”) primaries, D65 white point, and linear transfer functions (no gamma curve). That’s been the standard on the web for a long time. But for wide gamut color (now available in CSS, WebGL, and WebGPU…) other primaries are available (P3 and Rec. 2020) so I’m really trying to be a little more specific on terms. Linear-P3 and Linear-Rec2020 are also linear. :slight_smile:

And… is nocolorspace different than linearcolorspace?

three.js APIs interpret NoColorSpace as “it’s not a color, don’t try to convert it between color spaces”. LinearSRGBColorSpace happens to be the color space three.js uses for rendering, so if a color is already in that color space it doesn’t need conversion. So in that sense they both take the same path in the renderer.

Key difference: if you change the working color space to something else (very experimental!) then inputs in LinearSRGBColorSpace would be converted.

import { ColorManagement } from 'three';
import { 
  LinearDisplayP3ColorSpace,
  LinearDisplayP3ColorSpaceImpl
} from 'three/addons/math/ColorSpaces.js';

// register Linear Display P3
ColorManagement.define( {
  [ LinearDisplayP3ColorSpace ]: LinearDisplayP3ColorSpaceImpl
} );

material.color.setRGB( 1, 0, 0, THREE.LinearSRGBColorSpace ); // no conversion
material.color.setRGB( 1, 0, 0, THREE.NoColorSpace ); // no conversion

// ⚠️ experimental!
ColorManagement.workingColorSpace = THREE.LinearDisplayP3ColorSpace;

material.color.setRGB( 1, 0, 0, THREE.LinearSRGBColorSpace ); // ✨ Linear-sRGB → Linear-P3
material.color.setRGB( 1, 0, 0, THREE.NoColorSpace ); // no conversion
1 Like