Shawn Hargreaves Blog
A repost of one of my more popular articles, upgraded for Game Studio 4.0...
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 states to values that may not be appropriate for drawing in 3D.
So exactly which states does SpriteBatch change? Here's the complete list:
GraphicsDevice.BlendState = BlendState.AlphaBlend;
GraphicsDevice.DepthStencilState = DepthStencilState.None;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates = SamplerState.LinearClamp;
SpriteBatch also modifies the vertex buffer, index buffer, and applies its own effect onto the GraphicsDevice.
Before you draw anything in 3D you will probably want to reset these states:
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
Depending on your 3D content, you may also want to set:
GraphicsDevice.SamplerStates = SamplerState.LinearWrap;
Its's great to see that you are having time to put up more brilliant posts again.
What about the GraphicsDeclaration .. ?
> What about the GraphicsDeclaration .. ?
What is a GraphicsDeclaration? No such type in XNA...
Sorry meant to say VertexDeclaration, like you didn't know that ;)
As side from re-setting the state of my GraphicsDevice, shouldn't I also re-set the VertexDeclaration?
My code usually instanciates the VertexDeclarations somewhere during initialization and they are set on the GraphicsDevice right before filling the VertexBuffer when drawing something in 3d. But if figured that if the BasicEffect overrides the VertexDeclaration it might be good to point that out here too.
> As side from re-setting the state of my GraphicsDevice, shouldn't I also re-set the VertexDeclaration?
There is no such thing as GraphicsDevice.VertexDeclaration in Game Studio 4.0, so no need to reset that.
So when, when, when?
Hi, i'm getting this strange exception on Windows Phone 7 emulator (April refresh) when trying to render a simple texture with SpriteBatch: "XNA Framework Reach profile requires TextureAddressMode to be Clamp when using texture sizes that are not powers of two.". I googled it and the only search result was in your twitter :)
The texture i'm using is not a power of two, but here are the strange facts:
1. I render some geometry to a fullscreen 480x800 RenderTarget and use SpriteBatch to render it to the screen. After this, i draw the non power of 2 texture with SpriteBatch and the exception is thrown.
2. I tried passing PointClamp and LinearClamp to the Begin() method of SpriteBatch, but the exception is thrown anyway.
3. If i don't render the previous geometry and rendertarget, the SpriteBatch is drawn correctly with no exception (even though it's size is non power of two)!
4. If i force a power of two size in the ContentPipeline for the texture, everything is fine, i get the geometry/rendertarget and this particular texture drawn to the screen!
Well... do you think this is some kind of bug? Some kind of optimization that's not working correctly in SpriteBatch? It seems like PointClamp or LinearClamp are getting lost somewhere with the previous draw code. Or am i missing something with SpriteBatch behaviour....
If you need further info, please tell me, i regularly read your wonderful blog.
Artur: look in the debugger to see what textures and sampler states are bound onto the device when this exception is thrown (not just on index 0 - are you using dual texture anywhere so you maybe have some non-pow-2 and wrap states set on the second sampler index?)
After further testing and debugging, i found the problem... well, i don't know if this is by design or if it just a minor issue. It has nothing to do with rendertargets and is very obvious how to work around.
I have the next code:
basicfx = new BasicEffect(graphicsDev);
basicfx.VertexColorEnabled = false;
basicfx.TextureEnabled = false; // <--- Texturing disabled
basicfx.LightingEnabled = false;
basicfx.FogEnabled = false;
basicfx.Texture = this.texNormalHex; // <---- Non power of two texture
After this, i was drawing a batch of triangles with this BasicEffect effectpass applied. Well, it seems even though texturing is disabled for this BasicEffect, if we don't explicitily set:
graphicsDev.SamplerStates = SamplerState.LinearClamp; // or any other *Clamp
... then the render will fail unpredictably further down the Draw() method (in my case it was launching the exception in spriteBatch.End). I thought that SamplerState wouldn't be used since TextureEnabled is false.
Thanks, hope this is useful for anyone with similar problems.
Gah! I didn't know there was that article around for 3.1. I ended up ripping open the 3.1 dll in Reflector to figure out what settings were being changed.
Thanks for posting this. I'll remember it if I need to fiddle with settings for 4.0.
Thanks a ton, this fixed my bugs in a game I'm working on. I couldn't figure out for the life of me why some triangles were being drawn in front of others.
what about GraphincsDevice.RenderState.CullMode = CullMode.None;
doesn't seem to wanna work in 4.0
Brent: see blogs.msdn.com/.../state-objects-in-xna-game-studio-4-0.aspx
Am I missing something? Because I do these resets in my draw method before I draw my 3D graphics (simple primitives) and then I draw my 2D graphics after that. However my 3D graphics still get messed up after the first iteration of Draw(). Is there something I might be missing?
Adam Goss: I had problem with SpriteBatch and displaying wireframe of 3D model. When i added SpriteBatch, wireframe was gone. Tried suggested reset steps, but none of them worked. Then i tryed setting GraphicsDevice.RasterizerState to my wireframe state right AFTER spriteBatch.End(), but BEFORE calling Draw on model. Maybe your issue is same?