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.
Blending can be used to make objects appear transparent. This is not its only use, but it is one of its main uses. Doing this requires that you take certain steps, some of them quite difficult to deal with. See the linked page for details.
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, 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.
Source, Destination, and the buffer
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.
These represent all of the components of that color. Srgb is just the RGB components of the source color. Da is the alpha component of the destination color.
All addition and multiplication is component-wise. Scalar multiplies against colors are also component-wise multiplies.
The source color S output from the fragment shader will be clamped to [0, 1] if the image format of the destination buffer that it is destined for is a normalized integer format. Otherwise, it will be used as given.
The destination color D read from the buffer can undergo changes as well. If the buffer in question uses an sRGB image format, and GL_FRAMEBUFFER_SRGB is currently enabled, then the value being read will be linearized, converting from the sRGB colorspace to a linear one. This happens before blending. Similarly, O will be converted from linear to sRGB if the enum is defined and if the buffer is an sRGB format.
If the buffer that D comes from contains an integral format (actual, non-normalized integers), then blending for that buffer is skipped entirely. S will be written directly to O.
Blending must be enabled with a call to glEnablei(GL_BLEND, i), where i is an integer representing the buffer to enable blending on. Each buffer being written to by a fragment shader can have blending separately enabled and disabled. glDisablei can be used to disable blending.
When blending is disabled to a buffer, the color from the fragment shader will be written directly to that buffer. When blending is enabled, one of the following blend equations will be used to determine the color written to that buffer.
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 = sS + dD. The The s and d are blending parameters that are multiplied into each of S and D before the addition.
- GL_FUNC_SUBTRACT: Subtracts the destination from the source. O = sS - dD. The source and dest are again multiplied by blending parameters.
- GL_FUNC_REVERSE_SUBTRACT: Subtracts the source from the destination. O = sD - dS. The source and dest are multiplied 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 s and d are ignored for this equation.
- GL_MAX: The output color is the component-wise maximum value of the source and dest colors. The parameters s and d are ignored for this equation.
Three of the blending equations modify the source and destination colors by parameters. These equations can be broken down into two separate equations:
* Orgb = srgb*Srgb + drgb * Drgb * Oa = sa*Sa + da * Da
The same goes for the two subtraction equations. This separates the RGB component computation from the alpha computation. So there are 4 possible blending parameters.
These parameters are specified by this function:
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
The srcRGB value specifies the srgb parameter. dstRGB specifies drgb. srcAlpha is for sa, while dstAlpha specifies da.
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, and you do not have to set them.
The values that the parameters can take is as follows.
The parameters GL_ONE and GL_ZERO are constant values. GL_ONE means 1.0, and GL_ZERO means 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 themselves, 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). This will give O = D * S + 0 * D.
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. Note that source and dest are not limited to the [0, 1] range if the destination buffer is a floating-point buffer.
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:
void 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 longer 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.