[solved] How to achieve this type of camera

I didn’t test the code before posting it, but I’m pretty sure it’s right. I successfully used that method in the past. If you have some code to share, I’d be happy to take a look.

Sure, I will post the code when I get home. I would say this is likely the problem with how I set up my camera and matrices, rather than with your code. I’m saying this partly because I’ve tried implementing other stuff today (including a billboard matrix with Matrix.CreateConstrainedBillboard) and something is not clicking right.

Ok, so this is the code I used to get the on screen position of the Rectangle for the sprite:

            Vector4 worldPos4 = new Vector4(position, 1);
            Vector4 screenPos4 = Vector4.Transform(worldPos4, camera.ViewProjection);
            Vector2 screenPos = new Vector2(screenPos4.X, screenPos4.Y) / screenPos4.W;

            Rectangle rectangle = new Rectangle((int)screenPos.X, (int)screenPos.Y, texture.Width, texture.Height);
            spriteBatch.Draw(texture, rectangle, Color.White);

And these are my matrices:

        public Matrix Projection
        {
            get
            {
                return Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), aspectRatio, nearClipPlane, farClipPlane);
            }
        }
        
        public Matrix View
        {
            get
            {
                return Matrix.CreateLookAt(position, cameraLookAt, Vector3.Up);
            }
        }

        public Matrix ViewProjection
        {
            get
            {
                return View * Projection;
            }
        }
        protected virtual Matrix World()
        {
            Matrix Scale = Matrix.CreateScale(1f);
            Matrix Rotation = Matrix.CreateFromYawPitchRoll(rotation.Y, rotation.Z, rotation.X);
            Matrix Translation = Matrix.CreateTranslation(position);

            Matrix result = Scale * Rotation * Translation;

            return result;
        }

This is more or less the result I’m expecting (sprite drawn at the center of the screen):

And this is what I’m getting (ignore the scaling of the sprite, this is a separate issue):

I’m not sure what I’m doing wrong, since I’m a noob still, but it’s gotta be something, so if you have an idea I’d appreciate any help.

I believe what you are looking for here is:

Orthogonal Projection
https://www.bing.com/images/search?q=orthogonal+projection&FORM=HDRSC2

Are you using World anywhere? Usually you multiply position * World * View * Projection to get screen position, but you’re skipping the multiplication of World. Although that’s for when you start with a position in object space. Since you’re just putting your sprite at a single point, it’s possible position is already in world space, but then I’m not sure why you have the method World() at all.

EDIT: I think you need the final transformation from screen position (-1 to +1) to pixel coordinates (0 to +1):
0.5f * (new Vector2(screenPos.x, -screenPos.y) + 1)

1 Like

This is the moment when you should use graphics.GraphicsDevice.Viewport.Project() :wink: to project the sprite’s position from 3D to the screen in screen coordinates
Or do it yourself as WVP matrix as @jnoyola suggested.

1 Like

Ok, got it.

I had to add the transformation to pixel coordinates as @jnoyola and @markus mentioned, and multiply the coordinates by Viewport.Width and Viewport.Height to get the correct position:

            Vector2 pixelPos = (new Vector2(screenPos.X, -screenPos.Y) + Vector2.One) / 2 * (graphics.GraphicsDevice.Viewport.Width/graphics.GraphicsDevice.Viewport.Height);

            Point rectPosition = new Point((int)(pixelPos.X * graphics.GraphicsDevice.Viewport.Width) - texture.Width / 2, (int)(pixelPos.Y * graphics.GraphicsDevice.Viewport.Height) - texture.Height);

Here is the final result (added one more sprite to check if they will all be positioned correctly):

Now I have to fix the scaling issue and sort the sprites correctly by depth, but I should be able to do that myself. Thanks for your help everyone, this is exaclty what I wanted!

6 Likes

Great you got it working. There’s still a small problem with the code though. The division of viewport width by viewport height doesn’t make sense here, you should use Vector2(viewportWidth, viewportHeight) instead. Then you don’t need the multiplications later.

Vector2 pixelPos = (new Vector2(screenPos.X, -screenPos.Y) + Vector2.One) / 2 * new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);
Point rectPosition = new Point((int)(pixelPos.X) - texture.Width / 2, (int)(pixelPos.Y) - texture.Height);

It’s probably working fine right now because this is an integer division, which means that the result will also be truncated to integer. With your current viewport resolution that just happens to be exactly 1. As soon as you use a wider viewport this division may result in a 2, which will cause problems.

1 Like

Sure, thanks. As you said fixing this did not really change anything visibly, but I’m hoping it will help me avoid issues later. Thanks again!