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 //============================================================================
26 //----------------------------------------------------------------------------
27 // CONSTRUCTOR: defines a default camera system defined as (45 DEG FOV)
28 //----------------------------------------------------------------------------
31 X.Set(1,0,0); Y.Set(0,1,0); Z.Set(0,0,1);
33 Near=0.5f; Far=140.0f; wL=-1; wR=1; wT=1; wB=-1;
37 Camera::Camera(const Camera &Cam)
42 void Camera::Copy(const Camera &Cam)
44 X=Cam.X; Y=Cam.Y; Z=Cam.Z; Orig=Cam.Orig;
45 Near=Cam.Near; Far=Cam.Far;
46 wL=Cam.wL; wR=Cam.wR; wT=Cam.wT; wB=Cam.wB;
49 //----------------------------------------------------------------------------
50 // OpenGL CAMERA ORIENTATION ROUTINE (glLookAt)
51 //----------------------------------------------------------------------------
53 const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp)
55 Z = Eye-ViewRefPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
56 X = ViewUp/Z; X.Normalize();
57 Y = Z/X; Y.Normalize();
61 //----------------------------------------------------------------------------
62 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (gluPerspective)
63 // Aspect = Width/Height; Yfov in degrees
64 //----------------------------------------------------------------------------
65 void Camera::Perspective(float Yfov, float Aspect, float Ndist, float Fdist)
67 Yfov *= 0.0174532f; // CONVERT TO RADIANS
68 Near=Ndist; Far=Fdist;
69 wT=(float)tan(Yfov*0.5f)*Near; wB=-wT;
73 //----------------------------------------------------------------------------
74 // OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (glFrustum). Window extents
75 // are defined on the viewplane at z=-Ndist.
76 //----------------------------------------------------------------------------
77 void Camera::Frustum(float l, float r, float b, float t, float Ndist, float Fdist)
79 Near=Ndist; Far=Fdist;
80 wR=r; wL=l; wB=b; wT=t;
83 //----------------------------------------------------------------------------
84 // Completely defines a camera as a tight fitting frustum surrounding the
85 // given bounding sphere. This is useful when most precision
86 // is required in pixel and depth resolution (for example, shadow-maps).
87 // The resulting camera is not skewed!
88 //----------------------------------------------------------------------------
89 void Camera::TightlyFitToSphere(
90 const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad)
92 // FIRST DEFINE COORDINATE FRAME
93 LookAt(Eye,Cntr,ViewUp);
95 // PROJECTED DIST TO CNTR ALONG VIEWDIR
96 float DistToCntr = (Cntr-Orig) * ViewDir();
98 // CALC TIGHT-FITTING NEAR AND FAR PLANES
99 Near = DistToCntr-Rad;
100 Far = DistToCntr+Rad;
102 //x = n*R / sqrt(d2 - r2)
104 if (Near<=0 || Far<=0)
105 printf("ERROR (Camera::TightlyFitToSphere) Eye is inside the sphere!\n");
107 // CALC TIGHT-FITTING SIDES
108 wT = (Near * Rad) / (float)sqrt(DistToCntr*DistToCntr - Rad*Rad);//(Near * Rad) / DistToCntr;
114 //----------------------------------------------------------------------------
115 // Routines to return the Lookat, Perspective, and Frustum params.
116 // NOTE: Perspective is designed for non-skewed cameras: the viewing
117 // direction must be centered on the viewplane window. Use frustum
118 // for off-axis cameras.
119 //----------------------------------------------------------------------------
120 void Camera::GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const
123 *ViewRefPt = Orig - Z;
127 void Camera::GetPerspectiveParams(float *Yfov, float *Aspect,
128 float *Ndist, float *Fdist) const
130 *Yfov = (float)atan(wT/Near) * 57.29578f * 2.0f; // CONVERT TO DEGREES
136 void Camera::GetFrustumParams(float *l, float *r, float *b, float *t,
137 float *Ndist, float *Fdist) const
147 //----------------------------------------------------------------------------
148 // RETURNS THE COP OR EYE IN WORLD COORDS (ORIG OF CAMERA SYSTEM)
149 //----------------------------------------------------------------------------
150 const Vec3f& Camera::wCOP() const
155 //----------------------------------------------------------------------------
156 // RETURNS THE VIEWING DIRECTION
157 //----------------------------------------------------------------------------
158 Vec3f Camera::ViewDir() const
163 Vec3f Camera::ViewDirOffAxis() const
165 float x=(wL+wR)*0.5f, y=(wT+wB)*0.5f; // MIDPOINT ON VIEWPLANE WINDOW
166 Vec3f ViewDir = X*x + Y*y - Z*Near;
171 //----------------------------------------------------------------------------
172 // Vec3f WORLD-TO-CAM AND CAM-TO-WORLD ROUTINES
173 //----------------------------------------------------------------------------
174 Vec3f Camera::WorldToCam(const Vec3f& wP) const
177 Vec3f cP(X*sP,Y*sP,Z*sP); return(cP);
180 // Return the z-value of the world point in camera space
181 float Camera::WorldToCamZ(const Vec3f& wP) const
189 Vec3f Camera::CamToWorld(const Vec3f& cP) const
191 Vec3f wP(X*cP.x + Y*cP.y + Z*cP.z + Orig); return(wP);
194 //----------------------------------------------------------------------------
195 // Makes the camera pose be the identity. World and camera space will be the
196 // same. Window extents and near/far planes are unaffected.
197 //----------------------------------------------------------------------------
198 void Camera::LoadIdentityXform()
206 //----------------------------------------------------------------------------
207 // Applies an OpenGL style premult/col vector xform to the coordinate frame.
208 // Only rotates, translates, and uniform scales are allowed.
209 // Window extents and near/far planes are affected by scaling.
210 //----------------------------------------------------------------------------
211 void Camera::Xform(const float M[16])
213 X.Set( X.x*M[0] + X.y*M[4] + X.z*M[8],
214 X.x*M[1] + X.y*M[5] + X.z*M[9],
215 X.x*M[2] + X.y*M[6] + X.z*M[10] );
216 Y.Set( Y.x*M[0] + Y.y*M[4] + Y.z*M[8],
217 Y.x*M[1] + Y.y*M[5] + Y.z*M[9],
218 Y.x*M[2] + Y.y*M[6] + Y.z*M[10] );
219 Z.Set( Z.x*M[0] + Z.y*M[4] + Z.z*M[8],
220 Z.x*M[1] + Z.y*M[5] + Z.z*M[9],
221 Z.x*M[2] + Z.y*M[6] + Z.z*M[10] );
222 Orig.Set( Orig.x*M[0] + Orig.y*M[4] + Orig.z*M[8] + M[12],
223 Orig.x*M[1] + Orig.y*M[5] + Orig.z*M[9] + M[13],
224 Orig.x*M[2] + Orig.y*M[6] + Orig.z*M[10] + M[14] );
226 // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
227 float Scale = X.Length();
232 // SCALE THE WINDOW EXTENTS AND THE NEAR/FAR PLANES
242 //----------------------------------------------------------------------------
243 // Translates the camera by the vector amount trans.
244 //----------------------------------------------------------------------------
245 void Camera::Translate(const Vec3f& trans)
251 //----------------------------------------------------------------------------
252 // Translates the camera about its origin by the rotation matrix M.
253 //----------------------------------------------------------------------------
254 void Camera::Rotate(const float M[9])
256 X.Set( X.x*M[0] + X.y*M[3] + X.z*M[6],
257 X.x*M[1] + X.y*M[4] + X.z*M[7],
258 X.x*M[2] + X.y*M[5] + X.z*M[8] );
259 Y.Set( Y.x*M[0] + Y.y*M[3] + Y.z*M[6],
260 Y.x*M[1] + Y.y*M[4] + Y.z*M[7],
261 Y.x*M[2] + Y.y*M[5] + Y.z*M[8] );
262 Z.Set( Z.x*M[0] + Z.y*M[3] + Z.z*M[6],
263 Z.x*M[1] + Z.y*M[4] + Z.z*M[7],
264 Z.x*M[2] + Z.y*M[5] + Z.z*M[8] );
268 //----------------------------------------------------------------------------
269 // Returns the COMPOSITE xform matrix that takes a point in the object space
270 // to a screen space (pixel) point. The inverse is also provided.
271 // You have to give the pixel dimensions of the viewport window.
272 //----------------------------------------------------------------------------
273 float* Camera::GetXform_Screen2Obj(float* M, int WW, int WH) const
275 Screen2WorldXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
276 wL,wR,wB,wT,Near,Far,WW,WH);
280 float* Camera::GetXform_Obj2Screen(float* M, int WW, int WH) const
282 World2ScreenXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
283 wL,wR,wB,wT,Near,Far,WW,WH);
287 //----------------------------------------------------------------------------
288 // OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/COL VECT, 4x4 MATRIX)
289 // A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
290 // VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
291 // WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
292 // Modelview XFORM. The associated inverse matrices are also provided.
293 //----------------------------------------------------------------------------
294 float* Camera::GetModelviewMatrix(float* M) const
296 Viewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
300 float* Camera::GetInvModelviewMatrix(float* M) const
302 invViewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
306 float* Camera::GetProjectionMatrix(float* M) const
308 Frustum16fv(M,wL,wR,wB,wT,Near,Far);
312 void Camera::SetModelviewMatrix(const float* M)
314 Viewing2CoordFrame16fv(M, &(X.x), &(Y.x), &(Z.x), &(Orig.x));
317 float* Camera::GetInvProjectionMatrix(float* M) const
319 invFrustum16fv(M,wL,wR,wB,wT,Near,Far);
323 float* Camera::GetViewportMatrix(float* M, int WW, int WH) const
325 Viewport16fv(M,WW,WH);
329 float* Camera::GetInvViewportMatrix(float* M, int WW, int WH) const
331 invViewport16fv(M,WW,WH);
335 //----------------------------------------------------------------------------
336 // Given a screen pixel location (sx,sy) w/ (0,0) at the lower-left and the
337 // screen dimensions, return the ray (start,dir) of the ray in world coords.
338 //----------------------------------------------------------------------------
339 void Camera::GetPixelRay(float sx, float sy, int ww, int wh,
340 Vec3f *Start, Vec3f *Dir) const
342 Vec3f wTL = Orig + (X*wL) + (Y*wT) - (Z*Near); // FIND LOWER-LEFT
343 Vec3f dX = (X*(wR-wL))/(float)ww; // WORLD WIDTH OF PIXEL
344 Vec3f dY = (Y*(wT-wB))/(float)wh; // WORLD HEIGHT OF PIXEL
345 wTL += (dX*sx - dY*sy); // INCR TO WORLD PIXEL
346 wTL += (dX*0.5 - dY*0.5); // INCR TO PIXEL CNTR
351 //----------------------------------------------------------------------------
352 // READ AND WRITE CAMERA AXES AND ORIGIN TO AND FROM A FILE GIVEN A FILE PTR.
353 //----------------------------------------------------------------------------
354 void Camera::WriteToFile(FILE *fp) const
356 if (fp==NULL) { printf("ERROR WRITING CAM TO FILE!\n"); return; }
357 fprintf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f\n",
358 X.x,X.y,X.z, Y.x,Y.y,Y.z, Z.x,Z.y,Z.z, Orig.x,Orig.y,Orig.z);
361 int Camera::ReadFromFile(FILE *fp) // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
363 int Cond = fscanf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f",
364 &X.x,&X.y,&X.z, &Y.x,&Y.y,&Y.z,
365 &Z.x,&Z.y,&Z.z, &Orig.x,&Orig.y,&Orig.z);
369 //----------------------------------------------------------------------------
370 // 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
371 // (Left,Right, Bottom,Top, Near,Far)
372 // In order, near pts counter-clockwise starting with right-top-near (RTN) pt
373 // and then far pts ccw starting with right-top-far (RTF) pt
374 //----------------------------------------------------------------------------
375 void Camera::CalcVerts(Vec3f *V) const // MUST BE PREALLOCED : "Vec3f V[8]"
377 // WINDOW EXTENTS ARE DEFINED ON THE NEAR PLANE, CALC NEAR PTS (IN CAM COORDS)
379 V[0].Set(wR,wT,NearZ);
380 V[1].Set(wL,wT,NearZ);
381 V[2].Set(wL,wB,NearZ);
382 V[3].Set(wR,wB,NearZ);
384 // CALC FAR PTS (IN CAM COORDS)
385 float FarZ=-Far, FN=Far/Near;
386 float fwL=wL*FN, fwR=wR*FN, fwB=wB*FN, fwT=wT*FN;
387 V[4].Set(fwR,fwT,FarZ);
388 V[5].Set(fwL,fwT,FarZ);
389 V[6].Set(fwL,fwB,FarZ);
390 V[7].Set(fwR,fwB,FarZ);
392 // XFORM FRUSTUM IN CAM COORDS TO WORLD SPACE
393 for (int i=0; i<8; i++)
394 V[i] = CamToWorld(V[i]);
397 //----------------------------------------------------------------------------
399 //----------------------------------------------------------------------------
400 void Camera::Print() const
402 printf("Camera System Parameters:\n");
403 printf(" X: (%.3f, %.3f, %.3f)\n", X.x, X.y, X.z);
404 printf(" Y: (%.3f, %.3f, %.3f)\n", Y.x, Y.y, Y.z);
405 printf(" Z: (%.3f, %.3f, %.3f)\n", Z.x, Z.y, Z.z);
406 printf(" Origin: (%.3f, %.3f, %.3f)\n", Orig.x, Orig.y, Orig.z);
407 printf(" NFLRBT: (%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
408 Near,Far,wL,wR,wB,wT);