Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Phone

Developing for Windows Phone and Xbox Live : Device States (part 1) - BlendState

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
6/9/2011 5:05:00 PM
In previous versions, there were three main objects used to control the graphics device state: namely the RenderState object, the SamplerState object, and the StateBlock object. As the names implied, the first controlled various rendering states, the second sampler states (textures), and the last was a way to control an entire “block” of states.

The StateBlock objects looked very useful, but in reality, they were a bit confusing to understand, and the performance of them was abysmal. Even when people used them correctly, the performance hit for using them was enough that they would have been better off not using them at all!

Knowing this, the object type was completely removed for Game Studio 4. Various features that relied on this type (such as the SaveStateMode enumeration) were also removed. Don’t worry, though, we made using the states themselves so much easier that you won’t even miss it being gone.

The SamplerState object still exists, although it’s behavior and members have changed. The RenderState object has changed quite drastically. It has mainly split into three new objects: BlendState, RasterizerState, and DepthStencilState. Again, as the name implies, these objects control the blending and rasterization of the scene, along with the depth and stencil buffer options.

Each of these new state objects has a number of properties that they control, and when they are set on the device, all of the properties are set at once. This enables you to easily set a wide variety of states in a single call, where in previous versions the same operation could take quite a few separate calls.

BlendState

One of the most common states you’ll want to change is the BlendState object, which controls how each color in your scene blends with another. At a high level, the blend operation is little more than taking two colors, performing some operation on them, and returning a third blended color. The first color is normally called the source color, and the second color is called the destination color. Knowing this, the actual formula for blending is quite simple:

output = (sourceColor * sourceBlendFactor) blendFunction (destColor * destBlendFactor)

There are several different permutations of this. The following example demonstrates the differences. As they say, pictures are worth a thousand words! Create a new Windows Game project. Add a new item that is a sprite font called Font, and add a piece of content from the accompanying CD, namely alphasprite.png. This is used to easily show the differences in state. Add the following variables to your game class:
SpriteFont font;
Texture2D background;
Texture2D alphaImage;
Texture2D red;

To load and create these as well, add the following to your LoadContent overload:

font = Content.Load<SpriteFont>("font");
alphaImage = Content.Load<Texture2D>("alphasprite");
background = new Texture2D(GraphicsDevice, 1, 1);
background.SetData<Color>(new Color[] { Color.CornflowerBlue });
red = new Texture2D(GraphicsDevice, 1, 1);
red.SetData<Color>(new Color[] { Color.Red});

This example shows the difference between the various blending modes. To do this, you have one background image (that is the destination color) that is the ubiquitous cornflower blue color and one source image (which includes the source color), which is either a solid red color or the data in the alpha sprite. Replace your Draw overload to include the rendering of the background:

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(background, GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}


To render your source image easily and compare how it is rendered, add the following method, which helps render the source image with varying blend states:

private void DrawBlendedImage(BlendState blend, string text, Texture2D image, Point position, Point size)
{
// Draw the source image on top opaque
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
spriteBatch.Draw(image, new Rectangle(position.X, position.Y,
size.X, size.Y), Color.White);
spriteBatch.End();
Vector2 measure = font.MeasureString(text);
spriteBatch.Begin();
spriteBatch.DrawString(font, text, new Vector2(position.X,
position.Y + size.Y + 2), Color.White);
spriteBatch.End();
// Draw the blended version now
spriteBatch.Begin(SpriteSortMode.Deferred, blend);
spriteBatch.Draw(image, new Rectangle(position.X,
position.Y + size.Y + (int)measure.Y + 2,
size.X, size.Y), Color.White);
spriteBatch.End();
}


There are several sprite batch begins and ends in this code, because you need to draw the images differently so you can tell the difference. After you set the blend mode for a sprite batch, it cannot be changed. Because you draw things with (potentially) different blend modes, you need a separate sprite batch Begin/End pair for each.

