sRGB and Mipmaps

The principle reason lighting functions require lRGB values is because they perform linear operations. They therefore produce inaccurate results on non-linear colors. This is not limited to lighting functions; all linear operations on colors require a lRGB value to produce a reasonable result.

One important linear operation performed on texel values is filtering. Whether magnification or minification, non-nearest filtering does some kind of linear arithmetic. Since this is all handled by OpenGL, the question is this: if a texture is in an sRGB format, does OpenGL's texture filtering occur before converting the texel values to lRGB or after?

The answer is quite simple: filtering comes after linearizing. So it does the right thing.

Note

It's not quite that simple. The OpenGL specification technically leaves it undefined. However, if your hardware can run these tutorials without modifications (ie: your hardware is OpenGL 3.3 capable), then odds are it will do the right thing. It is only on pre-3.0 hardware where this is a problem.

A bigger question is this: do you generate the mipmaps correctly for your textures? Mipmap generation was somewhat glossed over in the last tutorial, as tools generally do this for you. In general, mipmap generation involves some form of linear operation on the colors. For this process to produce correct results for sRGB textures, it needs to linearize the sRGB color values, perform its filtering on them, then convert them back to sRGB for storage.

Unless you are writing texture processing tools, this question is answered by asking your texture tools themselves. Most freely available texture tools are completely unaware of non-linear colorspaces. You can tell which ones are aware based on the options you are given at mipmap creation time. If you can specify a gamma for your texture, or if there is some setting to specify that the texture's colors are sRGB, then the tool can do the right thing. If no such option exists, then it cannot. For sRGB textures, you should use a gamma of 2.2, which is what sRGB approximates.

Note

The DDS plugin for GIMP is a good, free tool that is aware of linear colorspaces. NVIDIA's command-line texture tools, also free, are as well.

To see how this can affect rendering, load up the Gamma Checkers project.

Figure 16.3. Gamma Checkers

Gamma Checkers

This works like the filtering tutorials. The 1 and 2 keys respectively select linear mipmap filtering and anisotropic filtering (using the maximum possible anisotropy).

We can see that this looks a bit different from the last time we saw it. The distant grey field is much darker than it was. This is because we are using sRGB colorspace textures. While the white and black are the same in sRGB (1.0 and 0.0 respectively), a 50% blend of them (0.5) is not. The sRGB texture assumes the 0.5 color is the sRGB 0.5, so it becomes darker than we would expect.

Initially, we render with no gamma correction. To toggle gamma correction, press the a key. This restores the view to what we saw previously.

However, the texture we are using is actually wrong. 0.5, as previously stated, is not the sRGB color for a 50% blend of black and white. In the sRGB colorspace, that color would be ~0.73. The texture is wrong because its mipmaps were not generated in the correct colorspace.

To switch to a texture who's mipmaps were properly generated, press the g key.

Figure 16.4. Gamma Correct with Gamma Mipmaps

Gamma Correct with Gamma Mipmaps

This still looks different from the last tutorial. Which naturally tells us that not rendering with gamma correction before was actually a problem, as this version looks much better. The grey blends much better with the checkerboard, as the grey is now correctly halfway between white and black. The take-home point here is that ensuring linearity in all stages of the pipeline is always important. This includes mipmap generation.

Fork me on GitHub