Thursday, April 28, 2011

Using state objects in XNA

Changing render states in shaders can become very inefficient and cumbersome. Another option is to use state objects, these are classes already existent in the XNA framework that we can use to set all the required rendering settings in a easy and efficient way. This post is more for orientation purpose than an actual reference.

State objects hold a set of different setting for the graphics card, these settings will be set all at once (making them more efficient). Changing states does take some so you should group objects with the same state settings to be drawn together. Once a state object is set it becomes immutable and can't be changed, it is also recommended that you create all the required state objects once (at game start) and use them so you don't have to create them at runtime.

First of all you have to create your state object (I'm going to use C# object initialize syntax here):

    BlendState myBlendState = new BlendState()
        AlphaBlendFunction = BlendFunction.Add,
        AlphaDestinationBlend = Blend.InverseSourceAlpha,
        AlphaSourceBlend = Blend.One

This king of syntax really helps organizing our code, also in this syntax you can't set a property  twice. After creating our blend state with all required settings we can set it to the graphics device (we should set our state object right before rendering all our geometry that uses this state object):

    GraphicsDevice.BlendState = myBlendState;

In XNA we actually have 4 state classes, all of the state classes have some build-in objects, these are:
  • BlendState
    • Opaque
    • AlphaBlend
    • Additive
    • NonPremultiplied
  • DepthStencilState
    • None
    • Default
    • DepthRead
  • RasterizerState
    • CullNone
    • CullClockwise
    • CullCounterClockwise
  • SamplerState
    • PointWrap
    • PointClamp
    • LinearWrap
    • LinearClamp
    • AnisotropicWrap
    • AnisotropicClamp
I will not into any more detail about them as everything the reference on MSDN is really great.

If at any point you need to revert back to the default behavior these are the settings you have to set:

    GraphicsDevice.BlendState = BlendState.Opaque;
    GraphicsDevice.DepthStencilState = DepthStencilState.Default;
    GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
    GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;

Starting from this point I will use these state objects instead of the shader settings approach, even if I like writing shaders more we should consider efficiency and commodity too.

No comments:

Post a Comment