The first call draws the source image using the built-in BlendState.Opaque object. The built-in objects are described more in depth in a moment, but for now, this object replaces the destination color with the source, ignoring alpha blending. This enables the source image to be rendered without any blending at all. The source image is drawn at the position passed into this helper method.

Next, draw some text describing which blend operation is shown here. Rendering text requires alpha blending to be enabled, so use the default sprite batch Begin call (which uses SpriteSortMode.Deferred and BlendState.AlphaBlend). Also use the MeasureString call on the font so you know how big it is (so you can start the blended image at the correct spot).

Finally, use your last Begin/End pair to draw the image with the specified blending state. During this next section of code, you create state objects on the fly, and every frame. Although this certainly works, it is a bad idea. It creates garbage, and unnecessarily makes your game run slower. In a real game, these are cached and reused.

Warning

You should not create new state objects every frame. This example does it for clarity reasons.


Before you create your new blend object and call the helper function, add two more helper functions to easily calculate the point and size parameters you pass in to DrawBlendedImage:

const int size = 80;
Point GetPoint(int i)
{
return new Point(10 + ((i % 9) * (size + 6)), 10 + ( (i/9) * (size * 2 + 50) ) );
}
Point GetSize()
{
return new Point(size, size);
}

These simply offset the point by a factor of the size based on the index of the current call. Now add the following code before the base.Draw call in your Draw overload:
int i = 0;
BlendState currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "One", red, GetPoint(i++), GetSize());

Note

After you set a particular state onto the device, it becomes immutable (you can no longer change it). You need to have separate state objects for each permutation you plan on using.


In the previous formula, the blended color for this image is the following:

output = (sourceColor * 1) + (destColor * 1)

Essentially, you add the two colors. Can you predict what it would look like without running the example? If you guessed that it would look like a brighter version of the source red, you’d be correct. Let’s look at why this is using real numbers in the formula. Assume the source color is RGB (Red, Green, Blue) of (255,0,0) and the destination color is (0,0, 255). You have the following:

output = ( (255,0,0) * 1) + ((0,0,255) * 1)
output = (255,0,0) + (0,0,255)
output = (255,0,255)

Pure red added with pure blue gives you a purple color. What if your source and destination colors were the same, and they were each (127,127,127) a mid-gray? Using this formula for the colors gives you the following:

output = ( (127,127,127) * 1) + ((127,127,127) * 1)
output = (127,127,127) + (127,127,127)
output = (254, 254, 254)

This gives you almost a pure white. Adding can be a powerful way to blend. However, what if you wanted to subtract instead? Add this code before your base.Draw call in your Draw overload:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Subtract;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "SubOne", red, GetPoint(i++), GetSize());

Can you predict what this one will do? This is simply the opposite of the addition, so you should see a dark version of the source image. Using the previous examples, if you use both source and destination colors of (127,127,127), it returns pure black (0,0,0). If you use a source color of purple (255,0,255) and a destination of red (255,0,0), it returns pure blue (0,0,255).

Here’s an interesting one. Add the following code:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.ReverseSubtract;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "RSubOne", red, GetPoint(i++), GetSize());

The ReverseSubract value is similar to the Subtract operation except, reversed. At a high level, instead of source-dest, this is dest-source. The formula is the following:

output = (destColor * 1) - (sourceColor * 1)

Knowing this, can you predict what this output color would be? If you guessed it would appear to be a negative of the source image, then bravo for you again! Let’s discuss the last two blend functions. Add the following code:

currentBlend = newBlendState();
currentBlend.ColorBlendFunction = BlendFunction.Min;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "Min", red, GetPoint(i++), GetSize());
currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Max;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "Max", red, GetPoint(i++), GetSize());

These two functions are basically self-explanatory. It looks at both pixel colors and picks the largest value if you specified Max, and the smallest value if you specified Min. You see a brighter image for the max function and a darker image for the min function.

Note

The Max and Min values of the BlendFunction enumeration require that both the source and destination use Blend.One.


