Projection and matrix reference notes monogame specific.

Im going to put this here as notes both for reference till i forget the next time and as a little bit of information for anyone trying to work specifically with monogames matrix’s.

Ok so simple statements first.

If we have a camera in world space at location 0, 0, 0 and we wish to look in the positive or negative view direction we can use Matrix CreateLookAt ( position , direction , up ) to create a view matrix that works with a projection matrix defined by one of the monogame Create Projection matrix types.

The notion of forward back in the above manner is related to the world space or were things are in your world (my_world_object.position - camera.position) if the result value is negative then it is a forward type of direction if this value is positive then it is a backwards type of direction.

Some common problems one might have when working with quads or triangles is lineing up the projection matrix to work like spritebatch does, so you can keep things in line.

For example above all we want CreateLookAt(…) to take the same parameters in relation to the actual screen we are looking at … aka we want Vector3 Up to be to the top of our monitor and Vector3 Forward to relate to the notion of us looking into the monitor.

However our world space might not play along with our new notion of what is forward and what is backwards.
Lets say our vision of our world space is one in that, our notion of forward being our camera looking into a positive world direction, or a negative one could be chosen by us.
Were CreateLookAt() maintains the notion of forward and up the same, no matter if choose the forward to be a positive z direction, instead of the standard negative one.
Simply put for that we need to make a change to the far plane of our Projection matrix to negate it.

For a example of the problem lets say…

We have a camera at position 0,0,0 it can look forward or backwards the difference is a -1 or +1 z in, CreateLookAt( position, new Vector3( 0,0 , + or - 1), up);

We make a cube and position it at say 0,0, +5 in the world or -5 in the world.

if we were to try to use Vector3 Forward to look at a cube at 0,0, +5 we wouldn’t be looking towards it because by default forward will look into the negative direction.

A more monogame concrete problem.

SpriteBatch.Draw as you are familiar with has a of layer depth parameter were the higher the z depth value is the further it is into the screen i.e. the notion of it being further FORWARD.
The layer depth is a positive Z value. Just like the +5 cube we just described which is the opposite of what your CreateProjection Matrixs operate on the notion of by default.

So…

We don’t want to pass Vector3.Backwards as the Forward direction into the CreateLookAt method as if that is the way we are thinking of looking into the screen.

With this point made lets talk about lining up a custom effects matrix with basic effect or spritebatch.Draw in tandem with CreateOrthographicOffCenter( left, right, bottom, top, near , far);

projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 10);

Typically the above is how you set up a orthographic matrix in monogame the top left of the screen is 0,0 and the z direction forward is negative in world space which is standard for 3d to think of negative as the depth into the screen this is also true for perspective projection as a typical choosen way to teach or think of it to help keep things less confusing. It would be used in combination with the view and world.

If you want to create a custom effect standard you typically just do this with Z looking into the negative direction so the far plane is a positive value like so.

Example 1).

zPolygonsOffsetIntoTheWorld = -1;

world = Matrix.Identity;

// the below is equivalent to view = Matrix.Identity;
view = Matrix.CreateLookAt(new Vector3(0, 0, 0), Vector3.Forward, Vector3.Up);

projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 10);

If you want to match spriteBatch.Draw which looks in the positive direction and maintain the CreateLookAt functionality in a way that makes sense. Then you must negate far plane.

Example 2).

zPolygonsOffsetIntoTheWorld = 1;

world = Matrix.Identity;

// the below is equivillent to view = Matrix.Identity;
view = Matrix.CreateLookAt(new Vector3(0, 0, 0), Vector3.Forward, Vector3.Up);

projection =  Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, -10) ;

Thus a change to projection matrix far plane means the view matrix keeps it’s sense of forward directionality as constant with the notion of forward as that of depth into the screen.

1 Like

For completeness here is the code for creating a triangle you can test the above with.

were layerDepth is equivalent to zPolygonsOffsetIntoTheWorld in the above example.



    public static void IndexedTriangle(GraphicsDevice graphicsDevice, Rectangle r, float layerDepth, out VertexPositionTexture[] vertices, out int[] indices)
    {
        vertices = new VertexPositionTexture[4];
        vertices[0] = new VertexPositionTexture() { Position = new Vector3(r.Left, r.Top, layerDepth), TextureCoordinate = new Vector2(0f, 0f) };
        vertices[1] = new VertexPositionTexture() { Position = new Vector3(r.Left, r.Bottom, layerDepth), TextureCoordinate = new Vector2(0f, 1f) };
        vertices[2] = new VertexPositionTexture() { Position = new Vector3(r.Right, r.Bottom, layerDepth), TextureCoordinate = new Vector2(1f, 1f) };
        vertices[3] = new VertexPositionTexture() { Position = new Vector3(r.Right, r.Top, layerDepth), TextureCoordinate = new Vector2(1f, 0f) };

        indices = new int[6];
        if (graphicsDevice.RasterizerState == RasterizerState.CullClockwise)
        {
            indices[0] = 0; indices[1] = 1; indices[2] = 2;
            indices[3] = 2; indices[4] = 3; indices[5] = 0;
        }
        else
        {
            indices[0] = 0; indices[1] = 2; indices[2] = 1;
            indices[3] = 2; indices[4] = 0; indices[5] = 3;
        }
    }

Since i didn’t mention how the above may relate to vertices world positions take note of the if else in the above function from which a logical deduction can be made.