Creating a Flexible Camera Class

1 / 39

# Creating a Flexible Camera Class - PowerPoint PPT Presentation

Creating a Flexible Camera Class. Bryan Duggan. Refresher on Vectors. u.v = (u x v x + u y v y + u z v z ) p = u x v = (u y v z - u z v y , u z v x - u x v z, u x v y - u y v x ). Identity Matrix. Identity Matrix.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Creating a Flexible Camera Class' - pia

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Creating a Flexible Camera Class

Bryan Duggan

Refresher on Vectors
• u.v = (ux vx + uy vy + uz vz)
• p = u x v = (uy vz - uz vy, uz vx - ux vz, ux vy - uy vx)
Identity Matrix
• Identity Matrix
• The identity matrix has the property that if A is a square matrix, then
Local Space
• The co-ordinate system we define the objects triangle list
• Build all models around their own co-ordinates
• Construct models without regard to position and orientation
World Space
• World Transform brings
• Objects into the world
• Sets up the relationship between objects in the scene
• Translations rotations and scaling
• May be a different transform for each object in the scene
• Use:
• IDirect3DDevice::SetTransform(D3DTS_WORLD, &matrix);
View Space
• View Space transform:
• Translates the camera to the origin, looking down the positive Z-Axis
• We don’t need to calculate it!! DirectX has an API to do this:
• D3DXMatrixLookAtLH(

D3DXMATRIX * pOut

, D3DXVECTOR3 * eye

, D3DXVECTOR3 * at

, D3DXVECTOR3 * up)

• Up is usually (0,1,0)
• Use:
• IDirect3DDevice::SetTransform(D3DTS_VIEW, &matrix);
Backface culling
• All polygons have 2 sides. A front (visible) side
• And a back (invisible) side
• DirectX can cull the backfaces to reduce processing
• Triangles with vertices specified in a clockwise winding order are considered front facing
• Use: _

device->SetRenderState(D3DRS_CULLMODE, value)

Where value is:

• D3DCULL_NONE
• D3DCULL_CW
• D3DCULL-CCW
Projection
• Transforming a 3D Scene to a 2D one
• Uses perspective projection
• Far away objects are smaller
• Defines our frustum
The projection matrix
• Is complex to derive, but directX has an API to do it:

D3DXMATRIX proj;

D3DXMatrixPerspectiveFovLH(

&proj,

D3DX_PI * 0.5f, // 90 - degree

(float)_width / (float)_height,

1.0f,

1000.0f);

_device->SetTransform(D3DTS_PROJECTION, &proj);

The Viewport transform
• We can optionally transform to a viewport in the display window:

typedef struct _D3DVIEWPORT9

{

DWORD X;

DWORD Y;

DWORD Width;

DWORD Height;

float MinZ;

float MaxZ;

} D3DVIEWPORT9;

We set the viewport using:

_device->SetViewport(&vp)

FPS Camera
• In an FPS, the camera may need to:
• walk forwards and backwards (W, S keys)
• strafe left and right (A, D keys)
• fly/jump (space key?)
• Look around (the mouse)
• Pitch (look up and down)
• Yaw (Look left and right)
• Roll (tilt left and right)
A static camera can be programmed by…

// Position and aim the camera.

D3DXVECTOR3 position(-50.0f, 5.0f, -50.0f);

D3DXVECTOR3 target(0.0f, 5.0f, 0.0f);

D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

D3DXMATRIX V;

D3DXMatrixLookAtLH(&V, &position, &target, &up);

device->SetTransform(D3DTS_VIEW, &V);

This is ok for
• A fixed camera position, but not very flexible when we want to have a moving camera as most games
So lets create our own!
• To model a camera we require 4 vectors:
• _position
• _look
• _right
• _up

Must always be

mutually orthogonal

(perpendicular) to each other

_up

_look

_right

_position

Movement
• To walk:
• Position changes in units of the look vector
• Making sure we don’t change the Y value!! (A person can look at the ground, but we don’t want to go in that direction)
• To strafe:
• Position changes in units of the right vector
• To jump:
• Position changes in the y direction
• To look around:
• On the X-Axis, we rotate around the y-axis (Yaw)
• Rotate _right and _look
• Up and down, we rotate on the _right vector (pitch)
• Rotate _up and _look
walk:

void MoveableEntity::walk(float units)

{

D3DXVECTOR3 newPos;

newPos = _pos + D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;

BoundableEntity * boundableEntity = _world->collidesWith(&newPos);

if ((!_collisionDetection) || (boundableEntity == NULL) || (boundableEntity == this))

{

_moved = true;

_pos = newPos;

}

}

strafe

void MoveableEntity::strafe(float units)

{

D3DXVECTOR3 newPos;

newPos = _pos + D3DXVECTOR3(_right.x, 0.0f, _right.z) * units;

BoundableEntity * boundableEntity = _world->collidesWith(&newPos);

if ( (!_collisionDetection) || (boundableEntity == NULL) || (boundableEntity == this))

{

_moved = true;

_pos = newPos;

}

}

yaw

void MoveableEntity::yaw(float angle)

{

D3DXMATRIX T;

D3DXMatrixRotationY(&T, angle);

// rotate _right and _look around _up or y-axis

D3DXVec3TransformCoord(&_right,&_right, &T);

D3DXVec3TransformCoord(&_look,&_look, &T);

_moved = true;

}

pitch

void MoveableEntity::pitch(float angle)

{

D3DXMATRIX T;

D3DXMatrixRotationAxis(&T, &_right, angle);

// rotate _up and _look around _right vector

D3DXVec3TransformCoord(&_up,&_up, &T);

D3DXVec3TransformCoord(&_look,&_look, &T);

_moved = true;

}

View Matrix
• At some point, we need to make a view transform matrix
• The view transform does 3 things:
• Makes the camera 0, 0, 0. Everything in the world needs to be translated by the same amount
• Makes the camera looks down the positive Z axis
So we need to…
• Translate
• Translate the camera to the origin (and everything else by the same amount)
• Rotate
• Align the right vector with the x-axis (and everything else by the same amount)
• Align the up vector with the y-axis (and everything else by the same amount)
• Align the look vector with the z-axis (and everything else by the same amount)
• Our new view matrix combines those operations (multiplies the 4 matrices to generate a combined transformation)
Calculate the translation bit
• To translate by -px, -py, -pz, we multiply by:
Calculate the rotation matrix

Rotate the right vector so that it aligns with the x-axis

Rotate the up vector so that it aligns with the y-axis

Rotate the look vector so that it aligns with the z-axis

Solve for the matrix A
• Since A is the same in all 3 transformations, we can write them together:
Solve for Matrix A
• A is the inverse of B because:
• BA = BB-1 = I
• You get the inverse of a matrix by switching the rows and columns:
In code:

// Build the view matrix:

float x = -D3DXVec3Dot(&_right, &_pos);

float y = -D3DXVec3Dot(&_up, &_pos);

float z = -D3DXVec3Dot(&_look, &_pos);

(_viewMatrix)(0,0) = _right.x; (_viewMatrix)(0, 1) = _up.x; (_viewMatrix)(0, 2) = _look.x; (_viewMatrix)(0, 3) = 0.0f;

(_viewMatrix)(1,0) = _right.y; (_viewMatrix)(1, 1) = _up.y; (_viewMatrix)(1, 2) = _look.y; (_viewMatrix)(1, 3) = 0.0f;

(_viewMatrix)(2,0) = _right.z; (_viewMatrix)(2, 1) = _up.z; (_viewMatrix)(2, 2) = _look.z; (_viewMatrix)(2, 3) = 0.0f;

(_viewMatrix)(3,0) = x; (_viewMatrix)(3, 1) = y; (_viewMatrix)(3, 2) = z; (_viewMatrix)(3, 3) = 1.0f;

Mouse look
• The aim
• When the player moves the mouse left and right, we yaw
• When the player moves the mouse up and down, we pitch
• By how much is determined by the delta between the last mouse position and the current mouse position
Mouse look algorithm

handleEvent()

{

If (event == MOUSE_MOVEMENT)

{

midX = width / 2

midY = height / 2

deltaX = currentX – midX

deltaY = currentY – midY

yaw(deltaY * modifier_heuristic)

roll(deltaX * modifier_heuristic)

set_cursor(midX, midY)

}

}

To trap mouse events
• Windows calls the WinProc (the handler we registered to receive notifications of events
• The framework calls:
• handleEvent(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
• When a mouse movement has occurred, we receive WM_MOUSEMOVE as the msg parameter
Firstly some Win32 API code to turn off the mouse

case WM_SETCURSOR:

// Turn off window cursor

SetCursor(NULL);

_device->ShowCursor(TRUE);

return TRUE; // prevent Windows from setting cursor to window class cursor

break;

Now to capture the mouse:

case WM_MOUSEMOVE:

midX = _width / 2;

midY = _height / 2;

POINT p;

GetCursorPos(&p);

xPos = p.x;

yPos = p.y;

if ((xPos == midX) && (yPos == midY))

{

break;

}

deltaX = xPos - midX;

deltaY = yPos - midY;

_camera->yaw(((float)deltaX) / 100.0f);

_camera->pitch(((float)deltaY) / 100.0f);

SetCursorPos(midX, midY);

break;

RTS Camera
• Camera position is over the world
• Enable the mouse cursor
• When the cursor moves to the extremes of the window:
• Pan left & right
• Move the position in units of the right vector
• Without affecting the Y
• Forward & backwards
• Move the position in units of the look vector
• Without affecting the Y
Extra operations
• Zoom in and out by using the scroll wheel?
• Free Rotate by holding down the ALT key?
Some important Win32 Calls!
• _device->ShowCursor(TRUE);
• Turns on the cursor
• GetWindowRect
• To get the window size
• ClipCursor
• To keep the cursor within certain screen coordinates
• GET_X_LPARAM(lParam);
• GET_Y_LPARAM(lParam);
• To get the X and Y of the cursor
Picking
• If we enable the mouse, we need to know when the user clicks something, what it is
• We need to translate from a screen position (x, y) to an (x, y, z) in our world