Sign in to follow this  
harlock1975

[XNA] ScissorRectangle not working

Recommended Posts

Hi everyone, I am new here but I am afraid I will be bothering you often in the near future :)
In the last couple of months I started to develop a simple "match 3" 2D game in XNA but I am now stuck with the following problem.
Long story short, the main game screen has a background and a "board area" where all the tiles are drawn, everything is working but I'd like to clip the board area so that objects that move out of it are not drawn over the background but are clipped.
I read that I could use the ScissorRectangle BUT I cannot manage it to work.
I tried the following approaches
- use the same SpriteBatch and set RasterizerState (with ScissorTestEnable set to true) -> no clipping occurs
- use a nested SpriteBatch for the board (even without ScissorRectangle set) -> board is not drawn!!!
So actually I have two questions
1. how can I have the ScissorRectangle working?
2. is there an explanation/tutorial/sample on how the various parameters of a SpriteBatch object affect rendering?
Thanks in advance, I hope to post some screenshots soon!!!

Share this post


Link to post
Share on other sites
Are you using the SpriteBatch.Begin() overload the allows you to specify a RasterizerState or are you setting it manually?

Enabling scissor testing separately from the SpriteBatch does, for some reason, not work. Probably the SpriteBatch applies its own RasterizerState immediately before drawing.

I have used the aforementioned SpriteBatch.Begin() overload sucessfully im my GUI library to clip controls like this:

[source lang="csharp"]
// Initialization
this.rasterizerState = new RasterizerState() {
ScissorTestEnable = true
};

// Each frame
this.spriteBatch.Begin(
SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, this.rasterizerState
);
this.graphics.ScissorRectangle = clipRegion;
// ...drawing code...
this.spriteBatch.End();
[/source]

Share this post


Link to post
Share on other sites
Aye, Spritebatch has its own default render states it sets if you do not pass in a custom one. Another thing to remember is that sprite batch will -not- reset states after End() is called. XNA 4.0 follows and encourages a "[url="http://blogs.msdn.com/b/shawnhar/archive/2010/04/02/state-objects-in-xna-game-studio-4-0.aspx"]only set the states you need"[/url] paradigm in this respect. The default states are:

BlendState.AlphaBlend
SamplerState.LinearClamp
DepthStencilState.None
RasterizerState.CullCounterClockwise

Additionally, the [url="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.begin%28v=XNAGameStudio.40%29.aspx"]MSDN docs[/url] help with stuff like this.

As for your approaches...what do you mean by a "nested" sprite batch? It is not advised to have two sprite batches calling Begin() after each other, each drawing, then each calling End() because one of them is going to be interfering with the other in what states are set, etc.

Share this post


Link to post
Share on other sites
First of all thanks to both!

[quote name='Cygon' timestamp='1318760085' post='4873086']
Are you using the SpriteBatch.Begin() overload the allows you to specify a RasterizerState or are you setting it manually?
[/quote]
Actually, I tried both.
In board constructor, I created a custom RasterizerState. I tried to set it using the properties in GraphicsDevice (so, reusing the SpriteBatch object I created in the main Draw method), but it is ignored.
Then I tried to create a new SpriteBatch object in order to pass the RasterizerState to the Begin overload, but it is ignored as well.
The code you posted is similar to the one I used, probably the only difference is that the Begin method I call is of a new SpriteBatch (first, I do need to draw an unclipped fullscreen background, then the clipped board).

[quote name='Starnick' timestamp='1318780091' post='4873134']
Aye, Spritebatch has its own default render states it sets if you do not pass in a custom one. Another thing to remember is that sprite batch will -not- reset states after End() is called.
...
As for your approaches...what do you mean by a "nested" sprite batch? It is not advised to have two sprite batches calling Begin() after each other, each drawing, then each calling End() because one of them is going to be interfering with the other in what states are set, etc.
[/quote]
That's exactly what I read in MSDN, that's why I made a "backup" of the RasterizerState before setting it.
I also read that I should not use more than one SpriteBatch object, but how can I pass my rasterizer to the Begin() method if I have not called End() yet?
Are you suggesting that I should End() the same SpriteBatch and then Begin() passing my rasterizer?

I didn't think of that, I will give it a try.
Thanks again!

Share this post


Link to post
Share on other sites
[quote name='harlock1975' timestamp='1318798229' post='4873212']Actually, I tried both.
In board constructor, I created a custom RasterizerState. I tried to set it using the properties in GraphicsDevice (so, reusing the SpriteBatch object I created in the main Draw method), but it is ignored.
Then I tried to create a new SpriteBatch object in order to pass the RasterizerState to the Begin overload, but it is ignored as well.
The code you posted is similar to the one I used, probably the only difference is that the Begin method I call is of a new SpriteBatch (first, I do need to draw an unclipped fullscreen background, then the clipped board).[/quote]

Well, I can guarantee that the code I posted is working - it's copied straight out of my GUI library which clips fine on WP7, Xbox360 and Win.

If you want to mix clipped stuff with unclipped stuff, just .End() your SpriteBatch, then .Begin() it again without the RasterizerState -- and vice versa if you want to turn clipping back on. That will guarantee all vertices in the SpriteBatch have been flushed. Using two SpriteBatches at the same time is asking for trouble - in terms of drawing order and applied render states.

Also make sure you go through the .End() .. .Begin() ritual when you modify the clipping region. The SpriteBatch will collect vertices until it either decides that it has enough to send to the GPU or you force it by calling .End(). If you leave it up to the SpriteBatch, everything will be clipped by whatever scissor rectangle you have set when the SpriteBatch decides to flush its buffers.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this