A Camera Class for

trexpeeverSoftware and s/w Development

Dec 13, 2013 (3 years and 6 months ago)

56 views

A Camera Class for
OpenGL

John McGuiness

October 2006

Necessity for a Camera Class


Existing available camera tool
-

gluLookAt()


Basic utility which encapsulates a series of rotate and translate
commands


Allows viewing along an arbitrary line of sight with an “Up”
vector defined


Need extra transformations to provide greater flexibility


Need to modify “Forward” and “Along” vectors as well as
“Up” to improve on gluLookAt()


Camera class may be built to encapsulate commands for
greater ease of use

“Up”, “Forward” and “Along”


The three camera view vectors are defined as shown:

Proposed Camera Features


The camera class should:


Provide motion along the view vectors as well as arbitrary axes
(in some cases)


Provide rotation about the view vectors as well as arbitrary axes
(in some cases)


Maintain the camera’s own orientation by keeping the viewing
vectors orthogonal to each other


Need to define motion for two possible types of camera:


Land camera


e.g. for road vehicles simulation


Air camera


e.g. for flight simulation

Camera Motion


Walking


This is motion along the
Forward

vector (or Z
-
axis):

Camera Motion


Strafing


This is side to side motion on the
Along

vector (or X
-
axis):

Camera Motion


Flying


This is vertical motion on the
Up

vector (or Y
-
axis):

Camera Rotation


Pitching


This is rotation about the
Along

vector


looking up and down

Camera Rotation


Yawing


This is rotation about the
Up

vector


looking left and right

Camera Rotation


Rolling


This is rotation about the
Forward

vector


twisting left and right

Camera Class Declaration


The camera class uses a type called Vector3D which
provides storage and common operations (e.g. dot
product, cross product etc.) for vectors



#include "Vector3D.h"



The enumerated type defined below is used to
distinguish between the two types of camera



enum CAM_TYPE { LAND_CAM, AIR_CAM };


Camera Class Declaration


First, we need private variables for each view vector as
well as the camera type and current position:



class Camera {



private:



CAM_TYPE CameraType;



Vector3D Position;



Vector3D Along;



Vector3D Up;



Vector3D Forward;



...

Camera Class Declaration


Various construction/destruction, update and control
functions are then declared publically:



class Camera {



...



public:



Camera(CAM_TYPE ct = LAND_CAM); // Default: land



virtual ~Camera();



void SetCameraType(CAM_TYPE ct);



Vector3D GetPosition();



void Reset();



void Update();



...

Camera Class Declaration


Finally, the motion and rotation functions are declared.


The boolean array,
Wall[4]
, is an extra feature which
modifies the motion of land cameras if they have to slide
against walls (as opposed to going through them)


class Camera {



...



public:



...



void Pitch(GLfloat theta);



void Yaw(GLfloat theta);



void Roll(GLfloat theta);



void Walk(GLfloat delta, bool Wall[4]);



void Strafe(GLfloat delta, bool Wall[4]);



void Fly(GLfloat delta);


};

Setup and Control Functions


The code listing on the following two slides is fairly self
-
explanatory


It comprises the basic constructor and destructor as well
as a function to alter the camera type


The Reset() function sets the camera position to (0,0,0)
and aligns the viewing axes with the local drawing
coordinate system


Note that the default Forward vector points along the
negative Z
-
axis

Setup and Control Functions


Camera::Camera(CAM_TYPE ct) {



SetCameraType(ct);



Reset();


}



Camera::~Camera() {


}



void Camera::SetCameraType(CAM_TYPEct) {



CameraType = ct;


}

Setup and Control Functions


Vector3D Camera::GetPosition() {



return Position;


}



void Camera::Reset() {



Position = Vector3D(0.0, 0.0, 0.0);



Along = Vector3D(1.0, 0.0, 0.0);



Up = Vector3D(0.0, 1.0, 0.0);



Forward = Vector3D(0.0, 0.0,
-
1.0);



Update();


}

Building the View Matrix


The last function called by Reset() is probably the most
important


The Update() function applies all changes made to the
viewing axes and camera position, and updates the view
in MODELVIEW mode


In actual fact, as with gluLookAt(), the perception of
camera motion is achieved by moving the objects around
the scene while keeping the camera at a fixed position


Instead of using translations and rotations, a view matrix
may be built, meaning that just one OpenGL function call
is needed


glLoadMatrix()

Building the View Matrix


First we obtain the camera virtual position coordinates
using the dot product of pairs of the view vectors:



void Camera::Update() {



GLfloat x = DotProduct(Along, Position);



GLfloat y = DotProduct(Up, Position);



GLfloat z = DotProduct(Forward, Position);



...



These will be used to translate the camera (or rather,
the scene) to its correct position

Building the View Matrix


The translation part of the view matrix is shown below:





1 0 0 0



T =

0 1 0 0




0 0 1 0





x

y z 1



Note that we must remember to make z positive, since
for convenience we have taken “Forward” as meaning
the direction
into

the screen which is opposite to
OpenGL convention (Z
-
axis is positive outwards)

Building the View Matrix


The rotation part of the view matrix is built from the
view vectors as shown:





A.x U.x

F.x



R =

A.y U.y

F.y




A.z U.z

F.z



Again, the Forward vector is reversed

Building the View Matrix


Combining these two matrices, we get:




1 0 0 0


A.x U.x

F.x

0


A.x U.x

F.x

0

V =

0 1 0 0 .


A.y U.y

F.y

0 =


A.y U.y

F.y

0



0 0 1 0


A.z U.z

F.z

0


A.z U.z

F.z

0




x

y z 1


0 0 0

1



x

y z 1



The code on the following slides shows the rest of the
implemented function

Building the View Matrix


void Camera::Update() {



...



Glfloat ViewMatrix[4][4];



ViewMatrix[0][0] = Along.x;



ViewMatrix[0][1] = Up.x;



ViewMatrix[0][2] =
-
Forward.x;



ViewMatrix[0][3] = 0.0;




ViewMatrix[1][0] = Along.y;



ViewMatrix[1][1] = Up.y;



ViewMatrix[1][2] =
-
Forward.y;



ViewMatrix[1][3] = 0.0;



...

Building the View Matrix



...



ViewMatrix[2][0] = Along.z;



ViewMatrix[2][1] = Up.z;



ViewMatrix[2][2] =
-
Forward.z;



ViewMatrix[2][3] = 0.0;




ViewMatrix[3][0] =
-
x;



ViewMatrix[3][1] =
-
y;



ViewMatrix[3][2] = z;



ViewMatrix[3][3] = 1.0;




glMatrixMode(GL_MODELVIEW);



glLoadMatrixf((GLfloat *)&ViewMatrix);


}

Camera Rotation Functions


The Pitch(), Yaw() and Roll() functions change the
direction of the Forward, Along and Up vectors
respectively


In each case, the rotation will result in the alteration of a
second view vector, leaving one unchanged


The second modified vector is found by calculating the
cross product of the other two vectors


This means that mutual orthognality is maintained for
the three vectors

Camera Rotation Functions


Looking at a yaw from above, we can see how to
calculate the new direction of the Along vector:

Camera Rotation Functions


Thus, for the Yaw function definition, we have:



void Camera::Yaw(GLfloat theta) {



Along = Along * cos(theta * DEG2RAD)




+ Forward * sin(theta * DEG2RAD);



Along.Normalize();



Forward = CrossProduct(Along, Up) *
-
1.0;



Update();


}



Pitch() and Roll() on the following slide look very similar

Camera Rotation Functions


void Camera::Pitch(GLfloat theta) {



// Invert UP/DOWN for air cameras



if(CameraType == AIR_CAM) theta =
-
theta;



Forward = Forward * cos(theta * DEG2RAD)





+ Up * sin(theta * DEG2RAD);



Forward.Normalize();



Up = CrossProduct(Forward, Along) *
-
1.0;



Update();


}



void Camera::Roll(GLfloat theta) {



if(CameraType == LAND_CAM) return; // Not for land cams



Up = Up * cos(theta * DEG2RAD)




-

Along * sin(theta * DEG2RAD);



Up.Normalize();



Along = CrossProduct(Forward, Up);



Update();


}

Camera Motion Functions


Walk(), Strafe() and Fly() are a little easier to implement


In each case, all we have to do is add the correct scaled
vector to the camera’s Position vector and update


As with rotation functions, motion functions work slightly
differently depending on the type of camera being used


For example, when walking forward with a land camera,
if the view has been pitched upwards, we do not want to
move up the camera’s forward vector, but rather along a
modified vector with the Y componet set to 0


this will
achieve the effect of staying on the ground rather than
taking off into the air.

Camera Rotation Functions


The Walk function with wall handling also implemented:



void Camera::Walk(GLfloat delta, bool Wall[4]) {



if(CameraType == LAND_CAM)



Position
-
= Vector3D(Forward.x *



!(Wall[0] && Forward.x * delta > 0.0 ||



Wall[1] && Forward.x * delta < 0.0),



0.0, Forward.z *



!(Wall[2] && Forward.z * delta > 0.0 ||



Wall[3] && Forward.z * delta < 0.0))



* delta;



else Position
-
= Forward * delta; // Air camera



Update();


}

Camera Rotation Functions


Similarly, the Strafe function is defined as follows:



void Camera::Strafe(GLfloat delta, bool Wall[4]) {



if(CameraType == LAND_CAM)



Position
-
= Vector3D(Along.x *



!(Wall[0] && Along.x * delta > 0.0 ||



Wall[1] && Along.x * delta < 0.0),



0.0, Along.z *



!(Wall[2] && Along.z * delta > 0.0 ||



Wall[3] && Along.z * delta < 0.0))



* delta;



else Position += Along * delta; // Air camera



Update();


}

Camera Rotation Functions


Finally, flying is, of course, only allowed for air cameras:



void Camera::Fly(GLfloat delta, bool Wall[4]) {



// Don't allow for land cameras



if(CameraType == LAND_CAM) return;



Position += Up * delta;



Update();


}



Although flying through walls has been allowed here,
this would be implemented in the same manner as the
previous two functions

References


Frank D. Luna, 2003,
Introduction to 3D Game
Programming with DirectX 9.0
, Wordware Publishing,
Inc.


Silicon Graphics Inc., 1997,
OpenGL Programming Guide,
Chapter 3


Viewing
, Addison
-
Wesley Publishing
Company


Philipp Crocoll, The Advanced CodeColony Camera,
http://www.codecolony.de/