Without blending, every fragment is either rejected or written to the framebuffer. That behaviour is desireable for opaque objects, but it does not allow rendering of translucent objects. The correct order of operation to draw a simple scene containing a solid table with a transparent glass ontop of it: draw the opaque table first, then enable blending (also set the desired blend equation and factors) and finally the glass is drawn.
Blending is an operation to mix the incoming fragment color (SourceColor) with the color that is currently in the color buffer (DestinationColor). This happens in two stages for each channel of the color buffer:
In order to use blending, the logical color buffer must have an Alpha channel. If there is no Alpha channel, or the color buffer uses color-index mode (8 Bit), no blending can occur and behaviour is the same as if blending was disabled.
Blending functionality for all draw buffers is enabled and disabled with EnableCap.Blend
GL.Enable( EnableCap.Blend ); GL.Disable( EnableCap.Blend ); // default
To enable or disable only a specific buffer if multiple color buffers are attached to the FBO, use
GL.Enable( IndexedEnableCap.Blend, index); GL.Disable( IndexedEnableCap.Blend, index);
Where index is used to specify the draw buffer associated with the symbolic constant GL_DRAW_BUFFER(index).
The command GL.BlendEquation( mode ) specifies how the results from stage 1 are combined with each other. If you wanted to implement this with OpenTK.Math, it would look like this:
Color4 SourceColor, // incoming fragment DestinationColor, // framebuffer contents SourceFactor, DestinationFactor, // specified by GL.BlendFunc() FinalColor; // the resulting color
Please note that for fixed-point color buffers both Colors are clamped to [0.0 .. 1.0] prior to computing the result. Floating-point color buffers are not clamped. Clamping into this range is left out in this code to improve legibility.
BlendEquationMode.Min: When using this parameter, SourceFactor and DestinationFactor are ignored.
FinalColor.Red = min( SourceColor.Red, DestinationColor.Red ); FinalColor.Green = min( SourceColor.Green, DestinationColor.Green ); FinalColor.Blue = min( SourceColor.Blue, DestinationColor.Blue ); FinalColor.Alpha = min( SourceColor.Alpha, DestinationColor.Alpha );
BlendEquationMode.Max: When using this parameter, SourceFactor and DestinationFactor are ignored.
FinalColor.Red = max( SourceColor.Red, DestinationColor.Red ); FinalColor.Green = max( SourceColor.Green, DestinationColor.Green ); FinalColor.Blue = max( SourceColor.Blue, DestinationColor.Blue ); FinalColor.Alpha = max( SourceColor.Alpha, DestinationColor.Alpha );
BlendEquationMode.FuncAdd: This is the default.
FinalColor.Red = SourceColor.Red*SourceFactor.Red + DestinationColor.Red*DestinationFactor.Red; FinalColor.Green = SourceColor.Green*SourceFactor.Green + DestinationColor.Green*DestinationFactor.Green; FinalColor.Blue = SourceColor.Blue*SourceFactor.Blue + DestinationColor.Blue*DestinationFactor.Blue; FinalColor.Alpha = SourceColor.Alpha*SourceFactor.Alpha + DestinationColor.Alpha*DestinationFactor.Alpha;
FinalColor.Red = SourceColor.Red*SourceFactor.Red - DestinationColor.Red*DestinationFactor.Red; FinalColor.Green = SourceColor.Green*SourceFactor.Green - DestinationColor.Green*DestinationFactor.Green; FinalColor.Blue = SourceColor.Blue*SourceFactor.Blue - DestinationColor.Blue*DestinationFactor.Blue; FinalColor.Alpha = SourceColor.Alpha*SourceFactor.Alpha - DestinationColor.Alpha*DestinationFactor.Alpha;
FinalColor.Red = DestinationColor.Red*DestinationFactor.Red - SourceColor.Red*SourceFactor.Red; FinalColor.Green = DestinationColor.Green*DestinationFactor.Green - SourceColor.Green*SourceFactor.Green; FinalColor.Blue = DestinationColor.Blue*DestinationFactor.Blue - SourceColor.Blue*SourceFactor.Blue; FinalColor.Alpha = DestinationColor.Alpha*DestinationFactor.Alpha - SourceColor.Alpha*SourceFactor.Alpha;
If the color buffer is using fixed-point precision, the result in FinalColor is clamped to [0.0 .. 1.0] before it is passed to the next pipeline stage, no clamping occurs for floating-point color buffers.
OpenGL 2.0 and later supports separate equations for the RGB components and the Alpha component respectively. The command GL.BlendEquationSeparate( modeRGB, modeAlpha ) accepts the same parameters as GL.BlendEquation( mode ).
The command GL.BlendColor( R, G, B, A ) is used to specify a constant color that can be used by GL.BlendFunc(). For the scope of this page it is used to define the variable
The command GL.BlendFunc( src, dest ) is used to select the SourceFactor (src) and DestinationFactor (dest) in the above equation. By default, SourceFactor is set to BlendingFactorSrc.One and DestinationFactor is BlendingFactorDest.Zero, which gives the same result as if blending were disabled.
OpenTK uses the enums BlendingFactorSrc and BlendingFactorDest to narrow down your options what is a valid parameter for src and dest. Not all parameters are valid factors for both, SourceFactor and DestinationFactor. Please refer to the inline documentation for details.
OpenGL 2.0 and later supports separate factors for RGB and Alpha, for source and destination respectively. The command GL.BlendFuncSeparate( srcRGB, dstRGB, srcAlpha, dstAlpha ) accepts the same factors as GL.BlendFunc( src, dest ).
To determine whether blending for all draw buffers is enabled or disabled, use
Result = GL.IsEnabled( EnableCap.Blend );
To query blending state of a specific draw buffer:
Result = GL.IsEnabled(IndexedEnableCap.Blend, index);
The selected blend factors can be queried separately for source and destination by using
The selected blend equation can be queried by using