-
Notifications
You must be signed in to change notification settings - Fork 0
/
Camera.cpp
166 lines (136 loc) · 6.69 KB
/
Camera.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//--------------------------------------------------------------------------------------
// Camera.cpp
//
// The camera class encapsulates the camera's view and projection matrix
//--------------------------------------------------------------------------------------
#include "Defines.h" // General definitions shared by all source files
#include "Camera.h" // Declaration of this class
///////////////////////////////
// Constructors / Destructors
// Constructor - initialise all camera settings - look at the constructor declaration in the header file to see that there are defaults provided for everything
CCamera::CCamera( D3DXVECTOR3 position, D3DXVECTOR3 rotation, float fov, float nearClip, float farClip )
{
m_Position = position;
m_Rotation = rotation;
m_Aspect = 1.333f; // Shouldn't be hard-coded (viewport width / viewport height)
SetFOV( fov );
SetNearClip( nearClip );
SetFarClip( farClip );
UpdateMatrices();
}
///////////////////////////////
// Camera Usage
// Update the matrices used for the camera in the rendering pipeline. Treat the camera like a model and create a world matrix for it. Then convert that into
// the view matrix that the rendering pipeline actually uses. Also create the projection matrix
//**** These matrices are created for a monoscopic camera, the getters below adjust for left/right eye
void CCamera::UpdateMatrices()
{
// Make matrices for position and rotations, then multiply together to get a "camera world matrix"
D3DXMATRIXA16 matrixXRot, matrixYRot, matrixZRot, matrixTranslation;
D3DXMatrixRotationX( &matrixXRot, m_Rotation.x );
D3DXMatrixRotationY( &matrixYRot, m_Rotation.y );
D3DXMatrixRotationZ( &matrixZRot, m_Rotation.z );
D3DXMatrixTranslation( &matrixTranslation, m_Position.x, m_Position.y, m_Position.z);
m_WorldMatrix = matrixZRot * matrixXRot * matrixYRot * matrixTranslation;
// The rendering pipeline actually needs the inverse of the camera world matrix - called the view matrix. Creating an inverse is easy with DirectX:
D3DXMatrixInverse( &m_ViewMatrix, NULL, &m_WorldMatrix );
// Initialize the projection matrix. This determines viewing properties of the camera such as field of view (FOV) and near clip distance
// One other factor in the projection matrix is the aspect ratio of screen (width/height) - used to adjust FOV between horizontal and vertical
float aspect = (float)g_ViewportWidth / g_ViewportHeight;
D3DXMatrixPerspectiveFovLH( &m_ProjMatrix, m_FOV, m_Aspect, m_NearClip, m_FarClip );
// Combine the view and projection matrix into a single matrix - which can (optionally) be used in the vertex shaders to save one matrix multiply per vertex
m_ViewProjMatrix = m_ViewMatrix * m_ProjMatrix;
}
//**|3D|*********************************/
// Camera matrix access / stereo offsets
// Get position of the camera. If a left or right stereo view is selected, then adjust position returned accordingly
D3DXVECTOR3 CCamera::GetPosition( EStereoscopic stereo, float interocular )
{
if (stereo == Monoscopic) return m_Position;
// Offset camera by half interocular distance left or right as appropriate
float offset = interocular * (stereo == StereoscopicLeft ? 0.5f : -0.5f);
D3DXVECTOR3 position = m_Position;
position.x += m_WorldMatrix._11 * offset;
position.y += m_WorldMatrix._12 * offset;
position.z += m_WorldMatrix._13 * offset;
return position;
}
// Get view matrix of camera. If a left or right stereo view is selected, then adjust position in matrix accordingly
D3DXMATRIXA16 CCamera::GetViewMatrix( EStereoscopic stereo, float interocular )
{
// Not stereoscopic
if (stereo == Monoscopic) return m_ViewMatrix;
// Offset camera by half interocular distance left or right as appropriate
float offset = interocular * (stereo == StereoscopicLeft ? 0.5f : -0.5f);
D3DXMATRIXA16 viewMatrix;
D3DXMATRIXA16 worldMatrix = m_WorldMatrix;
worldMatrix._41 += offset * worldMatrix._11;
worldMatrix._42 += offset * worldMatrix._12;
worldMatrix._43 += offset * worldMatrix._13;
//** MISSING shift the x position in the camera's worldMatrix by the offset calculated above
// Needs to move in the local x-axis - the function above offers guidance
// Invert camera's adjusted "world matrix" to create view matrix
D3DXMatrixInverse( &viewMatrix, NULL, &worldMatrix );
return viewMatrix;
}
// Get projection matrix of camera. If a left or right stereo view is selected, then adjust matrix as discussed in lecture
D3DXMATRIXA16 CCamera::GetProjectionMatrix( EStereoscopic stereo, float interocular, float screenDistance )
{
// Not stereoscopic
if (stereo == Monoscopic) return m_ProjMatrix;
// Offset camera by half interocular distance left or right as appropriate
float offset = interocular * (stereo == StereoscopicLeft ? 0.5f :- 0.5f);
// Offset viewing frustum based on camera offset (as discussed in lecture)
D3DXMATRIXA16 projMatrix = m_ProjMatrix;
//** MISSING - set the single value in the projection matrix that is different for offset cameras - see the lecture notes
projMatrix._31 = (offset / screenDistance) / (m_Aspect * tanf(m_FOV/2));
return projMatrix;
}
//***************************************/
// Control the camera's position and rotation using keys provided. Amount of motion performed depends on frame time
void CCamera::Control( float frameTime, EKeyCode turnUp, EKeyCode turnDown, EKeyCode turnLeft, EKeyCode turnRight,
EKeyCode moveForward, EKeyCode moveBackward, EKeyCode moveLeft, EKeyCode moveRight)
{
if (KeyHeld( turnDown ))
{
m_Rotation.x += RotSpeed * frameTime;
}
if (KeyHeld( turnUp ))
{
m_Rotation.x -= RotSpeed * frameTime;
}
if (KeyHeld( turnRight ))
{
m_Rotation.y += RotSpeed * frameTime;
}
if (KeyHeld( turnLeft ))
{
m_Rotation.y -= RotSpeed * frameTime;
}
// Local X movement - move in the direction of the X axis, get axis from camera's "world" matrix
if (KeyHeld( moveRight ))
{
m_Position.x += m_WorldMatrix._11 * MoveSpeed * frameTime;
m_Position.y += m_WorldMatrix._12 * MoveSpeed * frameTime;
m_Position.z += m_WorldMatrix._13 * MoveSpeed * frameTime;
}
if (KeyHeld( moveLeft ))
{
m_Position.x -= m_WorldMatrix._11 * MoveSpeed * frameTime;
m_Position.y -= m_WorldMatrix._12 * MoveSpeed * frameTime;
m_Position.z -= m_WorldMatrix._13 * MoveSpeed * frameTime;
}
// Local Z movement - move in the direction of the Z axis, get axis from view matrix
if (KeyHeld( moveForward ))
{
m_Position.x += m_WorldMatrix._31 * MoveSpeed * frameTime;
m_Position.y += m_WorldMatrix._32 * MoveSpeed * frameTime;
m_Position.z += m_WorldMatrix._33 * MoveSpeed * frameTime;
}
if (KeyHeld( moveBackward ))
{
m_Position.x -= m_WorldMatrix._31 * MoveSpeed * frameTime;
m_Position.y -= m_WorldMatrix._32 * MoveSpeed * frameTime;
m_Position.z -= m_WorldMatrix._33 * MoveSpeed * frameTime;
}
}