SpriteBatch and renderstates

2010 update: if you are using a version of XNA Game Studio >= 4.0, see here instead.

If you are mixing 3D rendering with 2D objects using SpriteBatch, you may notice that your 3D graphics no longer draw correctly after you have rendered sprites. This is because the SpriteBatch changes several device renderstates to values that may not be appropriate for drawing in 3D.

An obvious way to avoid this problem is to pass SaveStateMode.SaveState when you call SpriteBatch.Begin, but there is a potential pitfall here. Saving and restoring device state can be slow, so if you do this a lot, your framerate will suffer.

A more efficient approach is to always set whatever renderstates you need before you draw any graphics. SpriteBatch will automatically set what it needs for drawing in 2D, so you just need to set these back to what you want before drawing in 3D.

So exactly which renderstates does SpriteBatch change? Here’s the complete list:

    GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
GraphicsDevice.RenderState.DepthBufferEnable = false;

GraphicsDevice.RenderState.AlphaBlendEnable = true;
GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = false;

GraphicsDevice.RenderState.AlphaTestEnable = true;
GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater;
GraphicsDevice.RenderState.ReferenceAlpha = 0;

GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Clamp;
GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Clamp;

GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Linear;
GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Linear;
GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Linear;

GraphicsDevice.SamplerStates[0].MipMapLevelOfDetailBias = 0.0f;
GraphicsDevice.SamplerStates[0].MaxMipLevel = 0;

SpriteBatch also modifies the Vertices, Indices, VertexDeclaration, VertexShader, and PixelShader properties on the GraphicsDevice.

Many of these settings are fine for both 2D and 3D rendering, but before you draw anything in 3D you will probably want to reset these states:

    GraphicsDevice.RenderState.DepthBufferEnable = true;
GraphicsDevice.RenderState.AlphaBlendEnable = false;
GraphicsDevice.RenderState.AlphaTestEnable = false;

Depending on your 3D content, you may also want to set:

    GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;


Comments (27)

  1. SpriteSortMode.Texture sorts sprites by texture. SpriteSortMode.BackToFront and SpriteSortMode.FrontToBack

  2. Crag says:

    I see SpriteBatch uses DestinationBlend = Blend.InverseSourceAlpha but after it’s done it seems to leave that renderstate set as Blend.DestinationAlpha. Is this the case?

  3. ShawnHargreaves says:

    > I see SpriteBatch uses DestinationBlend = Blend.InverseSourceAlpha but after it’s done it seems to leave that renderstate set as Blend.DestinationAlpha. Is this the case?

    No. SpriteBatch never sets the destination blend state to destination alpha.

  4. Joey says:

    Thanks, this is exactly what I needed.

  5. Ulf says:

    Wow, this just saved my day! Been digging through my 3D rendering code for the last days, figuring it had to be something crazy going on there, but you hit the spot Shawn.

  6. Mihe says:

    Five stars ! Another one saved by this article 🙂

  7. Abe says:

    Thanks! This fixed my problem.

  8. Aozora Shinyuu says:

    Thanks ! It helped me a lot ! There is another reason which can cause polygon glitch through !

    If the Plane values are too sensible, you will get  some polygon colision !

  9. Steven says:

    I spent hours trying to fix this problem, I hate how the hardest things can be fixed with just a few lines, thanks for making me feel like an idiot, lol

    honestly thank you.

  10. Fairuz says:

    thank you so much, I was tearing my hair out over what I was doing wrong…

  11. Dave says:

    Thanks for the info, never thought adding a simple 2D crosshair would cause so many problems…

  12. QQMAX says:

    Thanks, but in WP7. The RenderState is removed….. I do not know how to fix this..

    Do you have any suggestion??

  13. haxpor says:

    Thanks, I thought the same that there’s a hurt to perf when using SaveStates. You just confirm the right way.

  14. nillabomb says:

    thanks you so much!!!! I could not for the life of me figure out why my 3d models were not drawing correctly (eg some meshes were always drawn on top of other meshes no matter the orientation of the model). Turns out I was drawing some sprite batches first and than my 3d models and it messed up the drawing settings for my models. Those three lines fixed it right up!

  15. washka says:

    Thanks man, I've been looking hours to fix this "bug".

  16. Nick says:

    Spent a few days trying to solve an error, went through tonnes of pages before finding this! Cheers!

  17. J says:

    Thanks for this – much appreciated.

  18. Bob says:

    WOW… thank you very, very, very much.  What a time saver.  You're the best.

  19. David says:

    Your link for the XNA v4 version goes to this same page. =(

  20. ShawnHargreaves says:

    Thanks David!

    Link fixed 🙂

  21. Chris says:

    For Windows Phone 7, try this:

               GraphicsDevice.BlendState = BlendState.Opaque;

               GraphicsDevice.DepthStencilState = DepthStencilState.Default;


  22. Jonathan Harbour says:

    Ridiculous, forcing a manual reset of states changed by SpriteBatch. That's sloppy code.

  23. lightwave says:

    it does seem kinda strange to me that you should have to reset what you set up each frame because its fliping your switches off state machine designs are'nt supposed to behave like that

  24. ShawnHargreaves says:

    Really the only sane way to achieve a high performance graphics API is to always set whatever state you need before each piece of drawing code (and use things like state objects to make this setting efficient).

    It's not really feasible to adopt an "if you change something, put it back" policy, because that begs the question, put it back to what? What should the default states be? Every piece of code wants different defaults, and such designs lead to a world of terrible fragility when assumptions change or you try to integrate pieces of code that were written assuming different default states.

    XNA adopts a policy of "assume nothing, and always set everything you care about before drawing anything", which is not only the most robust way to manage renderstates, but also by far the most efficient.

  25. Burak Ucurel says:

    How could they have overlooked the fact that people will no doubt need sprites in 3D games/scenes? Either way this helped a lot, now i can display the HUD with the actual game not looking all wrong and weird. Thanks, 5/5

  26. BitSchieber says:

    Thanks Chris:-)