Sign in to follow this  

Efficiency for camera:

This topic is 3661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm not sure whether this is the right forum, but this involved a bit of DirectX and well as math theory so I'm posting it here. I'm trying to add a few different modes for my camera and I'm not sure if I'm doing it the best way. I've made an arcball class that is used to rotate the camera, but also the object in another part of my code. As it contained quaternions, I made my camera do the same and only convert to a matrix in the update function, but since then I've found a a few reasons that I'd have to convert it to a matrix and back outside of the update function. I want to be able to set the target, the camera position and set the rotation using the accessors for those and make use of the arcball (uses quaternions), but I want to have it so that when you set the target, it also sets the rotation needed to point the camera at the target. I'd like to have some features so that when switching between modes, it will try to comply with what's needed for the new mode, whilst making as little change to the current orientation as possible. I'm not asking for help with all of that, but I do need a bit of help deciding stuff like whether to store the overall orientation as a matrix, a quaternion or as position, target and up vectors and whether it's best to recalculate everything each time the camera receives input or to leave most of that to the update function. Here's the camera class I have at the moment. I'm not really struggling with the math behind it, but I'm posting it to give an idea of the decisions I've made so far.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace ModelEx3
{
    class ModelExCamera
    {
        public enum CameraMode
        {
            Manual = 0,
            Fly = 1,
            Orbit = 2
        };

        Device                  m_xDevice;
        Control                 m_xRenderWindow;
        Vector3                 m_xPosition;
        Vector3                 m_xTarget;
        Quaternion              m_xRotation;
        ModelExArcBall          m_xArcBall;
        CameraMode              m_eMode;

        float                   m_fTargetDistance;
        float                   m_fFieldOfView;
        float                   m_fAspectRatio;
        float                   m_fNearClipPlane;
        float                   m_fFarClipPlane;

        public Vector3          Position
        {
            get { return m_xPosition; }
            set { m_xPosition = value; }
        }
        public Vector3          Target
        {
            get { return m_xTarget; }
            set { m_xTarget = value; }
        }
        public Quaternion       Rotation
        {
            get { return m_xRotation; }
        }
        public ModelExArcBall   ArcBall
        {
            get { return m_xArcBall; }
        }
        public CameraMode       Mode
        {
            get
            {
                return m_eMode;
            }
            set
            {
                if (value == CameraMode.Fly &&
                    m_eMode != CameraMode.Fly)
                {
                    RemoveRoll();
                }
                if (value == CameraMode.Orbit &&
                    m_eMode != CameraMode.Orbit)
                {
                    m_xRotation = Quaternion.Identity;
                }
                            
                m_eMode = value;
            }
        }

        public ModelExCamera(ref Device xDevice, Vector3 xTarget, float fTargetDistance)
        {
            m_xDevice               = xDevice;
            m_eMode                 = CameraMode.Orbit;
            m_xTarget               = xTarget;
            m_fTargetDistance       = fTargetDistance;
            m_xRotation             = Quaternion.Identity;

            Matrix xRotation        = Matrix.RotationQuaternion(m_xRotation);
            Vector3 xTargetVector   = new Vector3(0.0f, 0.0f, m_fTargetDistance);
            xTargetVector.TransformCoordinate(xRotation);
            m_xPosition             = m_xTarget - xTargetVector;

            m_xRenderWindow         = xDevice.PresentationParameters.DeviceWindow;
            m_fFieldOfView          = (float)Math.PI / 4.0f;
            m_fAspectRatio          = (float)m_xRenderWindow.Width / (float)m_xRenderWindow.Height;
            m_fNearClipPlane        = 0.1f;
            m_fFarClipPlane         = 1000.0f;

            m_xArcBall = new ModelExArcBall(ref m_xRenderWindow, true);
            m_xArcBall.Update(ref m_xRotation, false);
        }

        public void Zoom(float fZoom)
        {
            m_fTargetDistance -= fZoom;
            m_fTargetDistance = Math.Max(m_fNearClipPlane, m_fTargetDistance);
        }

        public void MoveForward(float fDistance)
        {
            Vector3 xForwardVector = m_xTarget - m_xPosition;
            xForwardVector.Normalize();
            xForwardVector *= fDistance;
            m_xPosition += xForwardVector;
            m_xTarget += xForwardVector;
        }

        public void RotateX(float fAngle)
        {
            Vector3 xBaseUp = new Vector3(0, 1, 0);
            Quaternion xRotationAxis = Quaternion.RotationAxis(xBaseUp, fAngle);
            if (m_eMode == CameraMode.Orbit)
            {
                xRotationAxis.Invert();
                m_xRotation = xRotationAxis * m_xRotation;
            }
            else if (m_eMode == CameraMode.Fly)
            {
                m_xRotation *= Quaternion.RotationYawPitchRoll(fAngle, 0.0f, 0.0f);
            }

            m_xRotation.Normalize();
        }

        public void RotateY(float fAngle)
        {
            Vector3 xBaseRight = new Vector3(1, 0, 0);
            Quaternion xRotationAxis = Quaternion.RotationAxis(xBaseRight, fAngle);
            if (m_eMode == CameraMode.Orbit)
            {
                xRotationAxis.Invert();
            }
            m_xRotation = xRotationAxis * m_xRotation;
            m_xRotation.Normalize();
        }

        public void RotateZ(float fAngle)
        {
            Vector3 xBaseForward = new Vector3(0, 0, 1);
            Quaternion xRotationAxis = Quaternion.RotationAxis(xBaseForward, fAngle);
            if (m_eMode == CameraMode.Orbit)
            {
                xRotationAxis.Invert();
            }
            m_xRotation = xRotationAxis * m_xRotation;
            m_xRotation.Normalize();
        }

        public void RemoveRoll()
        {
            Vector3 xBaseUp = new Vector3(0.0f, 1.0f, 0.0f);
            Matrix xRotation = Matrix.LookAtLH(
                m_xPosition,
                m_xTarget,
                xBaseUp
            );
            m_xRotation = Quaternion.RotationMatrix(xRotation);
            m_xRotation.Invert();
        }

        public void Update()
        {
            m_xDevice.Transform.Projection = Matrix.PerspectiveFovLH(
                m_fFieldOfView,
                (float)m_xRenderWindow.Width / (float)m_xRenderWindow.Height,
                m_fNearClipPlane,
                m_fFarClipPlane
            );

            m_xArcBall.Update(ref m_xRotation, m_eMode == CameraMode.Orbit);

            Matrix xRotation = Matrix.RotationQuaternion(m_xRotation);
            Vector3 xUpDirection = new Vector3(0.0f, 1.0f, 0.0f);

            if (Mode == CameraMode.Fly)
            {
                Vector3 xTargetVector = new Vector3(0.0f, 0.0f, m_fTargetDistance);
                xTargetVector.TransformCoordinate(xRotation);
                m_xTarget = m_xPosition + xTargetVector;

                xUpDirection.TransformCoordinate(xRotation);
            }
            else if (Mode == CameraMode.Orbit)
            {
                Vector3 xTargetVector = new Vector3(0.0f, 0.0f, m_fTargetDistance);
                xTargetVector.TransformCoordinate(xRotation);
                m_xPosition = m_xTarget - xTargetVector;

                xUpDirection.TransformCoordinate(xRotation);
            }

            m_xDevice.Transform.View = Matrix.LookAtLH(
                m_xPosition,
                m_xTarget,
                xUpDirection
            );
        }
    }
}

