Gamma and Mipmapping

For the next few weeks, my plan is to try and talk about the last few gamma things that no one tells you about and then I can stop talking about it. Today’s topic is gamma and mipmapping.

As you should know by now, the value 187 is actually half-way between o and 255. So suppose that the image up top is a texture in a game, and we want to mipmap it. What values should the left and right side converge to? Well, since 187 is half-way between 0 and 255, we would want it to be 187.

The naive way to calculate mipmaps is to just average all 4 sample points. Btw, I’m assuming the four samples are normalized between 0.0f and 1.0f. The pseudocode would look like:

float4 sourceSamples[4]; // the four source samples
float4 finalSample = 0;
for (int i = 0; i < 4; i++)
    finalSample += sourceSample[i];
finalSample /= 4;
return sourceSample;

But that’s not actually what we want, because then half-way between 0 and 255 would be 128, which is not correct. The solution is to use gamma correction. When we read the samples, we should convert them to linear (as in, pow(x,2.2)) and then when we write the value, we should convert from linear to gamma (as in, pow(x,1/2.2)). Here is the pseudocode to do it.

float4 sourceSamples[4]; // the four source samples
float4 finalSample = 0;
for (int i = 0; i < i++)
    finalSample += pow(sourceSample[i],2.2);
finalSample /= 4;
return pow(sourceSample,1/2.2); // 1/2.2 ~= .454545

That’s how the NVIDIA Photoshop plugin does it. Let’s take our image, and save it as a .dds file.

Click on that “MIP Map Filtering…” button. The defaults should look like this:

If you save with those settings, you get this final image:

That’s no good. Looking at the mipmaps, 0 and 255 were averaged to 128. Instead, let’s change the setting to this one and save again.

Then we get this image:

One thing: you might wonder why in the largest mipmap that the left and right side are 128. Well, the image is too wide to fit in the column, so I’m letting the browser scale it in half. But most browsers don’t perform gamma correction when they downscale images. If you right-click and view the image by itself or save it to disk, it will look right.

And that’s it! Now, how important is this effect? It’s not the biggest issue in the world, but if you don’t do it, you will often notice that textures get darker in the distance. But you may as well fix it, or at least use the right number when you let NVIDIA create mipmaps for you.

5 Responses to “Gamma and Mipmapping”

  1. Cool, thanks John.
    A whole new “gamma” corrected world :)

  2. Must read!

  3. Hi, if I understood correctly, in both code snipets you forgot to index the array (sourceSample) inside the FOR loop and in the last line is returning the array, instead of the actual answer (finalSample).

    Great blog by the way :)

  4. Thx. Fixed. Btw, if anyone knows how to make wordpress understand < and >, I’d love to know.

  5. [...] [...]