1 //------------------------------------------------------------------------------
3 //------------------------------------------------------------------------------
4 // GLVU : Copyright 1997 - 2002
5 // The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its
8 // documentation for any purpose is hereby granted without fee, provided that
9 // the above copyright notice appear in all copies and that both that copyright
10 // notice and this permission notice appear in supporting documentation.
11 // Binaries may be compiled with this software without any royalties or
14 // The University of North Carolina at Chapel Hill makes no representations
15 // about the suitability of this software for any purpose. It is provided
16 // "as is" without express or implied warranty.
18 //============================================================================
19 // camera.cpp : camera class implementation
20 //----------------------------------------------------------------------------
22 //============================================================================
24 #include <simgear/compiler.h>
29 //----------------------------------------------------------------------------
30 // CONSTRUCTOR: defines a default camera system defined as (45 DEG FOV)
31 //----------------------------------------------------------------------------
34 X.Set(1,0,0); Y.Set(0,1,0); Z.Set(0,0,1);
36 Near=0.5f; Far=140.0f; wL=-1; wR=1; wT=1; wB=-1;
40 Camera::Camera(const Camera &Cam)
45 void Camera::Copy(const Camera &Cam)
47 X=Cam.X; Y=Cam.Y; Z=Cam.Z; Orig=Cam.Orig;
48 Near=Cam.Near; Far=Cam.Far;
49 wL=Cam.wL; wR=Cam.wR; wT=Cam.wT; wB=Cam.wB;
52 //----------------------------------------------------------------------------
53 // OpenGL CAMERA ORIENTATION ROUTINE (glLookAt)
54 //----------------------------------------------------------------------------
56 const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp)
58 Z = Eye-ViewRefPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
59 X = ViewUp/Z; X.Normalize();
60 Y = Z/X; Y.Normalize();
64 //----------------------------------------------------------------------------
65 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (gluPerspective)
66 // Aspect = Width/Height; Yfov in degrees
67 //----------------------------------------------------------------------------
68 void Camera::Perspective(float Yfov, float Aspect, float Ndist, float Fdist)
70 Yfov *= 0.0174532f; // CONVERT TO RADIANS
71 Near=Ndist; Far=Fdist;
72 wT=(float)tan(Yfov*0.5f)*Near; wB=-wT;
76 //----------------------------------------------------------------------------
77 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (glFrustum). Window extents
78 // are defined on the viewplane at z=-Ndist.
79 //----------------------------------------------------------------------------
80 void Camera::Frustum(float l, float r, float b, float t, float Ndist, float Fdist)
82 Near=Ndist; Far=Fdist;
83 wR=r; wL=l; wB=b; wT=t;
86 //----------------------------------------------------------------------------
87 // Completely defines a camera as a tight fitting frustum surrounding the
88 // given bounding sphere. This is useful when most precision
89 // is required in pixel and depth resolution (for example, shadow-maps).
90 // The resulting camera is not skewed!
91 //----------------------------------------------------------------------------
92 void Camera::TightlyFitToSphere(
93 const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad)
95 // FIRST DEFINE COORDINATE FRAME
96 LookAt(Eye,Cntr,ViewUp);
98 // PROJECTED DIST TO CNTR ALONG VIEWDIR
99 float DistToCntr = (Cntr-Orig) * ViewDir();
101 // CALC TIGHT-FITTING NEAR AND FAR PLANES
102 Near = DistToCntr-Rad;
103 Far = DistToCntr+Rad;
105 //x = n*R / sqrt(d2 - r2)
107 if (Near<=0 || Far<=0)
108 printf("ERROR (Camera::TightlyFitToSphere) Eye is inside the sphere!\n");
110 // CALC TIGHT-FITTING SIDES
111 wT = (Near * Rad) / (float)sqrt(DistToCntr*DistToCntr - Rad*Rad);//(Near * Rad) / DistToCntr;
117 //----------------------------------------------------------------------------
118 // Routines to return the Lookat, Perspective, and Frustum params.
119 // NOTE: Perspective is designed for non-skewed cameras: the viewing
120 // direction must be centered on the viewplane window. Use frustum
121 // for off-axis cameras.
122 //----------------------------------------------------------------------------
123 void Camera::GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const
126 *ViewRefPt = Orig - Z;
130 void Camera::GetPerspectiveParams(float *Yfov, float *Aspect,
131 float *Ndist, float *Fdist) const
133 *Yfov = (float)atan(wT/Near) * 57.29578f * 2.0f; // CONVERT TO DEGREES
139 void Camera::GetFrustumParams(float *l, float *r, float *b, float *t,
140 float *Ndist, float *Fdist) const
150 //----------------------------------------------------------------------------
151 // RETURNS THE COP OR EYE IN WORLD COORDS (ORIG OF CAMERA SYSTEM)
152 //----------------------------------------------------------------------------
153 const Vec3f& Camera::wCOP() const
158 //----------------------------------------------------------------------------
159 // RETURNS THE VIEWING DIRECTION
160 //----------------------------------------------------------------------------
161 Vec3f Camera::ViewDir() const
166 Vec3f Camera::ViewDirOffAxis() const
168 float x=(wL+wR)*0.5f, y=(wT+wB)*0.5f; // MIDPOINT ON VIEWPLANE WINDOW
169 Vec3f ViewDir = X*x + Y*y - Z*Near;
174 //----------------------------------------------------------------------------
175 // Vec3f WORLD-TO-CAM AND CAM-TO-WORLD ROUTINES
176 //----------------------------------------------------------------------------
177 Vec3f Camera::WorldToCam(const Vec3f& wP) const
180 Vec3f cP(X*sP,Y*sP,Z*sP); return(cP);
183 // Return the z-value of the world point in camera space
184 float Camera::WorldToCamZ(const Vec3f& wP) const
192 Vec3f Camera::CamToWorld(const Vec3f& cP) const
194 Vec3f wP(X*cP.x + Y*cP.y + Z*cP.z + Orig); return(wP);
197 //----------------------------------------------------------------------------
198 // Makes the camera pose be the identity. World and camera space will be the
199 // same. Window extents and near/far planes are unaffected.
200 //----------------------------------------------------------------------------
201 void Camera::LoadIdentityXform()
209 //----------------------------------------------------------------------------
210 // Applies an OpenGL style premult/col vector xform to the coordinate frame.
211 // Only rotates, translates, and uniform scales are allowed.
212 // Window extents and near/far planes are affected by scaling.
213 //----------------------------------------------------------------------------
214 void Camera::Xform(const float M[16])
216 X.Set( X.x*M[0] + X.y*M[4] + X.z*M[8],
217 X.x*M[1] + X.y*M[5] + X.z*M[9],
218 X.x*M[2] + X.y*M[6] + X.z*M[10] );
219 Y.Set( Y.x*M[0] + Y.y*M[4] + Y.z*M[8],
220 Y.x*M[1] + Y.y*M[5] + Y.z*M[9],
221 Y.x*M[2] + Y.y*M[6] + Y.z*M[10] );
222 Z.Set( Z.x*M[0] + Z.y*M[4] + Z.z*M[8],
223 Z.x*M[1] + Z.y*M[5] + Z.z*M[9],
224 Z.x*M[2] + Z.y*M[6] + Z.z*M[10] );
225 Orig.Set( Orig.x*M[0] + Orig.y*M[4] + Orig.z*M[8] + M[12],
226 Orig.x*M[1] + Orig.y*M[5] + Orig.z*M[9] + M[13],
227 Orig.x*M[2] + Orig.y*M[6] + Orig.z*M[10] + M[14] );
229 // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
230 float Scale = X.Length();
235 // SCALE THE WINDOW EXTENTS AND THE NEAR/FAR PLANES
245 //----------------------------------------------------------------------------
246 // Translates the camera by the vector amount trans.
247 //----------------------------------------------------------------------------
248 void Camera::Translate(const Vec3f& trans)
254 //----------------------------------------------------------------------------
255 // Translates the camera about its origin by the rotation matrix M.
256 //----------------------------------------------------------------------------
257 void Camera::Rotate(const float M[9])
259 X.Set( X.x*M[0] + X.y*M[3] + X.z*M[6],
260 X.x*M[1] + X.y*M[4] + X.z*M[7],
261 X.x*M[2] + X.y*M[5] + X.z*M[8] );
262 Y.Set( Y.x*M[0] + Y.y*M[3] + Y.z*M[6],
263 Y.x*M[1] + Y.y*M[4] + Y.z*M[7],
264 Y.x*M[2] + Y.y*M[5] + Y.z*M[8] );
265 Z.Set( Z.x*M[0] + Z.y*M[3] + Z.z*M[6],
266 Z.x*M[1] + Z.y*M[4] + Z.z*M[7],
267 Z.x*M[2] + Z.y*M[5] + Z.z*M[8] );
271 //----------------------------------------------------------------------------
272 // Returns the COMPOSITE xform matrix that takes a point in the object space
273 // to a screen space (pixel) point. The inverse is also provided.
274 // You have to give the pixel dimensions of the viewport window.
275 //----------------------------------------------------------------------------
276 float* Camera::GetXform_Screen2Obj(float* M, int WW, int WH) const
278 Screen2WorldXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
279 wL,wR,wB,wT,Near,Far,WW,WH);
283 float* Camera::GetXform_Obj2Screen(float* M, int WW, int WH) const
285 World2ScreenXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
286 wL,wR,wB,wT,Near,Far,WW,WH);
290 //----------------------------------------------------------------------------
291 // OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/COL VECT, 4x4 MATRIX)
292 // A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
293 // VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
294 // WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
295 // Modelview XFORM. The associated inverse matrices are also provided.
296 //----------------------------------------------------------------------------
297 float* Camera::GetModelviewMatrix(float* M) const
299 Viewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
303 float* Camera::GetInvModelviewMatrix(float* M) const
305 invViewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
309 float* Camera::GetProjectionMatrix(float* M) const
311 Frustum16fv(M,wL,wR,wB,wT,Near,Far);
315 void Camera::SetModelviewMatrix(const float* M)
317 Viewing2CoordFrame16fv(M, &(X.x), &(Y.x), &(Z.x), &(Orig.x));
320 float* Camera::GetInvProjectionMatrix(float* M) const
322 invFrustum16fv(M,wL,wR,wB,wT,Near,Far);
326 float* Camera::GetViewportMatrix(float* M, int WW, int WH) const
328 Viewport16fv(M,WW,WH);
332 float* Camera::GetInvViewportMatrix(float* M, int WW, int WH) const
334 invViewport16fv(M,WW,WH);
338 //----------------------------------------------------------------------------
339 // Given a screen pixel location (sx,sy) w/ (0,0) at the lower-left and the
340 // screen dimensions, return the ray (start,dir) of the ray in world coords.
341 //----------------------------------------------------------------------------
342 void Camera::GetPixelRay(float sx, float sy, int ww, int wh,
343 Vec3f *Start, Vec3f *Dir) const
345 Vec3f wTL = Orig + (X*wL) + (Y*wT) - (Z*Near); // FIND LOWER-LEFT
346 Vec3f dX = (X*(wR-wL))/(float)ww; // WORLD WIDTH OF PIXEL
347 Vec3f dY = (Y*(wT-wB))/(float)wh; // WORLD HEIGHT OF PIXEL
348 wTL += (dX*sx - dY*sy); // INCR TO WORLD PIXEL
349 wTL += (dX*0.5 - dY*0.5); // INCR TO PIXEL CNTR
354 //----------------------------------------------------------------------------
355 // READ AND WRITE CAMERA AXES AND ORIGIN TO AND FROM A FILE GIVEN A FILE PTR.
356 //----------------------------------------------------------------------------
357 void Camera::WriteToFile(FILE *fp) const
359 if (fp==NULL) { printf("ERROR WRITING CAM TO FILE!\n"); return; }
360 fprintf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f\n",
361 X.x,X.y,X.z, Y.x,Y.y,Y.z, Z.x,Z.y,Z.z, Orig.x,Orig.y,Orig.z);
364 int Camera::ReadFromFile(FILE *fp) // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
366 int Cond = fscanf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f",
367 &X.x,&X.y,&X.z, &Y.x,&Y.y,&Y.z,
368 &Z.x,&Z.y,&Z.z, &Orig.x,&Orig.y,&Orig.z);
372 //----------------------------------------------------------------------------
373 // 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
374 // (Left,Right, Bottom,Top, Near,Far)
375 // In order, near pts counter-clockwise starting with right-top-near (RTN) pt
376 // and then far pts ccw starting with right-top-far (RTF) pt
377 //----------------------------------------------------------------------------
378 void Camera::CalcVerts(Vec3f *V) const // MUST BE PREALLOCED : "Vec3f V[8]"
380 // WINDOW EXTENTS ARE DEFINED ON THE NEAR PLANE, CALC NEAR PTS (IN CAM COORDS)
382 V[0].Set(wR,wT,NearZ);
383 V[1].Set(wL,wT,NearZ);
384 V[2].Set(wL,wB,NearZ);
385 V[3].Set(wR,wB,NearZ);
387 // CALC FAR PTS (IN CAM COORDS)
388 float FarZ=-Far, FN=Far/Near;
389 float fwL=wL*FN, fwR=wR*FN, fwB=wB*FN, fwT=wT*FN;
390 V[4].Set(fwR,fwT,FarZ);
391 V[5].Set(fwL,fwT,FarZ);
392 V[6].Set(fwL,fwB,FarZ);
393 V[7].Set(fwR,fwB,FarZ);
395 // XFORM FRUSTUM IN CAM COORDS TO WORLD SPACE
396 for (int i=0; i<8; i++)
397 V[i] = CamToWorld(V[i]);
400 //----------------------------------------------------------------------------
402 //----------------------------------------------------------------------------
403 void Camera::Print() const
405 printf("Camera System Parameters:\n");
406 printf(" X: (%.3f, %.3f, %.3f)\n", X.x, X.y, X.z);
407 printf(" Y: (%.3f, %.3f, %.3f)\n", Y.x, Y.y, Y.z);
408 printf(" Z: (%.3f, %.3f, %.3f)\n", Z.x, Z.y, Z.z);
409 printf(" Origin: (%.3f, %.3f, %.3f)\n", Orig.x, Orig.y, Orig.z);
410 printf(" NFLRBT: (%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
411 Near,Far,wL,wR,wB,wT);