Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

Problem with camera

Started by Eldritch 3 replies 500+ views
Original Post
Eldritch
Eldritch
I have implemented a camera class into my engine, but it turns out that the code I have written is very buggy. My movement and turning-speed seem to accelerate with every new step.. like.. in the beginning, it is as slow as it should be, but after a few frames of moving/rotating, I have lightning movement and rotation all of the sudden (values seem to accumulate). I need help with the code. I have probably done something wrong.

/*!
    @file       Camera.cs
    @brief      Defines camera view.
    @version    1.0
*/

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using EdenEngine.Core;

namespace EdenEngine.Graphics
{
    /// <summary>
    /// Interface for the game view.
    /// </summary>
    public sealed class Camera
    {
        /// <summary>
        /// Camera position.
        /// </summary>
        private Vector3 m_vec3Position;

        /// <summary>
        /// Horizontal rotation.
        /// </summary>
        private float m_fHorizontalRotation = MathHelper.PiOver2;

        /// <summary>
        /// Vertical rotation.
        /// </summary>
        private float m_fVerticalRotation = -MathHelper.PiOver2 / 10.0f;

        /// <summary>
        /// Rotation speed.
        /// </summary>
        private const float m_fRotationSpeed = 0.0008f;

        /// <summary>
        /// Movement speed.
        /// </summary>
        private const float m_fMovementSpeed = 0.03f;

        /// <summary>
        /// View matrix.
        /// </summary>
        private Matrix m_matView;

        /// <summary>
        /// Projection matrix.
        /// </summary>
        private Matrix m_matProjection;

        /// <summary>
        /// Reflection matrix.
        /// </summary>
        private Matrix m_matReflection;

        /// <summary>
        /// Camera instance.
        /// </summary>
        private static Camera s_instance = new Camera();

        /// <summary>
        /// Gets Camera instance.
        /// </summary>
        public static Camera Instance
        {
            get { return s_instance; }
        }

        /// <summary>
        /// Gets view matrix.
        /// </summary>
        public Matrix View
        {
            get { return m_matView; }
        }

        /// <summary>
        /// Gets projection matrix.
        /// </summary>
        public Matrix Projection
        {
            get { return m_matProjection; }
        }

        /// <summary>
        /// Gets reflection matrix.
        /// </summary>
        public Matrix Reflection
        {
            get { return m_matReflection; }
        }