For each of these examples so far, you used Blend. One for both the source and destination. This is easy to understand because it simply leaves the color unchanged; however, there are quite a few different blend operations available. Blend.Zero is just as easy to understand, because it multiplies the color by zero, effectively ignoring it (depending on the blend function, of course).

To set the blend operation to simply use the source or destination color, add the following code:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.SourceColor;
currentBlend.ColorDestinationBlend = Blend.Zero;
DrawBlendedImage(currentBlend, "2xSrc", red, GetPoint(i++), GetSize());

Notice that you use the blend operation for the source to be the source color. It doesn’t mean that you are simply using the color as is! Remember the formula, plugging in the data gets you the following:

output = (sourceColor * sourceColor) + (destColor * 0)

Using this essentially doubles the amount of the source in the final color. You can do the same with the following destination:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.Zero;
currentBlend.ColorDestinationBlend = Blend.DestinationColor;
DrawBlendedImage(currentBlend, "2xDest", red, GetPoint(i++), GetSize());

This makes the following formula:

output = (sourceColor * 0) + (destColor * destColor)

Again, it essentially doubles the destination color. Now, you can also use the inverse of either of these colors by choosing InverseSourceColor or InverseDestinationColor. Calculate the values by subtracting the current color value from the maximum color value for the channel; for example, if you used single byte RGB values such as solid green (0,255,0), inversing this color gives you (255 - 0, 255 - 255, 255 - 0) or a purple color of (255,0,255). Using the inverse of a color on itself cancels itself out, as you can see in the following code:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.InverseSourceColor;
currentBlend.ColorDestinationBlend = Blend.One;
DrawBlendedImage(currentBlend, "InvSrc", red, GetPoint(i++), GetSize());
currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.InverseDestinationColor;
DrawBlendedImage(currentBlend, "InvDest", red, GetPoint(i++), GetSize());

If you look at the formula, it makes sense (for example, for the first state):

output = (sourceColor * inv(sourceColor)) + (destColor * 1)
output = (destColor * 1)

However, you can just as easily blend with the opposite colors.

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.DestinationColor;
currentBlend.ColorDestinationBlend = Blend.SourceColor;
DrawBlendedImage(currentBlend, "Swap", red, GetPoint(i++), GetSize());

This makes the following formula:

output = (sourceColor * destColor) + (destColor * sourceColor)

You can even use the inverse of the colors swapped.

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.InverseDestinationColor;
currentBlend.ColorDestinationBlend = Blend.InverseSourceColor;
DrawBlendedImage(currentBlend, "InvSwap", red, GetPoint(i++), GetSize());

Let’s discuss the last blend operation, BlendFactor (and it also has the InverseBlendFactor to go along with it). This essentially lets you blend either of your colors with an arbitrary color of your choice, for example:

currentBlend = new BlendState();
currentBlend.ColorBlendFunction = BlendFunction.Add;
currentBlend.ColorSourceBlend = Blend.One;
currentBlend.ColorDestinationBlend = Blend.BlendFactor;
currentBlend.BlendFactor = Color.Blue;
DrawBlendedImage(currentBlend, "Factor", red, GetPoint(i++), GetSize());

This makes the formula for the output color the following:

output = (sourceColor * 1) + (destColor * blue)

Given the red color of the source image and the slightly blue background color, this color ends up as a bright purple. A common use of a blend factor is to have it change over time to perform fancy effects.

Note

It is unreasonable to force someone to use a new state object for every blend factor (remember that the state objects are immutable). Therefore, use a BlendFactor property on the graphics device to override what is in the state object. Note that the graphics device’s value is updated when the state is applied, so make sure you change it only after the state is set.


There are two more properties to discuss briefly. First are the ColorWriteChannel properties (there are four total) that specify which color channels can be written during the blend operation. Each channel corresponds to a render target, and by default it writes all the channels.

The MultisampleMask property enables you to control which samples are valid for multisampling. By default, all bits are on, so all samples are valid, but you can change this on the fly.

