This post is an attempt to keep up with Gamma.
innocence lost
Because, you see, only once I became fully aware of Gamma did things really start to fall apart. In my pre-gamma-aware innocence, I may have done a few things right.
Let me show what I mean:
Here, I generate a linear gradient using the GLSL Fragment shader. Suppose, creating a full-screen quad using this shader code snippet:
|
|
G.L.S.L
And voila – a perceptually linear gradient.

A conceptually linear gradient, innocently created
But now, let’s be smart about this: we see that we are In fact Drawing on an sRGB monitor (most desktop monitors these days are), so we should probably use an sRGB image for the swapchain (these are the most common 8bpc Swapchain image format in Vulkan). Thus we need to somehow convert our RGB colors to sRGB. The most elegant way to do this is to use an image attachment with the sRGB format, which (at least in Vulkan) does the conversion automatically and accurately on texel save.
If we create the same shader as before, but now in an sRGB swapchain the non-linear RRGB encoding of the swapchain image should correct the sRGB monitor gamma. The brightness value of the gradient (as measured by the brightness meter) should now increase linearly on the screen. They do. It should look like a linear gradient, right?
Wrong.
Instead, we get this:

A perfectly ‘linear’ slope
It’s not like that Look Linear: Shaders do not claim the same space. Instead, it seems as if darker colors are too bright, while brighter colors appear washed out. Here’s what I expected to see:

a conceptually linear gradient
The difference is subtle, but look at both gradients and ask yourself: which appears to have more detail? Who is more balanced?
Even if the first shield Is more linear in terms of physical brightness, the second looks like More linear.
This seems counter-intuitive to me. But where intuition fails, ratio can help; And there is actually a rational explanation: visual perception is non-linear.
And you see those who are in darkness/Those who are in light disappear from sight
You don’t have to take my word for it; Take Dr. Charles Poynton instead – the guy who gave HDTV the square pixel and the number 1080. Here’s a diagram of how our perception reacts to changes in lightness, which I found in my dissertation:

CIE lightness (Poynton 2018, p. 17). Note how perception is biased towards darker colors.
CIE lightness, when defined as a (relative) curve of just noticeable differences, fits very well to a power function with exponent (0.42), a small linear bit below the relative brightness of about 1%.
This is okay. Nature. It probably helped our ancestors survive or something. And this explains why our physically linear gradient looks very bright in dark areas. Let’s draw a diagram:
A linear gradient is being biased
in black: Partiality
Red:hint at this point in the chain
bias check
Whenever we want to create a perceptually linear gradient, we must remember to pay our dues to evolution and take this perceptual bias into account.
if you want appearance of a linear gradient, you must Display a non-linear gradientHe who tunes the deeper parts. Effectively, you want to enforce the inverse of the non-linearity introduced by the assumption. What is confusing is that if you forget to do any gamma correction it can be done for you automatically:
two-penny gamma correction
If you have an sRGB monitor and you are flawless No Perform any sRGB corrections (such as by rendering to a linear RGB framebuffer). FORMAT_R8G8B8A8_UNORM For example), linear gradient values will be obtained Biased only by the monitor’s gamma response – The result will be a gradient that looks “about linear”.
Our conceptually linear gradient, innocently created
It looks “about linear” because what happens is that while the monitor will “gamma” the gradient, your eye will again “de-gamma” the gradient – and since these two non-linear effects on the signal (monitor, eye) are approximately opposite to each other, we end up with a linear perceived signal.
And here’s the cool thing: This was by design!
“The non-linearity of a CRT is exactly the opposite of the lightness sensitivity of human vision. The non-linearity makes the response of a CRT roughly perceptually uniform. Far from being a flaw, this feature is highly desirable.”
Why is this desirable?
A big reason to encode images in sRGB is that, due to the perceptual nature of sRGB, we get much better perceptual luminance contrast resolution out of 8 bits per channel. Instead of wasting bits on high brightness where our eyes have trouble seeing the change, we spend most of the bit-budget where it matters: on deeper colors.
sRGB is an elegant form of perceptual compression: images at 8-bit-per-channel and below (for reasons of encoding efficiency). really want To be encoded as sRGB.
And if the monitor can display these sRGB images directly and natively (because the hardware applies the inverse of the sRGB gamma transform) – it’s a perfect match…
Practical applications for rendering using Vulkan
In Vulkan, if you can use the sRGB format for your swapchain image, you do not need to manually correct for sRGB gamma. Your pixels will automatically be stored in non-linear sRGB, and displayed linearly on the screen. This is great for encoding the highest amount of perceptual color contrast detail using a limited amount of bits (sRGB formats are typically about 8 bits per channel).
When image format names have a suffix *_SRGB sRGB gamma transformation has been applied transparently on all read texel And write texel This is useful, because we can only meaningfully mix color in linear space, mixing in non-linear space would not be (physically) correct, The Khronos Data Format specification has some great documentation on this topic,
But this means that if you want to render you have to undo the effect of the implicit sRGB gamma transform on texel write. conceptually linear gradient when using sRGB image backing. The function that the Vulkan driver implements for you on texel write is called srgb_oetfAbbreviation for “sRGB optical-electrical transfer function”.
To neutralize this function, you must apply inverse_srgb_oetfthis is it srgb_eotf “sRGB Electro-Optical Transfer Function” just before storing the texel.
Here’s how it would look using our schematic from earlier:
A perceptually linear gradient, corrected and encoded using sRGB
Create a perceptually linear gradient in an sRGB swapchain image
|
|
G.L.S.L
And voila:

a conceptually linear gradient
Further reading:
Bonus
Thanks for sticking around after the final credits. Here’s some additional information that may come in handy one day in a CGI pub quiz:
Have you ever wondered what the “s” in RGB means? I neither – till now; I assumed that’s what it meant Very goodThe sad reality is more polite: apparently it means Standard“Standard RGB”, What is the standard?
RSS:
Be the first to know about new posts by subscribing to the RSS feed
Further posts:
<a href