Share this post


Link to post
Share on other sites
Personly i would go with vectors (look,position,up,right). That way you can build the matrix when you need it (simple enough) and the same with quaternions.

This way the simpler operations can use the vectors. Have a bool to say if the last matrix/quaternion you built is up to date and if not rebuild for more advances operations.

Basicaly always have a matrix/quaternion in your class but only update/use when needed - i would use the vectors for ground work (the input stuff).

Having said that my camerra is not as advanced as yours looking at the code. It only has move/roll/pitch/yaw functions so that is easy enough to do with vectors and then throw out the view matrix when its needed every frame. If you can get away with sticking to the vectors then i would but im not sure if you can - especially with abilities like orbiting objects.

In the end if it works stick with it. No point recoding it to use another data type unless you are activly optimising and you dont have other things to do.

Regards

Share this post


Link to post
Share on other sites
If I store the overall rotation as vectors and I wanted to set the rotation using the accessor (the arc ball requires something like this as well), I'd have to recalculate the vectors every time the rotation changed and convert them back to a matrix again whenever I needed to retreive the rotation.
However if I store the rotation as a quaternion or a matrix, I'd have to recalculate the quat or matrix every time I changed any of the vectors or any time I needed to retreive the vectors.
It looks like I'll need to update the rotation when I change the vectors and update the vectors every time I change the rotation if I want to support both ways of moving my camera. I suppose it's more efficient to only update things when I need to instead of every frame anyway.

Share this post


Link to post
Share on other sites
In my camera system, I just use three vectors. When the camera is moved, I set a dirty flag, that I then check at the satrt of my render loop. If the dirty flag is set, then I re-create the matrix from the three vectors, and clear the dirty flag.
That way the matrix is only calculated at most once per frame, which is particularly cheap to do.
I'm not really suer how you'd do this with quaternions, I'd suggest sticking to either quaternions or vectors and not mixing them.

Share this post


Link to post
Share on other sites
Ok, I think I've figured out how to explain my problem. I have functions for setting the position, target and the rotation itself. If I set the position, the rotation would be out of date and in the fly cam mode, so would the target (because it's a fixed distance). If I set the target, then the rotation and the position would be out of date for the same reasons. If I set the rotation directly as a quaternion or a matrix, the target and the position would be out of date.
I'm anticipating the need to change the rotation more than once per frame (for example when chasing a moving object and receiving input from the mouse/keyboard). I don't think I'll be able to get my updating to as few times as once per frame, but it looks like you guys are saying I can leave the updating until the "get" functions and any other function that needs to make use of the out of date values is called before doing the update.

Share this post


Link to post
Share on other sites

This topic is 3661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this