XNA ViewPort and SpriteBatch Projection

I am working on an XNA game and I am using ViewPort.Project and ViewPort.Unproject to translate to and from world coordinates. I am currently using them for every object that I draw using SpriteBatch. What I would like to do is compute a matrix that I can send to SpriteBatch.Begin to transform screen-space for me.

Here are the functions I'm currently using to translate to and from the screen:

Vector2 ToWorldCoordinates(Vector2 pixels) { Vector3 worldPosition = graphics.GraphicsDevice.Viewport.Unproject(new Vector3(pixels, 0), Projection, View, Matrix.Identity); return new Vector2(worldPosition.X, worldPosition.Y); } Vector2 ToScreenCoordinates(Vector2 worldCoords) { var screenPositon = graphics.GraphicsDevice.Viewport.Project(new Vector3(worldCoords, 0), Projection, View, Matrix.Identity); return new Vector2(screenPositon.X, screenPositon.Y); } 

The view is set to Matrix.Identity and Projection:

 Projection = Matrix.CreateOrthographic(40 * graphics.GraphicsDevice.Viewport.AspectRatio, 40, 0, 1); 

And this is how I draw things now:

  spriteBatch.Begin(); foreach (var thing in thingsToDraw) { spriteBatch.Draw(thing.Texture, ToScreenCoordinates(thing.PositionInWorldCoordinates), thing.Color); spriteBatch.End(); } spriteBatch.End(); 

This is what I would like to do instead (using SpriteBatch.Begin () version) XNA 4.0

  // how do I calculate this matrix? Matrix myTransformationMatrix = GetMyTransformationMatrix(); spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, myTransformationMatrix); foreach (var thing in thingsToDraw) { // note: no longer converting each object position to screen coordinates spriteBatch.Draw(thing.Texture, thing.PositionInWorldCoordinates, thing.Color); spriteBatch.End(); } spriteBatch.End(); 
+4
source share
1 answer

I wrote about SpriteBatch and various "spaces" (world, projection, client, etc.) here , here and here . These answers are probably worth reading.

SpriteBatch assumes that your space in the world is the same as the space with the client, which, however, has many pixels in height and width, that is, beginning at the top left, Y + down.

It looks like (based on your use of CreateOrthographic ) you want your world space to be displayed as 40 units high on the screen, and no matter how many devices fit the width. You also want world origin to be in the center of the screen, and Y + up.

Therefore, you must adhere to a different matrix between them in order to convert your World space to Client space. I believe the correct matrix (in psudocode): scale(40/viewport.Height) * scale(1, -1) * translate(viewport.Width/2, viewport.Height/2) . Scale, flip, and translate to move from World to Client.

You should also remember that sprites assume that Y + is off. Thus, you must pass the scale (1, -1) to SpriteBatch.Draw , otherwise they will be inverted (and, due to discarding the back surface, will be invisible).

+12
source

All Articles