XNA offers us support for dealing with
transparency when we render our graphics. We can achieve various
effects with this, such as removing transparent parts of an image or
drawing an image so that it is semitransparent, allowing the graphics
behind to show through. This is known as alpha blending.
In this section we'll look at the available alpha blending options and learn how you can customize them for your games.
1. Enabling and Disabling Alpha Blending
In order to take advantage of alpha blending, we need to instruct XNA to use a blend state
object. This contains information that XNA will use to determine
exactly how to mix the pixels of the objects that it is drawing with
the pixels that are already present on the screen.
This might be as simple as determining whether to
completely replace an existing pixel or leave it with its current
color, or it might involve a blend of the existing pixel and the pixel
from the rendered object.
The active BlendState object can be found in the GraphicsDevice.BlendState property. The object can be interrogated, but its properties cannot be updated: just like the SamplerState objects we saw in the last section, a BlendState object's properties all become read-only once it has been set into the GraphicsDevice.
To alter the active BlendState, we must create a new BlendState object, configure its properties, and only then pass it to the GraphicsDevice, as can be seen in Listing 1. Once again, it is important to avoid doing this inside your Update or Draw functions: any required BlendState objects should instead be created just once during initialization and then reused as and when needed.
Example 1. Creating and activating a new BlendState object
// Create a new BlendState object BlendState blendState = new BlendState(); // Set blend state object properties //... // Set the object into the GraphicsDevice GraphicsDevice.BlendState = blendState;
|
To disable alpha blending, the BlendState property should be set to BlendState.Opaque, as shown in Listing 2.
There are two reasons why it is very important to remember to disable
alpha blending as soon as you have finished with it. First, alpha
blending has a higher processing overhead on the graphics hardware than
opaque rendering because it needs to consider the pixels already on the
screen as well as those being rendered. Second, having blending active
when you are not expecting it to be can produce very confusing results
in your game, causing objects to become transparent or even disappear.
Example 2. Disabling alpha blending
// Switch to the Opaque blend state GraphicsDevice.BlendState = BlendState.Opaque;
|
2. XNA's Built-In Blend States
There are some transparency effects that are more
frequently used within games than others, and to simplify using these
effects XNA provides a series of static objects whose properties
reflect this. Before we get into the complexities of how alpha blending
actually works, let's take a look at some of these states and describe
the purpose and use of each. We will look at how the blend states work
under the covers later in this section.
Throughout this section we will describe colors and
alpha values as float values rather than as integers. This means that
they will always be in the range of 0 to 1, rather than 0 to 255. The
reason for this will become apparent later in the section.
You can experiment with these blend states by opening the AlphaBlending example project and changing the state that is set at the end of the Initialize function.
2.1. Opaque
The BlendState.Opaque reference that we saw in Listing 2 is not an enumeration as it might at first appear, but is in fact one of the built-in blend state objects. Opaque is a static property on the BlendState class that returns a BlendState object configured with alpha blending disabled.
With opaque blending active, every pixel rendered
from the source texture will be written to the screen so that it
entirely replaces the content that is already present.
Figure 1 shows the Grapes texture rendered using the opaque blend mode.
2.2. AlphaBlend
A particularly useful blend state is AlphaBlend,
which is actually the mode that we were using with sprites when an
alpha channel or a color key was present. This mode reads the alpha
value from the source texture and uses it to determine how opaque the
pixel should be when rendered on top of the existing graphics.
Pixels whose alpha values are 0.0 within the texture
will be rendered entirely transparent (invisible). Pixels whose alpha
values are 1.0 are rendered entirely opaque. Alpha values between them
will result in varying levels of semitransparency. This is therefore
ideal for textures that contain an alpha channel or color key because
it allows them to be rendered with sections that are partially or
completely transparent.
Figure 2 shows the Grapes textures once again, this time rendered with the AlphaBlend blend state.
2.3. Additive
Setting the blend state to BlendState.Additive
applies another blend that takes into account the existing graphics
that have already been displayed on the screen and also the alpha
information contained within the texture being rendered.
This time, however, the colors of the pixels being
rendered are added to the colors on the screen, rather than replacing
them. Colors are added by taking their individual red, green, and blue
color elements, multiplying them by the texture's alpha value to make
them observe the texture transparency information, and then finally
adding them to the existing red, green, and blue color values already
present on the screen. This might well result in some of the elements
exceeding their maximum level of 1.0. When this happens, they are
clamped to 1.0.
If, for example, the screen were filled with a dark
green color whose RGB values are (0.0, 0.5, 0.0), and we render a solid
red texture with RGB values (1.0, 0.0, 0.0) and full alpha (1.0), the
resulting calculation would be as follows:
Rednew = (Redsource x Alpha) + Reddest = (1.0 × 1.0) + 0.0 = 1.0
Greennew = (Greensource x Alpha) + Greendest = (0.0 × 1.0) + 0.5 = 0.5
Bluenew = (Bluesource x Alpha) + Bluedest = (0.0 × 1.0) + 0.0 = 0.0
The resulting color will have RGB values (1.0, 0.5,
0.0)—an orange color. If we had a yellow color already on the screen
(1.0, 1.0, 0.0) and we rendered a purple texture (1.0, 0.0, 1.0) with
an alpha value of 0.5, the final color would be calculated as follows:
Rednew = (Redsource x Alpha) + Reddest = (1.0 × 0.5) + 1.0 = 1.5
Greennew = (Greensource x Alpha) + Greendest = (0.0 × 0.5) + 1.0 = 1.0
Bluenew = (Bluesource x Alpha) + Bluedest = (1.0 × 0.5) + 0.0 = 0.5
The resulting color would be (1.0, 1.0, 0.5) as the red value would be clamped at 1.0. This is a pale yellow color.
Because additive blending is adding two colors
together, repeated rendering of the same area on the screen pushes the
color toward full red, green, and blue intensity. If the colors being
mixed contain elements of all three color components, the color will
tend toward white.
Figure 3
shows the grape textures rendered with additive blending. The color of
the background is being retained and mixed with the texture as it is
drawn, resulting in a blue tinge across everything, and cyan leaves on
the grapes as the texture's green color and the screen's blue color are
mixed together.