Blending

From OpenGL Wiki
Jump to navigation Jump to search

Blending is the stage of OpenGL rendering pipeline that takes the fragment color outputs from the Fragment Shader and combines them with the colors in the color buffers that these outputs map to. Blending parameters can allow the source and destination colors for each output to be combined in various ways.

Transparency[edit]

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.

Fragment Outputs[edit]

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[edit]

Draw Buffers Blend
Core in version 4.6
Core since version 4.0
ARB extension ARB_draw_buffers_blend

Given the availability of this feature, the user can specify different blending parameters or equations for each buffer.

Note: All AMD/ATI 3.x-class hardware, the HD2000, 3000, and 4000 series, implement ARB_draw_buffers_blend. No pre-4.0 hardware from NVIDIA implements this.

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 whose blending data this function call is intended to change. So, given the function glBlendFuncSeparate, there is a glBlendFuncSeparatei whose first parameter is a draw buffer index.

Note that the glEnablei/glDisablei functions are not part of this functionality. The ability to enable/disable blending to specific buffers is core 3.0 functionality. Whereas draw buffers blend is about the ability to specify different blend parameters for different buffers.

Source, Destination, and the buffer[edit]

The Fragment Shader can write a number of colors. These colors are mapped to particular images in the Framebuffer via glDrawBuffers. Blending happens independently on each fragment shader output value.

Blending operations take place between a source color and a destination color. The source color is the value written by the fragment shader. The destination color is the color from the image in the framebuffer. 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.

The S, D, and so forth represent all of the components of that color. Srgb represents only the RGB components of the source color. Da represents 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.

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.

Blend enabling[edit]

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.

Blending on all buffers can be enabled or disabled with glEnable and glDisable.

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.

Note that blending only works for a particular buffer if the Image Format is some form of floating point. Either regular floats or Normalized Integers. If it is an unnormalized integer, blending for that buffer behaves as if it is disabled.

Blend Equations[edit]

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 multiplied by blending parameters.
  • GL_FUNC_REVERSE_SUBTRACT: Subtracts the source from the destination. O = dD - sS. 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.

Blending Parameters[edit]

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.

Constant Values[edit]

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.

Colors[edit]

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 equations are 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 performs linear interpolation between the source and destination colors based on the source alpha. The alpha function and parameters simply write the source alpha to the output. If the source alpha needs to be blended with the destination alpha, then these blend parameters may be used instead:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

This performs linear interpolation on both the color and the source alpha. The source alpha's parameter is GL_ONE rather than GL_SRC_ALPHA because it is being multiplied by the source alpha already.

It is often useful to perform premultiplied alpha blending, a slight modification of standard linear interpolation. Premultiplication is so named because the RGB source color has already been multiplied by the alpha. This usually is done by image editing software when generating the texture, but it can also be done as a Fragment Shader operation or even with per-vertex color data passed into the Vertex Shader. However it happens, the value output by the fragment shader has effectively already been multiplied by the alpha component, so the blend equation must take that into account.

The setup for this is as follows. Note that the alpha settings are unchanged, and that compositing semi-transparent layers on top of each other will eventually make the output opaque.

glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

Blend Color[edit]

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 a state value, like the blend equations and blend parameters. Therefore, it cannot change within a single draw call; fragment shaders cannot write to, modify, or even access 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[edit]

Dual source blending refers to a blending mode, where the Fragment Shader 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) out vec4 outputColor0;
layout(location = 0, index = 1) out 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.

Note: In virtually every OpenGL implementation and hardware, GL_MAX_DUAL_SOURCE_DRAW_BUFFERS is 1. This applies to 3.x and 4.x hardware alike. For all practical purposes, if you use dual-source blending, you can only write to one buffer.

The source color S in blending equations is always color 0. Color 1 can only be used as a parameter. The parameters that use color 1 are GL_SRC1_COLOR, GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_COLOR, and GL_ONE_MINUS_SRC1_ALPHA.