3. Creating Custom Blend States
Although the built-in blend states will be
appropriate in many situations, sometimes it is useful to be able to
further customize the blend state that XNA uses. There is an enormous
number of combinations of blend states that can be created, and they
are defined using three properties of the BlendState object: ColorBlendFunction, ColorSourceBlend, and ColorDestinationBlend.
They are matched by three similar properties that refer to the alpha channel: AlphaBlendFunction, AlphaSourceBlend, and AlphaDestinationBlend.
On Windows and Xbox platforms they can be set independently of the
color properties to create even more combinations of blending
operations, but on Windows Phone 7 they must exactly match the
corresponding color properties or XNA will throw an exception.
The way in which blending is performed using these
properties is consistent and understandable on a mathematical level,
but can sometimes require a little experimentation to achieve the
desired effect. As we saw with the Additive blend, a calculation is
performed against the individual red, green, and blue components of the
source and destination colors in order to obtain the final color that
will appear on the screen.
The calculation is as follows:
(source color x ColorSourceBlend) ColorBlendFunction (destination color x ColorDestinationBlend)
For each pixel that XNA renders to the screen, it
first takes the red, green, blue, and alpha elements of the source
color (the color of the pixel being rendered from the texture) and
multiplies them by the corresponding elements from the ColorSourceBlend value. It then repeats this with the color of the pixel already present on the screen, multiplying it by the ColorDestinationBlend elements.
With these two colors calculated, they are combined using the appropriate ColorBlendFunction.
We will look at all the available options for them
in a moment, but before we do that let's pick a simple example to
demonstrate this calculation.
One of the available blend types is Blend.One, which provides the value 1.0 for each of the red, green, blue, and alpha color elements. Another factor is Blend.Zero, which provides the value 0.0 for each color component. Finally we have a blend function named BlendFunction.Add which simply adds the source and the destination color element values together.
If we use Blend.One as the source blend,Blend.Zero as the destination blend, and BlendFunction.Add as the blend function, the color for each pixel is calculated as follows:
Rednew = (Redsource x 1.0) + (Reddest x 0.0)
Greennew = (Greensource x 1.0) + (Greendest x 0.0)
Bluenew = (Bluesource x 1.0) + (Bluedest x 0.0)
As you can see, the end result if these blending
parameters are used is that the object is rendered absolutely opaque;
no blending takes place at all. The output colors calculated are
exactly the same as the source colors, with the existing destination
color completely ignored. This is in fact the configuration that is
provided by the BlendState.Opaque object. The code to configure this blend state is shown in Listing 3.
Example 3. Manually configuring a BlendState object for opaque blending
// Create a new BlendState object BlendState blendState = new BlendState();
// Set the color blend properties blendState.ColorBlendFunction = BlendFunction.Add; blendState.ColorSourceBlend = Blend.One; blendState.ColorDestinationBlend = Blend.Zero;
// Copy the color blend properties to the alpha blend properties blendState.AlphaBlendFunction = blendState.ColorBlendFunction; blendState.AlphaSourceBlend = blendState.ColorSourceBlend; blendState.AlphaDestinationBlend = blendState.ColorDestinationBlend;
// Set the object into the GraphicsDevice GraphicsDevice.BlendState = blendState;
|
NOTE
The initial configuration of a newly instantiated BlendState object is exactly the same as that of the built-in BlendState.Opaque object.
Let's take a look at a different pair of blend types. We will use Blend.SourceAlpha for the source blendand combine it withBlend.InverseSourceAlpha for the destination.SourceAlpha provides the source color's alpha value, whereas InverseSourceAlpha
providesthe source color's alpha subtracted from 1 (so a source alpha
of 1 becomes 0, a source of 0 becomes 1, a source of 0.2 becomes 0.8,
and so on). Using BlendFunction.Add once again, the output color of each pixel is therefore calculated as follows:
Rednew = (Redsource x Alphasource) + (Reddest x (1 - Alphasource))
Greennew = (Greensource x Alphasource) + (Greendest x (1 - Alphasource))
Bluenew = (Bluesource x Alphasource) + (Bluedest x (1 - Alphasource))
Think for a moment about the results of this
calculation. If the source alpha is 1 (opaque), the calculation will
take the entire source color (because it is being multiplied by 1) and
none of the destination color (because it is being multiplied by 0).
The result will be that the pixel is rendered opaque.
If, on the other hand, the source alpha is 0
(transparent), the calculation will take none of the source color (as
this is being multiplied by 0) and all the destination color (because
it is being multiplied by 1). The result will be that the pixel is
rendered entirely transparent.
Alpha values that fall between 0 and 1 will provide
a gradual transition between transparent and opaque. This is exactly
the effect that we need for rendering textures onto the screen so that
they observe the image's alpha channel.
The available Blend enumeration values are shown in Table 1.
The Values column uses the characters R, G, B, and A to refer to the
red, green, blue, and alpha color components; and adds a subscript of s
or d to identify whether this relates to the source or destination
color.
Table 1. Blend Types
Blend | Description | Values |
---|
One | All color elements are set to 1 | (1, 1, 1, 1) |
Zero | All color elements are set to 0 | (0, 0, 0, 0) |
SourceColor | The color elements of the pixel in the source texture | (Rs, Gs, Bs, As) |
InverseSourceColor | The inverse color elements of the pixel in the source texture (each subtracted from 1) | (1 – Rs, 1 – Gs, 1 – Bs, 1 – As) |
SourceAlpha | The alpha value of the pixel in the source texture | (As, As, As, As) |
InverseSourceAlpha | The inverse alpha value of the pixel in the source texture | (1 – As, 1 – As, 1 – As, 1 – As) |
DestinationColor | The color elements of the pixel currently displayed on the screen | (Rd, Gd, Bd, Ad) |
InverseDestinationColor | The inverse color elements of the pixel currently displayed on the screen | (1 – Rd, 1 – Gd, 1 – Bd, 1 – Ad) |
DestinationAlpha | The alpha value of the pixel currently displayed on the screen | (Ad, Ad, Ad, Ad) |
InverseDestinationAlpha | The inverse alpha value of the pixel currently displayed on the screen | (1 – Ad, 1 – Ad, 1 – Ad, 1 – Ad) |
BlendFactor | The color elements of the graphic device's BlendFactor color | (Rblendfactor, Gblendfactor, Bblendfactor, Ablendfactor) |
InverseBlendFactor | The inverse color elements of the blend factor color | (1 – Rblendfactor, 1 – Gblendfactor, 1 – Bblendfactor, 1 – Ablendfactor) |
SourceAlphaSaturation | Either the source alpha or the inverse of the destination alpha, whichever is less | (f, f, f, 1), where f is the calculation max(As, 1 – Ad) |
The ColorBlendFunction can be set to any of the values shown in Table 2. Remember that each of them operates on the red, green, blue, and alpha values independently to calculate the final color.
Table 2. Blending Functions
BlendFunction | Description |
---|
Add | The color is calculated by adding the source and destination colors:
Output = (source color * source blend) + (dest color * dest blend)
|
Subtract | The color is calculated by subtracting the destination color from the source:
Output = (source color * source blend) – (dest color * dest blend)
|
ReverseSubtract | The color is calculated by subtracting the source color from the destination:
Output = (dest color * dest blend) – (source color * source blend)
|
Min | The color is calculated by finding the lesser value from the source and destination colors:
Output = Min( (source color * source blend), (dest color * dest blend))
When using Min on Windows Phone 7, the source and destination blend
functions must both be set to Blend.One, or XNA will throw an exception. |
Max | The color is calculated by finding the greater value from the source and destination colors:
Output = Max( (source color * source blend), (dest color * dest blend))
When using Max on Windows Phone 7, the source and destination blend
functions must both be set to Blend.One, or XNA will throw an exception. |
A huge range of effects can be obtained using
different combinations of these functions and blendtypes. Try
experimenting with them inside the AlphaBlending example project to see some of the results that you can obtain.
4. Object Transparency
One very useful rendering feature that we've not yet
seen support for in this section is the ability to fade an entire
object between opaque and transparent.
The reason is simply because the alpha value is stored in a separate property. Each Effect object (including BasicEffect) has an Alpha
property that can be given a value between 0 (invisible) and 1
(opaque). All the source alpha values within the object will be
multiplied by this to generate the value for the SourceAlpha blend. Providing your blend state observes the source alpha, you can therefore use the Alpha property to fade your objects between opaque and transparent and still observe the alpha information stored in your textures.