Note

Like BlendFactor, MultisampleMask is also a property on the device so it can be changed without using the blend state.


Premultiplied Alpha

Another change in this release of Game Studio involves the default mechanism used to perform alpha blending. In previous versions, “normal” interpolated blending was performed for alpha blending, which in the formula you’ve been using now was defined as:

output = (sourceColor * sourceAlpha) + (destColor * inv(sourceAlpha))

This was the standard way to declare transparency, but in Game Studio 4.0, the default changed to premultiplied alpha. This mode assumes that the color’s RGB values are multiplied by the alpha value before the blend takes place (hence, the term premultiplied), and the formula for this alpha blending is the following:

output = sourceColor + (destColor * inv(sourceAlpha)

This is similar to the original one, but subtly different enough to matter. Game Studio’s defaults changed to use premultiplied alpha because (while it is not perfect) in the majority of cases, it is the blending mode that most developers actually want in the first place. Plus, it is easy to switch back to the old default way of blending.

What does it mean that Game Studio uses premultiplied alpha as the default? Look at the properties of the AlphaSprite.png that you added to your content project. Under the texture content processor, notice a property for PremultipliedAlpha that is set to true. This means that during build time when the content pipeline is processing this texture, for each pixel that it processes it premultiplies the alpha in this formula:

pixelColor.rgb *= pixelColor.a;

Add the following code to your project to see how the alpha computation changes:

DrawBlendedImage(BlendState.AlphaBlend, "Alpha", alphaImage, GetPoint(i++), GetSize());


If you render this now, the source image has a black background where the alpha channel is when drawn opaque, with a transparent background and the image showing up alpha blended below it. Now, go to the properties of AlphaSprite.Png and change the PremultipliedAlpha value to false. Run the application, and notice that the top and bottom images look the same, and rather than a black background, it has a white background with no alpha blending at all.

I’m sure you can guess why. The blend operation expects the alpha value to be premultiplied, and it is not. The background turned white because without the premultiplication multiplying the 0 alpha value with the white RGB value, returning a 0 RGB value of black, it maintains the white color. However, add the following code to the project:

DrawBlendedImage(BlendState.NonPremultiplied, "NPAlpha",
alphaImage, GetPoint(i++), GetSize());

Because the image isn’t premultiplied anymore, this shows the image normally alpha blended. Lastly, switch the image back to PremultipliedAlpha true. Notice that now both premultiplied and non-premultiplied seem to render alpha blended, and appear to look identical. This is because this particular image only has an alpha value of completely on or completely off. There are no partial alpha values, so the two blend operations come up with the same values. This wouldn’t be the case otherwise.

Whew, that was a long discussion about blending. There are a number of built-in blend states for the more commonly used operations as well that are static objects off of the BlendState itself. These include Opaque, Alphablend, Additive, and Nonpremultiplied. After all that, running the app gives you quite a few examples of varying blend modes, much like you see in Figure 1.

Figure 1. An example of blending states
Other -----------------
- Developing for Windows Phone and Xbox Live : Using SkinnedEffect
- Developing for Windows Phone and Xbox Live : Using AlphaTestEffect & Using EnvironmentMapEffect
- Developing for Windows Phone and Xbox Live : Using the Effect Interfaces & Using DualTextureEffect
- Developing for Windows Phone and Xbox Live : Using BasicEffect (part 2) - Textures, Vertex Colors, and Fog
- Developing for Windows Phone and Xbox Live : Using BasicEffect (part 1) - Basic Lighting
- Developing for Windows Phone and Xbox Live : Camera Types & Models
- Developing for Windows Phone and Xbox Live : Projection Matrix
- Developing for Windows Phone and Xbox Live : View Matrix
- Programming Windows Phone 7 : Pivot and Panorama - The XNA Music Classes: MediaPlayer
- Programming Windows Phone 7 : Pivot and Panorama - Displaying the Albums
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server