How could I implement custom color transfer functions?
I want to carefully control for the color of my visual stimuli. I've seen that I can set a channel-by-channel gamma, but what if my transfer function is not well fit by a typical gamma curve?
I've tried using a Look up table, but it seems that Shady's only LUT implementation takes just the red channel and looks up all the channels at once, whereas I want something that will look-up each channel independently, in order to enable the use of independently linear R, G and B channels?

- 48
- 5
1 Answers
It's true that LUTs are only one-dimensional on the input side. Shady's LUT support is fundamentally not designed for the kind of usage you describe (in addition, note that when you use a LUT, there are other side-effects like the disabling of dithering). What is really needed is some way of applying arbitrary transformations (without necessarily quantizing).
From version 1.12 onwards, Shady has the ability to customize "color transformations" via the global AddCustomColorTransformation
function and the corresponding .colorTransformation
property of the Stimulus
class and global COLORTRANS
namespace. Like the other ways of adding custom functions (signal, modulation or windowing functions) it injects snippets of custom GL Shading Language into the shader, and must be done before your World
is constructed. Here's an example, condensed from Shady's more-comprehensively-explained color-transformation demo:
import Shady; Shady.RequireShadyVersion('1.12')
Shady.AddCustomColorTransformation("""
vec4 PhotoNegative(vec4 color)
{
color.rgb = 1.0 - color.rgb;
return color;
}
""")
w = Shady.World()
s = w.Stimulus(Shady.EXAMPLE_MEDIA.alien1, frame=Shady.Integral(16))
s.colorTransformation = Shady.COLORTRANS.PhotoNegative
The obvious potential downside of custom functions is that they require you to get your hands dirty writing actual GLSL code, which in turn means keeping your eye on optimizing the computational complexity of what you're writing, so that you avoid things slowing down too much.
In most cases the effort would probably be minimal, though. Custom transformations for color vision research could be implemented by separately applying a custom function to color.r
, color.g
and color.b
, and/or by applying a matrix transformation to color.rgb
, which the shader can do very efficiently. Remember to leave the alpha channel value color.a
untouched at 1.0 (in Shady, alpha-blending breaks linearization).

- 14,867
- 5
- 37
- 64