Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Camera.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2010 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * CCamera holds a view and a projection matrix. It also has a frustum
20  * which can be used to cull objects for rendering.
21  */
22 
23 #include "precompiled.h"
24 
25 #include "Camera.h"
26 
27 #include "graphics/HFTracer.h"
28 #include "graphics/Terrain.h"
29 #include "lib/ogl.h"
30 #include "maths/MathUtil.h"
31 #include "maths/Vector4D.h"
32 #include "ps/Game.h"
33 #include "ps/World.h"
34 #include "renderer/Renderer.h"
35 #include "renderer/WaterManager.h"
36 
38 {
39  // set viewport to something anything should handle, but should be initialised
40  // to window size before use
41  m_ViewPort.m_X = 0;
42  m_ViewPort.m_Y = 0;
43  m_ViewPort.m_Width = 800;
44  m_ViewPort.m_Height = 600;
45 }
46 
48 {
49 }
50 
51 void CCamera::SetProjection(float nearp, float farp, float fov)
52 {
53  m_NearPlane = nearp;
54  m_FarPlane = farp;
55  m_FOV = fov;
56 
57  float aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
58  float f = 1.0f/tanf(m_FOV/2);
59 
60  m_ProjMat.SetZero ();
61  m_ProjMat._11 = f/aspect;
62  m_ProjMat._22 = f;
65  m_ProjMat._43 = 1.0f;
66 }
67 
68 void CCamera::SetProjectionTile(int tiles, int tile_x, int tile_y)
69 {
70 
71  float aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
72  float f = 1.0f/tanf(m_FOV/2);
73 
74  m_ProjMat._11 = tiles*f/aspect;
75  m_ProjMat._22 = tiles*f;
76  m_ProjMat._13 = -(1-tiles + 2*tile_x);
77  m_ProjMat._23 = -(1-tiles + 2*tile_y);
78 }
79 
80 //Updates the frustum planes. Should be called
81 //everytime the view or projection matrices are
82 //altered.
84 {
85  CMatrix3D MatFinal;
86  CMatrix3D MatView;
87 
88  m_Orientation.GetInverse(MatView);
89 
90  MatFinal = m_ProjMat * MatView;
91 
92  // get the RIGHT plane
94 
95  m_ViewFrustum.m_aPlanes[0].m_Norm.X = scissor[1].X*MatFinal._41 - MatFinal._11;
96  m_ViewFrustum.m_aPlanes[0].m_Norm.Y = scissor[1].X*MatFinal._42 - MatFinal._12;
97  m_ViewFrustum.m_aPlanes[0].m_Norm.Z = scissor[1].X*MatFinal._43 - MatFinal._13;
98  m_ViewFrustum.m_aPlanes[0].m_Dist = scissor[1].X*MatFinal._44 - MatFinal._14;
99 
100  // get the LEFT plane
101  m_ViewFrustum.m_aPlanes[1].m_Norm.X = -scissor[0].X*MatFinal._41 + MatFinal._11;
102  m_ViewFrustum.m_aPlanes[1].m_Norm.Y = -scissor[0].X*MatFinal._42 + MatFinal._12;
103  m_ViewFrustum.m_aPlanes[1].m_Norm.Z = -scissor[0].X*MatFinal._43 + MatFinal._13;
104  m_ViewFrustum.m_aPlanes[1].m_Dist = -scissor[0].X*MatFinal._44 + MatFinal._14;
105 
106  // get the BOTTOM plane
107  m_ViewFrustum.m_aPlanes[2].m_Norm.X = -scissor[0].Y*MatFinal._41 + MatFinal._21;
108  m_ViewFrustum.m_aPlanes[2].m_Norm.Y = -scissor[0].Y*MatFinal._42 + MatFinal._22;
109  m_ViewFrustum.m_aPlanes[2].m_Norm.Z = -scissor[0].Y*MatFinal._43 + MatFinal._23;
110  m_ViewFrustum.m_aPlanes[2].m_Dist = -scissor[0].Y*MatFinal._44 + MatFinal._24;
111 
112  // get the TOP plane
113  m_ViewFrustum.m_aPlanes[3].m_Norm.X = scissor[1].Y*MatFinal._41 - MatFinal._21;
114  m_ViewFrustum.m_aPlanes[3].m_Norm.Y = scissor[1].Y*MatFinal._42 - MatFinal._22;
115  m_ViewFrustum.m_aPlanes[3].m_Norm.Z = scissor[1].Y*MatFinal._43 - MatFinal._23;
116  m_ViewFrustum.m_aPlanes[3].m_Dist = scissor[1].Y*MatFinal._44 - MatFinal._24;
117 
118  // get the FAR plane
119  m_ViewFrustum.m_aPlanes[4].m_Norm.X = scissor[1].Z*MatFinal._41 - MatFinal._31;
120  m_ViewFrustum.m_aPlanes[4].m_Norm.Y = scissor[1].Z*MatFinal._42 - MatFinal._32;
121  m_ViewFrustum.m_aPlanes[4].m_Norm.Z = scissor[1].Z*MatFinal._43 - MatFinal._33;
122  m_ViewFrustum.m_aPlanes[4].m_Dist = scissor[1].Z*MatFinal._44 - MatFinal._34;
123 
124  // get the NEAR plane
125  m_ViewFrustum.m_aPlanes[5].m_Norm.X = -scissor[0].Z*MatFinal._41 + MatFinal._31;
126  m_ViewFrustum.m_aPlanes[5].m_Norm.Y = -scissor[0].Z*MatFinal._42 + MatFinal._32;
127  m_ViewFrustum.m_aPlanes[5].m_Norm.Z = -scissor[0].Z*MatFinal._43 + MatFinal._33;
128  m_ViewFrustum.m_aPlanes[5].m_Dist = -scissor[0].Z*MatFinal._44 + MatFinal._34;
129 }
130 
131 void CCamera::ClipFrustum(const CPlane& clipPlane)
132 {
133  m_ViewFrustum.AddPlane(clipPlane);
134 }
135 
136 void CCamera::SetViewPort(const SViewPort& viewport)
137 {
138  m_ViewPort.m_X = viewport.m_X;
139  m_ViewPort.m_Y = viewport.m_Y;
140  m_ViewPort.m_Width = viewport.m_Width;
141  m_ViewPort.m_Height = viewport.m_Height;
142 }
143 
144 
145 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
146 // GetCameraPlanePoints: return four points in camera space at given distance from camera
147 void CCamera::GetCameraPlanePoints(float dist, CVector3D pts[4]) const
148 {
149  float aspect = float(m_ViewPort.m_Width)/float(m_ViewPort.m_Height);
150  float x = dist*aspect*tanf(m_FOV*0.5f);
151  float y = dist*tanf(m_FOV*0.5f);
152 
153  pts[0].X = -x;
154  pts[0].Y = -y;
155  pts[0].Z = dist;
156  pts[1].X = x;
157  pts[1].Y = -y;
158  pts[1].Z = dist;
159  pts[2].X = x;
160  pts[2].Y = y;
161  pts[2].Z = dist;
162  pts[3].X = -x;
163  pts[3].Y = y;
164  pts[3].Z = dist;
165 }
166 
167 void CCamera::BuildCameraRay(int px, int py, CVector3D& origin, CVector3D& dir) const
168 {
169  CVector3D cPts[4];
171 
172  // transform to world space
173  CVector3D wPts[4];
174  for (int i = 0; i < 4; i++)
175  wPts[i] = m_Orientation.Transform(cPts[i]);
176 
177  // get world space position of mouse point
178  float dx = (float)px / (float)g_Renderer.GetWidth();
179  float dz = 1 - (float)py / (float)g_Renderer.GetHeight();
180 
181  CVector3D vdx = wPts[1] - wPts[0];
182  CVector3D vdz = wPts[3] - wPts[0];
183  CVector3D pt = wPts[0] + (vdx * dx) + (vdz * dz);
184 
185  // copy origin
186  origin = m_Orientation.GetTranslation();
187  // build direction
188  dir = pt - origin;
189  dir.Normalize();
190 }
191 
192 void CCamera::GetScreenCoordinates(const CVector3D& world, float& x, float& y) const
193 {
195 
196  CVector4D screenspace = transform.Transform(CVector4D(world.X, world.Y, world.Z, 1.0f));
197 
198  x = screenspace.X / screenspace.W;
199  y = screenspace.Y / screenspace.W;
200  x = (x + 1) * 0.5f * g_Renderer.GetWidth();
201  y = (1 - y) * 0.5f * g_Renderer.GetHeight();
202 }
203 
204 CVector3D CCamera::GetWorldCoordinates(int px, int py, bool aboveWater) const
205 {
206  CHFTracer tracer(g_Game->GetWorld()->GetTerrain());
207  int x, z;
208  CVector3D origin, dir, delta, terrainPoint, waterPoint;
209 
210  BuildCameraRay(px, py, origin, dir);
211 
212 
213  bool gotTerrain = tracer.RayIntersect(origin, dir, x, z, terrainPoint);
214 
215  if (!aboveWater)
216  {
217  if (gotTerrain)
218  return terrainPoint;
219 
220  // Off the edge of the world?
221  // Work out where it /would/ hit, if the map were extended out to infinity with average height.
222  return GetWorldCoordinates(px, py, 50.0f);
223  }
224 
225  CPlane plane;
226  plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal
227  CVector3D(0.f, g_Renderer.GetWaterManager()->m_WaterHeight, 0.f)); // passes through water plane
228 
229  bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint );
230 
231  // Clamp the water intersection to within the map's bounds, so that
232  // we'll always return a valid position on the map
234  if (gotWater)
235  {
236  waterPoint.X = clamp(waterPoint.X, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
237  waterPoint.Z = clamp(waterPoint.Z, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
238  }
239 
240  if (gotTerrain)
241  {
242  if (gotWater)
243  {
244  // Intersecting both heightmap and water plane; choose the closest of those
245  if ((origin - terrainPoint).LengthSquared() < (origin - waterPoint).LengthSquared())
246  return terrainPoint;
247  else
248  return waterPoint;
249  }
250  else
251  {
252  // Intersecting heightmap but parallel to water plane
253  return terrainPoint;
254  }
255  }
256  else
257  {
258  if (gotWater)
259  {
260  // Only intersecting water plane
261  return waterPoint;
262  }
263  else
264  {
265  // Not intersecting terrain or water; just return 0,0,0.
266  return CVector3D(0.f, 0.f, 0.f);
267  }
268  }
269 
270 }
271 
272 CVector3D CCamera::GetWorldCoordinates(int px, int py, float h) const
273 {
274  CPlane plane;
275  plane.Set(CVector3D(0.f, 1.f, 0.f), CVector3D(0.f, h, 0.f)); // upwards normal, passes through h
276 
277  CVector3D origin, dir, delta, currentTarget;
278 
279  BuildCameraRay(px, py, origin, dir);
280 
281  if (plane.FindRayIntersection(origin, dir, &currentTarget))
282  return currentTarget;
283 
284  // No intersection with the infinite plane - nothing sensible can be returned,
285  // so just choose an arbitrary point on the plane
286  return CVector3D(0.f, h, 0.f);
287 }
288 
290 {
291  // Basically the same as GetWorldCoordinates
292 
293  CHFTracer tracer(g_Game->GetWorld()->GetTerrain());
294  int x, z;
295 
296  CVector3D origin, dir, delta, terrainPoint, waterPoint;
297 
298  origin = m_Orientation.GetTranslation();
299  dir = m_Orientation.GetIn();
300 
301  bool gotTerrain = tracer.RayIntersect(origin, dir, x, z, terrainPoint);
302 
303  CPlane plane;
304  plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal
305  CVector3D(0.f, g_Renderer.GetWaterManager()->m_WaterHeight, 0.f)); // passes through water plane
306 
307  bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint );
308 
309  // Clamp the water intersection to within the map's bounds, so that
310  // we'll always return a valid position on the map
312  if (gotWater)
313  {
314  waterPoint.X = clamp(waterPoint.X, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
315  waterPoint.Z = clamp(waterPoint.Z, 0.f, (float)((mapSize-1)*TERRAIN_TILE_SIZE));
316  }
317 
318  if (gotTerrain)
319  {
320  if (gotWater)
321  {
322  // Intersecting both heightmap and water plane; choose the closest of those
323  if ((origin - terrainPoint).LengthSquared() < (origin - waterPoint).LengthSquared())
324  return terrainPoint;
325  else
326  return waterPoint;
327  }
328  else
329  {
330  // Intersecting heightmap but parallel to water plane
331  return terrainPoint;
332  }
333  }
334  else
335  {
336  if (gotWater)
337  {
338  // Only intersecting water plane
339  return waterPoint;
340  }
341  else
342  {
343  // Not intersecting terrain or water; just return 0,0,0.
344  return CVector3D(0.f, 0.f, 0.f);
345  }
346  }
347 }
348 
349 void CCamera::LookAt(const CVector3D& camera, const CVector3D& target, const CVector3D& up)
350 {
351  CVector3D delta = target - camera;
352  LookAlong(camera, delta, up);
353 }
354 
355 void CCamera::LookAlong(CVector3D camera, CVector3D orientation, CVector3D up)
356 {
357  orientation.Normalize();
358  up.Normalize();
359  CVector3D s = orientation.Cross(up);
360 
361  m_Orientation._11 = -s.X; m_Orientation._12 = up.X; m_Orientation._13 = orientation.X; m_Orientation._14 = camera.X;
362  m_Orientation._21 = -s.Y; m_Orientation._22 = up.Y; m_Orientation._23 = orientation.Y; m_Orientation._24 = camera.Y;
363  m_Orientation._31 = -s.Z; m_Orientation._32 = up.Z; m_Orientation._33 = orientation.Z; m_Orientation._34 = camera.Z;
364  m_Orientation._41 = 0.0f; m_Orientation._42 = 0.0f; m_Orientation._43 = 0.0f; m_Orientation._44 = 1.0f;
365 }
366 
367 
368 ///////////////////////////////////////////////////////////////////////////////////
369 // Render the camera's frustum
370 void CCamera::Render(int intermediates) const
371 {
372 #if CONFIG2_GLES
373 #warning TODO: implement camera frustum for GLES
374 #else
375  CVector3D nearPoints[4];
376  CVector3D farPoints[4];
377 
378  GetCameraPlanePoints(m_NearPlane, nearPoints);
379  GetCameraPlanePoints(m_FarPlane, farPoints);
380  for(int i = 0; i < 4; i++)
381  {
382  nearPoints[i] = m_Orientation.Transform(nearPoints[i]);
383  farPoints[i] = m_Orientation.Transform(farPoints[i]);
384  }
385 
386  // near plane
387  glBegin(GL_POLYGON);
388  glVertex3fv(&nearPoints[0].X);
389  glVertex3fv(&nearPoints[1].X);
390  glVertex3fv(&nearPoints[2].X);
391  glVertex3fv(&nearPoints[3].X);
392  glEnd();
393 
394  // far plane
395  glBegin(GL_POLYGON);
396  glVertex3fv(&farPoints[0].X);
397  glVertex3fv(&farPoints[1].X);
398  glVertex3fv(&farPoints[2].X);
399  glVertex3fv(&farPoints[3].X);
400  glEnd();
401 
402  // connection lines
403  glBegin(GL_QUAD_STRIP);
404  glVertex3fv(&nearPoints[0].X);
405  glVertex3fv(&farPoints[0].X);
406  glVertex3fv(&nearPoints[1].X);
407  glVertex3fv(&farPoints[1].X);
408  glVertex3fv(&nearPoints[2].X);
409  glVertex3fv(&farPoints[2].X);
410  glVertex3fv(&nearPoints[3].X);
411  glVertex3fv(&farPoints[3].X);
412  glVertex3fv(&nearPoints[0].X);
413  glVertex3fv(&farPoints[0].X);
414  glEnd();
415 
416  // intermediate planes
417  CVector3D intermediatePoints[4];
418  for(int i = 0; i < intermediates; ++i)
419  {
420  float t = (i+1.0)/(intermediates+1.0);
421 
422  for(int j = 0; j < 4; ++j)
423  intermediatePoints[j] = nearPoints[j]*t + farPoints[j]*(1.0-t);
424 
425  glBegin(GL_POLYGON);
426  glVertex3fv(&intermediatePoints[0].X);
427  glVertex3fv(&intermediatePoints[1].X);
428  glVertex3fv(&intermediatePoints[2].X);
429  glVertex3fv(&intermediatePoints[3].X);
430  glEnd();
431  }
432 #endif
433 }
~CCamera()
Definition: Camera.cpp:47
float _21
Definition: Matrix3D.h:42
float _22
Definition: Matrix3D.h:43
float _12
Definition: Matrix3D.h:43
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
Definition: Decompose.h:22
float _44
Definition: Matrix3D.h:45
bool FindRayIntersection(const CVector3D &start, const CVector3D &direction, CVector3D *intsect)
Definition: Plane.cpp:127
float m_NearPlane
Definition: Camera.h:118
int m_Y
Definition: Camera.h:34
void SetZero()
Definition: Matrix3D.cpp:39
float _43
Definition: Matrix3D.h:44
CVector3D Cross(const CVector3D &vector) const
Definition: Vector3D.cpp:55
ssize_t GetVerticesPerSide() const
Definition: Terrain.h:65
CVector3D Transform(const CVector3D &vector) const
Definition: Matrix3D.h:272
float m_FarPlane
Definition: Camera.h:119
void Normalize()
Definition: Vector3D.cpp:77
CVector3D GetWorldCoordinates(int px, int py, bool aboveWater=false) const
Definition: Camera.cpp:204
float _32
Definition: Matrix3D.h:43
void LookAlong(CVector3D camera, CVector3D focus, CVector3D up)
Definition: Camera.cpp:355
void Set(const CVector3D &p1, const CVector3D &p2, const CVector3D &p3)
Definition: Plane.cpp:36
float _11
Definition: Matrix3D.h:42
int m_Height
Definition: Camera.h:36
float Y
Definition: Vector4D.h:128
#define g_Renderer
Definition: Renderer.h:61
CTerrain * GetTerrain()
Get the pointer to the terrain object.
Definition: World.h:88
float _33
Definition: Matrix3D.h:44
CVector3D GetIn() const
Definition: Matrix3D.cpp:253
float X
Definition: Vector3D.h:31
void LookAt(const CVector3D &camera, const CVector3D &orientation, const CVector3D &up)
Definition: Camera.cpp:349
float Y
Definition: Vector3D.h:31
float _13
Definition: Matrix3D.h:44
float _31
Definition: Matrix3D.h:42
void AddPlane(const CPlane &plane)
Definition: Frustum.cpp:52
void GetCameraPlanePoints(float dist, CVector3D pts[4]) const
Definition: Camera.cpp:147
float _42
Definition: Matrix3D.h:43
CGame * g_Game
Globally accessible pointer to the CGame object.
Definition: Game.cpp:56
void GetScreenCoordinates(const CVector3D &world, float &x, float &y) const
Definition: Camera.cpp:192
void ClipFrustum(const CPlane &clipPlane)
Definition: Camera.cpp:131
float _24
Definition: Matrix3D.h:45
void SetViewPort(const SViewPort &viewport)
Definition: Camera.cpp:136
intptr_t ssize_t
Definition: wposix_types.h:82
float _34
Definition: Matrix3D.h:45
CPlane m_aPlanes[MAX_NUM_FRUSTUM_PLANES]
Definition: Frustum.h:65
void UpdateFrustum(const CBoundingBoxAligned &scissor=CBoundingBoxAligned(CVector3D(-1.0f,-1.0f,-1.0f), CVector3D(1.0f, 1.0f, 1.0f)))
Definition: Camera.cpp:83
CFrustum m_ViewFrustum
Definition: Camera.h:123
float W
Definition: Vector4D.h:128
void BuildCameraRay(int px, int py, CVector3D &origin, CVector3D &dir) const
Definition: Camera.cpp:167
CVector3D m_Norm
Definition: Plane.h:67
CCamera()
Definition: Camera.cpp:37
float _23
Definition: Matrix3D.h:44
void GetInverse(CMatrix3D &dst) const
Definition: Matrix3D.cpp:277
int m_Width
Definition: Camera.h:35
void SetNumPlanes(size_t num)
Definition: Frustum.cpp:43
static float LengthSquared(const SVec3 v)
Definition: mikktspace.cpp:107
CMatrix3D m_Orientation
Definition: Camera.h:112
SViewPort m_ViewPort
Definition: Camera.h:121
CWorld * GetWorld()
Get the pointer to the game world object.
Definition: Game.h:120
float Z
Definition: Vector3D.h:31
Definition: Plane.h:38
CMatrix3D m_ProjMat
Definition: Camera.h:115
void Render(int intermediates=0) const
Render: Renders the camera&#39;s frustum in world space.
Definition: Camera.cpp:370
CVector3D GetTranslation() const
Definition: Matrix3D.cpp:195
int m_X
Definition: Camera.h:33
float _41
Definition: Matrix3D.h:42
CVector3D GetFocus() const
Definition: Camera.cpp:289
void SetProjectionTile(int tiles, int tile_x, int tile_y)
Definition: Camera.cpp:68
float m_FOV
Definition: Camera.h:120
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
void SetProjection(float nearp, float farp, float fov)
Definition: Camera.cpp:51
float m_Dist
Definition: Plane.h:68
float X
Definition: Vector4D.h:128
float _14
Definition: Matrix3D.h:45