        /// <summary>
        /// Gets camera position.
        /// </summary>
        public Vector3 Position
        {
            get { return m_vec3Position; }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        private Camera
            (
            )
        {
        }

        /// <summary>
        /// Initializes camera.
        /// </summary>
        /// <param name="fFOV">Desired field of view angle.</param>
        public void Initialize
            (
            ViewerProperties properties
            )
        {
            // Set camera position.
            m_vec3Position = properties.StartPosition;

            // Create view matrix.
            UpdateView();

            // Create projection matrix.
            m_matProjection = Matrix.CreatePerspectiveFieldOfView
                (
                properties.FieldOfViewAngle,
                Renderer.Instance.Device.Viewport.AspectRatio,
                0.3f,
                properties.ViewDistance
                );
        }

        /// <summary>
        /// Updates view and creates view matrix.
        /// </summary>
        private void UpdateView
            (
            )
        {
            // Create camera rotation matrix.
            Matrix cam_rot =
                Matrix.CreateRotationX(m_fVerticalRotation) * Matrix.CreateRotationY(m_fHorizontalRotation);

            // Declare original target and up vectors.
            Vector3 cam_orig_target = new Vector3(0, 0, -1);
            Vector3 cam_orig_up = new Vector3(0, 1, 0);

            // Calculate rotated and final target vectors.
            Vector3 cam_rot_target = Vector3.Transform(cam_orig_target, cam_rot);
            Vector3 cam_fin_target = m_vec3Position + cam_rot_target;

            // Calculate rotated up vector.
            Vector3 cam_rot_up = Vector3.Transform(cam_orig_up, cam_rot);

            // Create view matrix.
            m_matView = Matrix.CreateLookAt(m_vec3Position, cam_fin_target, cam_rot_up);

            // Calculate reflection matrix.
            //
            Vector3 refl_campos = m_vec3Position;
            refl_campos.Y = -m_vec3Position.Y + Environment.Instance.WaterHeight * 2;
            
            Vector3 refl_targetpos = cam_fin_target;
            refl_targetpos.Y = -cam_fin_target.Y + Environment.Instance.WaterHeight * 2;

            Vector3 cam_right = Vector3.Transform(new Vector3(1, 0, 0), cam_rot);
            Vector3 inv_up = Vector3.Cross(cam_right, refl_targetpos - refl_campos);
            m_matReflection = Matrix.CreateLookAt(refl_campos, refl_targetpos, inv_up);
            //
        }

        public void Update
            (
            float fDeltaTime
            )
        {
            // Check for rotation.
            if (InputManager.Instance.MouseHasMoved() == true)
            {
                // Rotate camera.
                Rotate(fDeltaTime);
            }

            // Check for movement.
            Vector3 move_vec = new Vector3(0, 0, 0);
            if (InputManager.Instance.KeyIsPressed(Keys.W))
            {
                move_vec += new Vector3(0, 0, -1);
            }
            if (InputManager.Instance.KeyIsPressed(Keys.S))
            {
                move_vec += new Vector3(0, 0, 1);
            }
            if (InputManager.Instance.KeyIsPressed(Keys.D))
            {
                move_vec += new Vector3(1, 0, 0);
            }
            if (InputManager.Instance.KeyIsPressed(Keys.A))
            {
                move_vec += new Vector3(-1, 0, 0);
            }

            Move(move_vec * fDeltaTime);
        }

        /// <summary>
        /// Moves camera view.
        /// </summary>
        /// <param name="vec3Dir">Direction to move in.</param>
        private void Move
            (
            Vector3 vec3Dir
            )
        {
            Matrix cam_rot =
                Matrix.CreateRotationX(m_fVerticalRotation) * Matrix.CreateRotationY(m_fHorizontalRotation);

            Vector3 rot_vec = Vector3.Transform(vec3Dir, cam_rot);
            m_vec3Position += m_fMovementSpeed * rot_vec;

            UpdateView();
        }

        /// <summary>
        /// Rotates camera view.
        /// </summary>
        /// <param name="fDeltaTime">Time passed since last frame.</param>
        private void Rotate
            (
            float fDeltaTime
            )
        {
            // Calculate rotation.
            m_fHorizontalRotation -= m_fRotationSpeed * InputManager.Instance.GetMouseDelta().X * fDeltaTime;
            m_fVerticalRotation -= m_fRotationSpeed * InputManager.Instance.GetMouseDelta().Y * fDeltaTime;

            // Re-center mouse.
            InputManager.Instance.CenterMouse();

            // Update view.
            UpdateView();
        }
    }
}

Gage64
Gage64
Try this:

if (InputManager.Instance.KeyIsPressed(Keys.W)){    move_vec = new Vector3(0, 0, -1);}// Same for the other keys...


The reason for this is basically that both your position and velocity change constantly, but only one of them should change like that (probably the position). This isn't the best way to explain this, but hopefully you understand what I mean.

I don't think you should make a similar change for the rotation angles, but try that too if it still doesn't work.
Eldritch
Eldritch
The problem that would arise then would be that the camera can only go in one direction at a time. It would be impossible to move "diagonally".
Gage64
Gage64
You're right. In that case, try this:

if (InputManager.Instance.KeyIsPressed(Keys.W)){    move_vec = // Calculate velocity here    m_vec3Position += move_vec;}// Same for the other keys...


And get rid of the Move() function. Or you can set a bool inside each if statement and have Move() actually move only when that bool is true.

The point is, you should not accumulate the velocity. It should be recalculated each frame and added to the position.

On a completely unrelated note, you should read this.
Eldritch
Eldritch
That code would not work either since I need to rotate the movement vector by the direction I am facing (which I do in the Move() function). The behaviour of the camera code feels like it is accumulating speed, even though there is nothing in the code that indicates that to be the case. Just though that someone could spot something that was not right in the math.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.