Search code examples
c#xna

Determining Yaw and Pitch between two Vector3 point


I've read all kinds of various methods to determine the angle between two vectors and I'm really confused so I need some help to understand what I need to do.

Below is my First-person camera code

 public class FPSCamera : Engine3DObject
{
    public Matrix View { get; private set; }
    public Matrix Projeciton { get; private set; }

    private Quaternion rotation;
    private float yaw;
    private float pitch;
    private bool isViewDirty;
    private bool isRotationDirty;

    public BoundingFrustum Frustum { get; private set; }

    public bool Changed { get; private set; }

    public Vector3 ForwardVector
    {
        get
        {
            return this.View.Forward;
        }
    }

    public FPSCamera()
        : base()
    {
        this.Position = Vector3.Zero;
        this.rotation = Quaternion.Identity;
        this.yaw = this.pitch = 0;
        this.isViewDirty = true;
        this.isRotationDirty = false;


    }

    public void SetPosition(Vector3 position)
    {
        this.Position = position;
        this.isViewDirty = true;
        this.Update(null);
    }

    public void Initialize(float aspectRatio)
    {
        this.Projeciton = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, 1f, 1000f);
    }

    public void Update(GameTime gameTime)
    {
        this.Changed = false;

        if (isRotationDirty)
        {
            if (yaw > MathHelper.TwoPi)
            {
                yaw = yaw - MathHelper.TwoPi;
            }

            if (yaw < -MathHelper.TwoPi)
            {
                yaw = yaw + MathHelper.TwoPi;
            }

            if (pitch > MathHelper.TwoPi)
            {
                pitch = pitch - MathHelper.TwoPi;
            }

            if (pitch < -MathHelper.TwoPi)
            {
                pitch = pitch + MathHelper.TwoPi;
            }

            this.rotation = Quaternion.CreateFromYawPitchRoll(yaw, pitch, 0);
            this.isRotationDirty = false;
            this.isViewDirty = true;
            this.Changed = true;
        }

        if (isViewDirty)
        {
            Vector3 up = Vector3.Transform(Vector3.Up, rotation);
            Vector3 target = Vector3.Transform(Vector3.Forward, rotation) + Position;
            this.View = Matrix.CreateLookAt(this.Position, target, up);
            this.isViewDirty = false;

            if (this.Frustum == null)
            {
                this.Frustum = new BoundingFrustum(this.View * this.Projeciton);
            }
            else
            {
                this.Frustum.Matrix = (this.View * this.Projeciton);
            }

            this.Changed = true;
        }
    }

    public void Move(Vector3 distance)
    {
        this.Position += Vector3.Transform(distance, rotation);
        this.isViewDirty = true;
    }

    public void Rotate(float yaw, float pitch)
    {
        this.yaw += yaw;
        this.pitch += pitch;
        this.isRotationDirty = true;
    }

    public void LookAt(Vector3 lookAt)
    {

    }
}

The "lookat" method is blank because I'm trying to figure out how to do it. I move the camera so it's position is (500,500,500) and need it to look at (0,0,0) but I can't figure out how to get the yaw and pitch between them so I can set the rotation correctly. I've read about normalizing the vectors and using the cross and dot product, but you can't normalize (0,0,0) as it has no direction so I'm a bit lost as to what to do. Any help would be appreciated.


Solution

  • It seems like you want to be able to manipulate your camera in 2 different ways:

    1.) Add or subtract a little yaw or pitch and have the camera respond accordingly.
    2.) Have the camera look at a known position and then back calculate the pitch and yaw angles so you can do #1 on subsequent frames if desired.

    I think what is making it difficult for you is that you want to store the overall pitch and yaw angles for later use. You might hear hear some experienced 3d programmes say that if you think you need to store angles, you're probably doing something wrong (last paragraph in this blog). Anyways, if you can let go of those angles, you camera class will be much simpler. Here is an example. These 2 public methods allow you to maipulate the camera by either 1.) adding pitch, yaw, or translation or 2.) by setting it to look at a specific point in the world. It also allows you to use either method at any time. By not having the concern of the absolute pitch and yaw angles, the code is much simpler.

    namespace WindowsGame1
    {
        class FPSCamera
        {
            public Matrix View;
            public Matrix Proj;
            public Vector3 Position, Target;
    
    
            public FPSCamera(float aspect)
            {
    
                Proj = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect, 1f, 1000f);
                Target = Vector3.Forward;
                SetViewMatrix();
            }
    
            public void UpdateCameraByPitchYawTranslation(float amountToPitchThisFrame, float amountToYawThisFrame, Vector3 amountToTranslateThisFrame)
            {
                Position += amountToTranslateThisFrame;
                Target += amountToTranslateThisFrame;
    
                Matrix camera = Matrix.Invert(View);
                Target = Vector3.Transform(Target - Position, Matrix.CreateFromAxisAngle(camera.Right, amountToPitchThisFrame)) + Position;
                Target = Vector3.Transform(Target - Position, Matrix.CreateFromAxisAngle(Vector3.Up, amountToYawThisFrame)) + Position;
    
                SetViewMatrix();
            }
    
            public void SetCameraToLookAtSpecificSpot(Vector3 spotToLookAt)
            {
                Target = spotToLookAt;
                SetViewMatrix();
            }
    
            private void SetViewMatrix()
            {
                View = Matrix.CreateLookAt(Position, Target, Vector3.Up);
            }
    
        }
    }
    

    You could also make a public method to set the camera position to a specific location if you wanted.