3D Camera (YAW, PITCH, ROLL, FOV)

Hello!
I created a 3D Camera System that allow (YAW, PITCH, ROLL, FOV).
I hope i can anyone help!

Create Camera:

// FOV = 80, Pos = new Vector3(0, 100, 200), LookDirection = Vector3.Forward.
this._camera = new Camera(this.GraphicsDevice, 80, new Vector3(0, 100, 200), Vector3.Forward);

Code:

public class Camera {
    
    private GraphicsDevice _graphicsDevice;

    public Matrix View { get; private set; }
    public Matrix Projection { get; private set; }
    private Matrix _world;

    private readonly float _nearPlaneDistance = 0.05f;
    private readonly float _farPlaneDistance = 1000f;
    
    private float _fov;

    public float Yaw { get; private set; }
    public float Pitch { get; private set; }
    public float Roll { get; private set; }

    public Camera(GraphicsDevice graphicsDevice, float fov, Vector3 pos, Vector3 lookDirection) {
        this._graphicsDevice = graphicsDevice;
        this.FieldOfViewDegrees = fov;
        this.Position = pos;
        this.Forward = lookDirection;
    }
    
    /**
     * Get / Set FOV
     */
    public float FieldOfViewDegrees {
        get => this._fov;

        set {
            this._fov = value;
            this.UpdatePerspective(this.FieldOfViewDegrees);
            this.SetWorldAndView(this.Forward);
        }
    }

    /**
     * Get / Set Position
     */
    public Vector3 Position {
        get => this._world.Translation;

        set {
            this._world.Translation = value;
            this.SetWorldAndView(this.Forward);
        }
    }

    /**
     * Get / Set Forward Vector
     */
    public Vector3 Forward {
        get => this._world.Forward;
        set => this.SetWorldAndView(value);
    }

    /**
     * Set World and View Matrix
     */
    private void SetWorldAndView(Vector3 forward) {
        this._world = Matrix.CreateWorld(this._world.Translation, forward, Vector3.Up);
        this.View = Matrix.CreateLookAt(this._world.Translation, this._world.Forward + this._world.Translation, this._world.Up);
    }
    
    /**
     * Update FOV
     */
    private void UpdatePerspective(float fovInDegrees) {
        float aspectRatio = this._graphicsDevice.Viewport.Width / (float) this._graphicsDevice.Viewport.Height;
        this.Projection = Matrix.CreatePerspectiveFieldOfView(fovInDegrees * (3.14159265358F / 180F), aspectRatio, this._nearPlaneDistance, this._farPlaneDistance);
    }

    /**
     * Tag a Pos on that the Camera should look
     */
    public void TargetPositionToLookAt(Vector3 targetPosition) {
        this.SetWorldAndView(Vector3.Normalize(targetPosition - this._world.Translation));
    }
    
    /**
     * To stop Rendering things that not watchable
     */
    public BoundingFrustum GetBoundingFrustum() {
        return new BoundingFrustum(this.View * this.Projection);
    }
    
    /**
     * Move Camera (Normally Tagged to the Player with Position)
     */
    public void Move(GameTime time, int speed = 30) {
        this.Position += (this._world.Forward * speed) * (float) time.ElapsedGameTime.TotalSeconds;
    }

    /**
     * Rotate Camera
     */
    public void Rotate(float yaw, float pitch, float roll) {
        this.Yaw = yaw % 360;
        this.Pitch = Math.Clamp(pitch, -90, 90);
        this.Roll = roll % 360;

        Matrix rotation = Matrix.CreateFromYawPitchRoll(MathHelper.ToRadians(this.Yaw), MathHelper.ToRadians(this.Pitch), 0);
        this.SetWorldAndView(rotation.Forward);
        
        this.View *= Matrix.CreateRotationZ(MathHelper.ToRadians(this.Roll));
    }
}

I fear your camera is limited in some situations, for example when going up vertically it may not produce the desired result, as the “up vector” is always static. (Which may be totally sufficient for different usages but may fail for loopings done in a plane)

A more stable approach would be to supply an axis system for the camera and rotate that axis system.

Like having class fields

Vector3 axis_x = Vector3.Left;
Vector3 axis_y = Vector3.Up;
Vector3 axis_z = Vector3.Forward;
Quaternion rotation = Matrix.Identity;

and everytime you rotate your camera around one of those axis, you actually transform all axis and the quaternion.

void Roll(float delta)
{
    Matrix mtx = Matrix.CreateFromAxisAngle(this.axis_z, delta); // generate from actual current forward vector
    this.axis_x = Vector3.TransformNormal(this.axis_x, mtx);
    this.axis_y = Vector3.TransformNormal(this.axis_y, mtx);
    this.rotation *= mtx;
}

Normally this done on an object like a local axis system and the camera is just tied to it. The Quaternion cares for the rotational aspect of the object (for world transform), while the axis care for maintaining a local axis system (as a rotational reference). So when you rotate around axis_z you always rotate around the objects current local z axis and not around the worlds static z

Once you have that object the easiest way to have a camera just follow said object is, to generate a cam position relative to it (using the objects axis, you can just put it at object.pos - object.axis_z*5) and in the CreateLookAt you suply the objects axis_y as up vector

(wrote this out of memory, consider it being pseudo code)

oh ok, thx i want to improve that!

But in generel it should just a Simple 3D Camera. :slight_smile: