Blending is the stage of OpenGL Rasterization that takes the fragment color outputs and combines them with the destination colors that they are adding to. Blending parameters can allow the source and destination colors for each output to be combined.
The result of the fragment processing stage of the OpenGL Pipeline, whether using Fragment Shaders or not, are zero or more color values. There are other outputs from fragment processing, but blending only deals with colors.
These colors must be written to zero or more of the color buffers in the current framebuffer. Each fragment output color is matched up with a particular buffer (or discarded) via a call to glDrawBuffers or glDrawBuffer. Once the matching is arranged, the color can be written to that buffer.
When blending is active, via a call to glEnable(GL_BLEND), the input colors from the fragment processor does not merely overwrite the corresponding value currently in the output buffer, but instead the two colors are combined together based on a function.
Draw Buffers Blend
In all OpenGL 4.0 or greater implementations, or any implementation that exposes the GL_ARB_draw_buffers_blend extension, the user can specify different blending parameters or equations for each buffer. Otherwise, all blending functions apply to all buffers.
If this functionality is available, for every function described below, there is an equivalent function that has an "i" at the end of the name ("iARB" for the extension version). This function takes one additional parameter at the beginning, an unsigned integer representing the draw buffer index who's blending data this function call is intended to change. So, given the function glBlendFuncSeparate, there is a glBlendFuncSeparatei who's first parameter is a draw buffer index.
When doing blending for a particular buffer, the color from the fragment output is called the source color. The color currently in the buffer is called the destination color. When discussing the source and dest colors, boldface type will be used to represent colors. The color S is the source color; the color D is the destination color; the color O is the output color that is written to the buffer. Srgb is just the RGB components of the source color. Da is the alpha of the destination color.
All addition and multiplication is component-wise. Scalar multiplies against colors are also component-wise multiplies.
Blending state for a buffer has two components. The first defines the basic equation used for blending. This equation defines the basic math operation that relates the source color and the dest color. The second blending component are parameters. Each equation has a number of parameters; these parameters can be used to modify the basic math computation used.
When computing the output color, two equations are used: one for the RGB portion of the output color, and one for the alpha of the output color. This is useful if you want to do something like blend the source and dest colors but take the source alpha as the fragment output produced it.
The two equations are set with this function:
void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
The modeRGB is the equation to use for the RGB portion of the output color, and modeAlpha is the equation to use for the alpha portion.
The possible equations are as follows:
- GL_FUNC_ADD: The source and destination colors are added to each other. O = S + D. The source and destination colors are each multiplied by values defined by blending parameters.
- GL_FUNC_SUBTRACT: Subtracts the destination from the source. O = S - D. The source and dest are again multiplied by values defined by blending parameters.
- GL_FUNC_REVERSE_SUBTRACT: Subtracts the source from the destination. O = D - S. The source and dest are multiplied by valued defined by blending parameters.
- GL_MIN: The output color is the component-wise minimum value of the source and dest colors. So performing GL_MIN in the RGB equation means that Or = min(Sr, Dr), Og = min(Sg, Dg), and so forth. The parameters are ignored for this equation.
- GL_MAX: The output color is the component-wise maximum value of the source and dest colors.
Three of the blending equations modify the source and destination colors by parameters. These parameters are specified by this function:
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
The srcRGB value specifies the parameter that is multiplied with the source color in the RGB equation. dstRGB represents the parameter multiplied with the destination color in the RGB equation. srcAlpha is the parameter multiplied with the source color in the alpha equation. And similarly for dstAlpha and the destination color in the alpha equation.
For blend equations that do not use parameters (GL_MIN and GL_MAX), the parameter values are meaningless. They do not affect the output values.
There are a number of possible parameters.
The parameters GL_ONE and GL_ZERO are constant values. GL_ONE multiplies the color by 1.0, and GL_ZERO multiplies it by 0.0.
If you want to do straight addition, O = S + D, then setting both the source and dest to GL_ONE is necessary, as well as using the GL_FUNC_ADD function.
There are a number of parameters that are derived from source and destination colors, or components thereof.
GL_SRC_COLOR and GL_DST_COLOR represent S' and D, as appropriate for the particular equation. So setting GL_SRC_COLOR in the RGB equation means getting Srgb; setting it in the alpha equation means getting Sa.
For example, if the blending you want is a straight multiplication of the source and destination colors, O = S * D, then you should set the GL_FUNC_ADD function. Then set the source parameter for that equation to GL_DST_COLOR, and set the destination parameter to GL_ZERO (we don't want to do addition, so null out the additive term).
There are also GL_ONE_MINUS_SRC_COLOR and GL_ONE_MINUS_DST_COLOR. These are exactly what they say: 1.0 - the value of those colors. This is a component-wise subtraction.
It is also possible to get the alpha component alone. GL_SRC_ALPHA and GL_DST_ALPHA represent Sa and Da, regardless of which equation is being used. There are also GL_ONE_MINUS_SRC_ALPHA and GL_ONE_MINUS_DST_ALPHA, which work as above. Sa and Da are scalars, so their multiplication with the source and destination colors is component-wise.
The traditional alpha blend is set up as follows:
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
This does linear interpolation between the source and destination colors based on the source alpha. The alpha function and parameters simply writes the source alpha to the output.
It is often useful to perform premultiplied alpha blending. This means that texture values have multiplied the alpha with the texel before accessing it (or in the shader). So you don't want to multiply the source color by the source alpha, as this has already been done for you by the texture. So the setup for this is as follows:
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
You may set a constant color that you can use for blending. This is called the blend color. It is set with this function:
glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
The blend color is state like the blend equations and blend parameters. Therefore, it cannot change within a single draw call; fragment shaders cannot write to or modify the blend color. All buffers share the same blend color.
The blend color is accessed only as parameters. The enumerators for these are GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, and GL_ONE_MINUS_CONSTANT_ALPHA.
Dual Source Blending
Dual source blending refers to a kind of blending, where the Fragment Shader (and this only works with fragment shaders) outputs two colors to the same output buffer. To do this, the two outputs must both point to the same buffer index, but with a special parameter that refers to whether it is color 0 or color 1. This can be done in GLSL using the layout qualifier:
layout(location = 0, index = 0) vec4 outputColor0; layout(location = 0, index = 1) vec4 outputColor1;
This has outputColor0 writing to color 0 of buffer 0, while outputColor1 goes to color 1 of buffer 0. Each buffer can have its own set of two colors.
Alternatively, you can use this function to bind the output before the program object is linked:
void glBindFragDataLocationIndexed(uint program, uint colorNumber, uint index, const char * name);
program is the program object, colorNumber is the buffer index, index is the color number (0 or 1), and name is the string name of the output variable.
Dual source blending is activated in a fragment shader by designating (via either method above) that at least one of the output values is going to color 1 of one of the destination buffers. When dual source blending is active for a shader, the number of color buffers that can be written to is no long GL_MAX_DRAW_BUFFERS, but GL_MAX_DUAL_SOURCE_DRAW_BUFFERS. This implementation-dependent constant represents the number of draw buffers that a fragment shader can output to when using dual-source blending.
Color 1 in blending equations can only be used as parameters; it cannot replace the S or D colors. The parameters that use color 1 are GL_SRC1_COLOR, GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_COLOR, and GL_ONE_MINUS_SRC1_ALPHA.