Thus far, we have seen how to use sRGB textures to store gamma-corrected images, such that they are automatically linearized upon being fetched from a shader. Since the sRGB colorspace closely approximates a gamma of 2.2, if we could use an sRGB image as the image we render to, we would automatically get gamma correction without having to put it into our shaders. But this would require two things: the ability to specify that the screen image is sRGB, and the ability to state that we are outputting linear values and want them converted to the sRGB colorspace when stored.
Naturally, OpenGL provides both of these. To see how they work, load up the last project, Gamma Landscape. This shows off some textured terrain with a day/night cycle and a few lights running around.
It uses the standard mouse-based controls to move around. As before, the 1 and 2 keys respectively select linear mipmap filtering and anisotropic filtering. The main feature is the non-shader-based gamma correction. This is enabled by default and can be toggled by pressing the SpaceBar.
sRGB Screen Image. The process for setting this up is a bit confusing, but is ultimately quite simple for our tutorials. The OpenGL specification specifies how to use the OpenGL rendering system, but it does not specify how to create the OpenGL rendering system. That is relegated to platform-specific APIs. Therefore, while code that uses OpenGL is platform-neutral, that code is ultimately dependent on platform-specific initialization code to create the OpenGL context.
These tutorials rely on FreeGLUT for setting up the OpenGL context and managing the
platform-specific APIs. The framework.cpp
file is responsible for
doing the initialization setup work, telling FreeGLUT exactly how we want our screen
image set up. In order to allow different tutorials to adjust how we set up our FreeGLUT
screen image, the framework calls the defaults
function.
Example 16.4. Gamma Landscape defaults Function
unsigned int defaults(unsigned int displayMode, int &width, int &height) { return displayMode | GLUT_SRGB; }
The displayMode
argument is a bitfield that contains the standard
FreeGLUT display mode flags set up by the framework. This function must return that
bitfield, and all of our prior tutorials have returned it unchanged. Here, we change it
to include the GLUT_SRGB
flag. That flag tells FreeGLUT that we want
the screen image to be in the sRGB colorspace.
Linear to sRGB Conversion.
This alone is insufficient. We must also tell OpenGL that our shaders will be
writing linear colorspace values and that these values should be converted to sRGB
before being written to the screen. This is done with a simple
glEnable
command:
Example 16.5. Enable sRGB Conversion
if(g_useGammaDisplay) glEnable(GL_FRAMEBUFFER_SRGB); else glDisable(GL_FRAMEBUFFER_SRGB);
The need for this is not entirely obvious, especially since we cannot manually turn off sRGB-to-linear conversion when reading from textures. The ability to disable linear-to-sRGB conversion for screen rendering is useful when we are drawing something directly in the sRGB colorspace. For example, it is often useful to have parts of the interface drawn directly in the sRGB colorspace, while the actual scene being rendered uses color conversion.
Note that the color conversion is just as free in terms of performance as it is for texture reads. So you should not fear using this as much and as often as reasonable.
Having this automatic gamma correction is better than manual gamma correction because it covers everything that is written to the screen. In prior tutorials, we had to manually gamma correct the clear color and certain other colors used to render solid objects. Here, we simply enable the conversion and everything is affected.
The process of ensuring a linear pipeline from texture creation, through lighting, through to the screen is commonly called gamma-correct texturing. The name is a bit of a misnomer, as “texturing” is not a requirement; we have been gamma-correct since Tutorial 12's introduction of that concept (except for Tutorial 15, where we looked at filtering). However, textures are the primary source of potential failures to maintain a linear pipeline, as many image formats on disc have no way of saying if the image data is in sRGB or linear. So the name still makes some sense.