4 ms·
"Filtering" is a graphics term of art that roughly means "interpolation". Imagine you want to represent a star with a single max brightness pixel. Suppose you
by dTal 4y ago
"Filtering" is a graphics term of art that roughly means "interpolation".
Imagine you want to represent a star with a single max brightness pixel. Suppose you want to smoothly pan that pixel to its neighbor. If you simply switch the pixel off and switch the neighbor on, it will look jumpy. So what you want to do is gradually dim the first pixel, while gradually brightening the second, so that the intensity smoothly moves over instead of jumping.
The catch: at all times, the sum of the light intensity from both pixels must be constant. You want the star to move, not flicker. Seems easy, right? Subtract 1 from the first pixel and add 1 to the second, keeping the sum the same?
Wrong! The relationship between the actual light emitted by a pixel and the number we use to represent it in software is not linear. It generally follows a power law, usually with an exponent of about 2.2, since this is a more efficient representation given that human perception also follows a power law. If 255 were actually twice as many photons as 127, you would find that they didn't actually look all that different - the range 0-255 would skew towards most values looking pretty bright. Instead the values "encode" the real brightness, and if you do math on these encoded values you are operating in "gamma space".
So, in order to correctly do our 1-pixel panning, we need to "decode" our pixel value to linear brightness by taking the logarithm (base 2.2), add 1 / subtract 1 there, and then raise it back up. This is what Carmack means by "filtering in linear space". Obviously, many programmers are not aware of the requirement to do this, and just treat the pixel values as if they were real brightness values. Result: flicker.
- hoten 4y agoThanks for breaking it down! It seems like this was a necessity to allow for a larger range of representable colours in a single byte. Is this system largely a carry over from more constrained hardware days, or is it still appropriate for modern hardware? Like, we could represent colors with a few more bytes and toss out the gamma encoding to get back to the same level of control. Or am I overlooking more fundamental reasons why this is a good abstraction?
- midnightclubbed 4y agoStill appropriate for modern hardware. Despite hardware getting faster, display resolutions and refresh rates have also increased to eat the memory bandwidth gains. Especially so at VR resolutions. Modern rendering engines will use a mixture of 8bit, 10bit, and 16bit per color channel buffers - the final 'lit' color buffer is where you will generally write fp16 (8bytes per pixel) linear HDR color values, if you can spare the performance hit, as this is where you need the highest range.
- dTal 4y agoIt's a good abstraction, because most of the time you care about perceived brightness. With gamma encoding, 255 looks twice as bright as 127. You are going to need to deal with that perceptual power law at some point no matter what representation you use, so you may as well pick the efficient one. It's probably not a good tradeoff to make everyone deal with a color scale that doesn't look right, and is inefficient, just to make intensity operations linear so that unwary programmers don't trip.