1
votes

So I know there are a few questions/answers regarding building a 2D Camera for XNA however people seem to just be happy posting their code without explanation. I'm looking for more of an explanation of what I'm doing wrong.

First off, I understand the whole World -> View - > Projection - > Screen transformation.

My goal is to have a camera object that is centered in the center of the viewport and that when the camera's position moves up it correlates to moving up in the viewport and when it moves to the right it correlates moving right in the viewport.

I'm having difficulty implementing that functionality because the Y value of the viewport is inverted.

//In Camera Class
private void UpdateViewTransform()
{
//My thinking here was that I would create a projection matrix to center the camera and then flip the Y axis appropriately
     Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0)) * 
                   Matrix.CreateScale(new Vector3(1f, -1f, 1f));

//Here is the camera Matrix. I have to give the Inverse of this matrix to the Spritebatch I believe since I want to go from World Coordinates to Camera Coordinates
     _viewMatrix = Matrix.CreateRotationZ(_rotation) *
                  Matrix.CreateScale(new Vector3(_zoom, _zoom, 1.0f)) *
                  Matrix.CreateTranslation(_position.X, _position.Y, 0.0f);

     _viewMatrix = proj * _viewMatrix;

}

Can someone help me understand how I can build my view transformation to pass into the SpriteBatch so that I achieve what I'm looking for.

EDIT

This as a transformation seems to work however I am unsure why. Can someone perhaps break it down for me in understanding:

Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0));
    _viewMatrix = Matrix.CreateRotationZ(_rotation) *
                 Matrix.CreateScale(new Vector3(_zoom, _zoom, 1.0f)) *
                 Matrix.CreateTranslation(-1 * _position.X, _position.Y, 0.0f);

    _viewMatrix = proj * _viewMatrix;

I've built a raytracer before so I should understand your understanding, my confusion lies with the fact it's 2D and that SpriteBatch is hiding what it's doing from me. Thanks! Farid

3
Have you tried simply using 1f in your scale rather than -1f?ChrisF
Using 1f caused the x translation to be inverted though :(Setheron

3 Answers

2
votes

If you flip everything on the Y axis with your scale matrix, that means you are flipping the models that SpriteBatch is drawing (textured quads). This means you also have to change your winding-order (ie: backface culling is interpreting that you are drawing the backs of the triangles facing the camera, so it culls them, so you have to change the rule that it uses).

By default, SpriteBatch uses RasterizerState.CullCounterClockwise. When you call SpriteBatch.Begin you need to pass in RasterizerState.CullClockwise instead.

And, of course, Begin is where you pass in your transformation matrix.

I haven't carefully checked your matrix operations - although I have a suspicion that the order is incorrect. I recommend you create a very simple testing app and build up your transformations one at a time.

1
votes

I've fought with XNA a lot trying to get it to be like other engines I have worked with before... my reccomendation, it isn't worth it... Just go with the XNA standards and use the Matrix helper methods for creating your Perspective / Viewport matrices.

0
votes

So after just thinking logically, I was able to deduce the proper transformation. I'll outline the steps here incase anyone wants the real breakdown:

It is important to understand what is a Camera Transformation or View Transformation. A View Transformation is normally what is needed to go from Coordinates relative to your Camera to World-Space coordinates. The inverse of the View Transformation would then make a world coordinate relative to your Camera!

Creating a View Matrix

  1. Apply the camera's rotation. We are doing it in the Z axis only because this is for a 2D camera.
  2. Apply the transformation of the Camera. This make sense since we want the World coordinate which is the sum of the camera coordinate and the object relative to the camera.
    1. You might notice that I multiplied the Y Component by -1. This is so that increasing the Camera's Y Position correlates to moving up since the screen's Y value points downward.
  3. Apply the camera's zoom

Now the inverse of the matrix will do World Coordinate -> View Cordinates.

I also chose to center my camera in the center of the screen, so I included a pre-appended translation.

Matrix proj = Matrix.CreateTranslation(new Vector3(_viewport.Width * 0.5f, _viewport.Height * 0.5f, 0));

        _viewMatrix = Matrix.CreateRotationZ(moveComponent.Rotation) *
                    Matrix.CreateTranslation(moveComponent.Position.X, -1 * moveComponent.Position.Y, 0.0f) *
                     Matrix.CreateScale(new Vector3(zoomComponent.Zoom, zoomComponent.Zoom, 1.0f));

        _viewMatrix = proj * Matrix.Invert(_viewMatrix);