Page MenuHome

Cycles/Eevee: unified and improved texture image color space handling

Authored by Brecht Van Lommel (brecht) on May 6 2019, 12:14 PM.



Cycles now uses the color space on the image datablock, and uses OpenColorIO
to convert to scene linear as needed. Byte images do not take extra memory,
they are compressed in scene linear + sRGB transfer function which in common
cases is a no-op.

Eevee and workbench were changed to work similar. Float images are stored as
scene linear. Byte images are compressed as scene linear + sRGB and stored in
a GL_SRGB8_ALPHA8 texture. From the GLSL shader side this means they are read
as scene linear, simplifying the code and taking advantage of hardware support.

Eevee texture sampling looks a little different now because interpolation
happens in scene linear space, which is more correct.

Overlays and grease pencil work in sRGB space so those now have an extra
conversion to sRGB after reading from image textures. This is not particularly
elegant but as long as engines use different conventions, one or the other
needs to do conversion.

This change breaks compatibility for cases where multiple image texture nodes
were using the same image with different color space node settings. However it
gives more predictable behavior for baking and texture painting if save, load
and image editing operations have a single color space to handle.

This patch is not finished yet, but posting now for overall design feedback.

Diff Detail

rB Blender

Event Timeline

Further updates to make alpha handling consistent.

Image textures are now all stored premultiplied for byte and float, for correct texture interpolation results. This means we need to unpremultiply in the shader nodes since blending with the transparent BSDF will multiply it again. Cycles does the same thing.

This works ok for byte images, but for float images I'm running into some issues, probably related to float precision. The solution for this I have no found yet.

Python API gl_load() and gl_touch() were changed to use GPU_texture_from_blender() so results are consistent. It's not really possible to load textures with different filters since it may have already been loaded, and if changes are needed this can still be done with bgl.

I'm really happy that it cleans a lot of places. I don't think the added conversion for the overlays are a problem. So for me it's a big +1.


Can you explain why this is needed only if alpha output is plugged?

This revision is now accepted and ready to land.May 10 2019, 10:02 PM

If alpha is not used, then you nearly always want alpha to be premultiplied to avoid artifacts in areas with zero alpha. If alpha is used, you nearly always want it to be unpremultiplied since it will be multiplied again when mixing with the transparent BSDF.

This is weird Cycles behavior, that I would like to improve once. But I'm not sure what the best way to do it is. A setting on the node to switch behavior is better I guess, but also hard to explain to users.

This revision was automatically updated to reflect the committed changes.