00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef __SGL_FRUSTUM_HPP
00026 #define __SGL_FRUSTUM_HPP
00027
00028 #include <sgl.h>
00029 #include <sglPolytope.hpp>
00030
00031
00032
00033
00034
00035 template <class T> class sglFrustum;
00036
00037 typedef sglFrustum<float> sglFrustumf;
00038 typedef sglFrustum<double> sglFrustumd;
00039
00040
00041
00051 template <class T>
00052 class sglFrustum : public sglPolytope<T>
00053 {
00054 public:
00056 enum { eLEFT = 0, eUP = 1, eRIGHT = 2, eDOWN = 3, eFRONT = 4, eBACK = 5,
00057 eNUM_PLANES = 6};
00058
00059 public:
00061 sglFrustum() : sglPolytope<T>(), m_ortho_flag(true), m_fov_y((T)-1) {}
00062
00064 template <class S>
00065 sglFrustum(const sglFrustum<S> &rhs)
00066 : sglPolytope<T>(rhs),
00067 m_ortho_flag(rhs.getOrthoFlag()),
00068 m_fov_y((T)rhs.getFOVY())
00069 {}
00070
00072 virtual ~sglFrustum() {}
00073
00075 template <class S>
00076 sglFrustum &operator=(const sglFrustum<S> &rhs)
00077 {
00078 if (this != (sglPolytope<T>*)&rhs)
00079 {
00080 sglPolytope<T>::operator=(rhs);
00081 m_ortho_flag = rhs.getOrthoFlag();
00082 m_fov_y = rhs.getFOVY();
00083 }
00084 return *this;
00085 }
00086
00090 bool getOrthoFlag() const { return m_ortho_flag; }
00091
00095 double getAspect() const { return m_aspect; }
00096
00101 double getFOVY() const { return m_fov_y; }
00102
00103
00110 bool build(sglMat4<T>& projection_matrix);
00111
00118 bool buildPerspective(double fovY,
00119 double aspect,
00120 double near_clip, double far_clip);
00121
00132 bool buildPerspective(double near_left, double near_right,
00133 double near_bottom, double near_top,
00134 double near_clip, double far_clip);
00135
00144 bool buildOrtho(double left, double right, double bottom, double top,
00145 double near_clip, double far_clip);
00146
00147 #ifdef SGL_FRUSTUM_DEBUG
00148
00149 void drawImmediate() const;
00150
00151 private:
00152 sglVec3f m_vertices[8];
00153
00154
00155
00156
00157 #endif
00158
00159 private:
00160 bool buildPerspectiveInternal(double near_left, double near_right,
00161 double near_bottom, double near_top,
00162 double near_clip, double far_clip);
00163
00164 private:
00165 bool m_ortho_flag;
00166 double m_aspect;
00167 double m_fov_y;
00168 };
00169
00170
00171 template <class T>
00172 inline bool sglFrustum<T>::build(sglMat4<T>& projectionMatrix)
00173 {
00174
00175 m_num_planes = 0;
00176
00177 sglVec3<T> p1, p2, p3;
00178 sglVec4<T> r1, r2, r3;
00179
00180 sglMat4<T> inv;
00181 inv.inverse(projectionMatrix);
00182
00183 for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00184 {
00185 switch(i)
00186 {
00187 case sglFrustum::eLEFT:
00188 p1.set(-1.f, 1.f, 1.f);
00189 p2.set(-1.f, -1.f, 1.f);
00190 p3.set(-1.f, -1.f, -1.f);
00191 break;
00192 case sglFrustum::eUP:
00193 p1.set(-1.f, 1.f, 1.f);
00194 p2.set(-1.f, 1.f, -1.f);
00195 p3.set( 1.f, 1.f, -1.f);
00196 break;
00197 case sglFrustum::eRIGHT:
00198 p1.set( 1.f, 1.f, -1.f);
00199 p2.set( 1.f, -1.f, -1.f);
00200 p3.set( 1.f, -1.f, 1.f);
00201 break;
00202 case sglFrustum::eDOWN:
00203 p1.set(-1.f, -1.f, -1.f);
00204 p2.set(-1.f, -1.f, 1.f);
00205 p3.set( 1.f, -1.f, 1.f);
00206 break;
00207 case sglFrustum::eFRONT:
00208 p1.set(-1.f, 1.f, -1.f);
00209 p2.set(-1.f, -1.f, -1.f);
00210 p3.set( 1.f, -1.f, -1.f);
00211 break;
00212 case sglFrustum::eBACK:
00213 p1.set( 1.f, 1.f, 1.f);
00214 p2.set( 1.f, -1.f, 1.f);
00215 p3.set(-1.f, -1.f, 1.f);
00216 break;
00217 }
00218
00219 ::mul(p1,(T)1.0,inv, r1);
00220 ::mul(p2,(T)1.0,inv, r2);
00221 ::mul(p3,(T)1.0,inv, r3);
00222
00223 if (r1[3] == 0.0 || r2[3] == 0.0 || r3[3] == 0.0)
00224 {
00225 return false;
00226 }
00227
00228 r1 *= (1.0/r1[3]);
00229 r2 *= (1.0/r2[3]);
00230 r3 *= (1.0/r3[3]);
00231
00232 p1.set(r1[0],r1[1],r1[2]);
00233 p2.set(r2[0],r2[1],r2[2]);
00234 p3.set(r3[0],r3[1],r3[2]);
00235
00236 if (!m_plane[i].build(p1,p2,p3))
00237 {
00238 return false;
00239 }
00240 }
00241
00242 #ifdef SGL_FRUSTUM_DEBUG
00243
00244
00245
00246
00247
00248 m_vertices[0].set(-1.f,-1.f,-1.f);
00249 m_vertices[1].set( 1.f,-1.f,-1.f);
00250 m_vertices[2].set( 1.f, 1.f,-1.f);
00251 m_vertices[3].set(-1.f, 1.f,-1.f);
00252
00253 m_vertices[4].set(-1.f,-1.f, 1.f);
00254 m_vertices[5].set( 1.f,-1.f, 1.f);
00255 m_vertices[6].set( 1.f, 1.f, 1.f);
00256 m_vertices[7].set(-1.f, 1.f, 1.f);
00257
00258 sglVec4f vertices[8];
00259 for (unsigned int ix=0; ix<8; ix++)
00260 {
00261 ::mul(m_vertices[ix], (T)1.0, inv, vertices[ix]);
00262 vertices[ix] *= (1.0/vertices[ix][3]);
00263 m_vertices[ix].set(vertices[ix][0], vertices[ix][1], vertices[ix][2]);
00264 }
00265 #endif
00266
00267 m_num_planes = 6;
00268 return true;
00269 }
00270
00271
00272
00273 template <class T>
00274 inline bool sglFrustum<T>::buildPerspective(double near_left,
00275 double near_right,
00276 double near_bottom,
00277 double near_top,
00278 double near_clip, double far_clip)
00279 {
00280 if (near_clip <= 0.0)
00281 {
00282 return false;
00283 }
00284
00285 m_ortho_flag = false;
00286 m_aspect = (near_right - near_left)/(near_top - near_bottom);
00287 m_fov_y = atan2(near_top, near_clip) - atan2(near_bottom, near_clip);
00288
00289 return buildPerspectiveInternal(near_left, near_right,
00290 near_bottom, near_top,
00291 near_clip, far_clip);
00292 }
00293
00294
00295
00296 template <class T>
00297 inline bool sglFrustum<T>::buildPerspective(double fovy, double aspect,
00298 double near_clip, double far_clip)
00299 {
00300 m_ortho_flag = false;
00301 m_aspect = aspect;
00302 m_fov_y = fovy;
00303
00304
00305
00306 GLdouble near_top, near_bottom, near_left, near_right;
00307
00308 near_top = near_clip * tan( fovy * 0.5 );
00309 near_bottom = -near_top;
00310
00311 near_left = near_bottom * aspect;
00312 near_right = near_top * aspect;
00313
00314
00315 return buildPerspectiveInternal(near_left, near_right,
00316 near_bottom, near_top,
00317 near_clip, far_clip);
00318 }
00319
00320
00321 template <class T>
00322 inline bool sglFrustum<T>::buildPerspectiveInternal(double near_left,
00323 double near_right,
00324 double near_bottom,
00325 double near_top,
00326 double near_clip,
00327 double far_clip)
00328 {
00329
00330 m_num_planes = 0;
00331
00332 sglVec3<T> p1, p2, p3;
00333 GLdouble far_top, far_bottom, far_left, far_right;
00334 GLdouble factor = far_clip/near_clip;
00335
00336 far_top = near_top*factor;
00337 far_bottom = near_bottom*factor;
00338
00339 far_left = near_left*factor;
00340 far_right = near_right*factor;
00341
00342 for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00343 {
00344 switch(i)
00345 {
00346 case sglFrustum::eLEFT:
00347 p1.set(far_left, far_top, -far_clip);
00348 p2.set(far_left, far_bottom, -far_clip);
00349 p3.set(near_left, near_bottom, -near_clip);
00350 break;
00351 case sglFrustum::eUP:
00352 p1.set(far_left, far_top, -far_clip);
00353 p2.set(near_left, near_top, -near_clip);
00354 p3.set(near_right, near_top, -near_clip);
00355 break;
00356 case sglFrustum::eRIGHT:
00357 p1.set(near_right, near_top, -near_clip);
00358 p2.set(near_right, near_bottom, -near_clip);
00359 p3.set(far_right, far_bottom, -far_clip);
00360 break;
00361 case sglFrustum::eDOWN:
00362 p1.set(near_left, near_bottom, -near_clip);
00363 p2.set(far_left, far_bottom, -far_clip);
00364 p3.set(far_right, far_bottom, -far_clip);
00365 break;
00366 case sglFrustum::eFRONT:
00367 p1.set(near_left, near_top, -near_clip);
00368 p2.set(near_left, near_bottom, -near_clip);
00369 p3.set(near_right, near_bottom, -near_clip);
00370 break;
00371 case sglFrustum::eBACK:
00372 p1.set(far_right, far_top, -far_clip);
00373 p2.set(far_right, far_bottom, -far_clip);
00374 p3.set(far_left, far_bottom, -far_clip);
00375 break;
00376 }
00377
00378 if (!m_plane[i].build(p1,p2,p3))
00379 {
00380 return false;
00381 }
00382 }
00383
00384 #ifdef SGL_FRUSTUM_DEBUG
00385
00386
00387
00388
00389
00390 m_vertices[0].set(near_left, near_bottom, -near_clip);
00391 m_vertices[1].set(near_right, near_bottom, -near_clip);
00392 m_vertices[2].set(near_right, near_top, -near_clip);
00393 m_vertices[3].set(near_left, near_top, -near_clip);
00394
00395 m_vertices[4].set(far_left, far_bottom, -far_clip);;
00396 m_vertices[5].set(far_right, far_bottom, -far_clip);
00397 m_vertices[6].set(far_right, far_top, -far_clip);
00398 m_vertices[7].set(far_left, far_top, -far_clip);
00399 #endif
00400
00401 m_num_planes = 6;
00402 return true;
00403 }
00404
00405
00406 template <class T>
00407 inline bool sglFrustum<T>::buildOrtho(double left, double right,
00408 double bottom, double top,
00409 double near_clip, double far_clip)
00410 {
00411
00412 m_num_planes = 0;
00413
00414 m_ortho_flag = true;
00415 m_aspect = (right - left)/(top - bottom);
00416 m_fov_y = -1.0;
00417
00418 sglVec3<T> p1, p2, p3;
00419
00420 for (int i=0; i<sglFrustumf::eNUM_PLANES; i++)
00421 {
00422 switch(i)
00423 {
00424 case sglFrustum::eLEFT:
00425 p1.set(left, top, -far_clip);
00426 p2.set(left, bottom, -far_clip);
00427 p3.set(left, bottom, -near_clip);
00428 break;
00429 case sglFrustum::eUP:
00430 p1.set(left, top, -far_clip);
00431 p2.set(left, top, -near_clip);
00432 p3.set(right, top, -near_clip);
00433 break;
00434 case sglFrustum::eRIGHT:
00435 p1.set(right, top, -near_clip);
00436 p2.set(right, bottom, -near_clip);
00437 p3.set(right, bottom, -far_clip);
00438 break;
00439 case sglFrustum::eDOWN:
00440 p1.set(left, bottom, -near_clip);
00441 p2.set(left, bottom, -far_clip);
00442 p3.set(right, bottom, -far_clip);
00443 break;
00444 case sglFrustum::eFRONT:
00445 p1.set(left, top, -near_clip);
00446 p2.set(left, bottom, -near_clip);
00447 p3.set(right, bottom, -near_clip);
00448 break;
00449 case sglFrustum::eBACK:
00450 p1.set(right, top, -far_clip);
00451 p2.set(right, bottom, -far_clip);
00452 p3.set(left, bottom, -far_clip);
00453 break;
00454 }
00455
00456 if (!m_plane[i].build(p1,p2,p3))
00457 {
00458 return false;
00459 }
00460 }
00461
00462 #ifdef SGL_FRUSTUM_DEBUG
00463
00464
00465
00466
00467
00468 m_vertices[0].set(left, bottom, -near_clip);;
00469 m_vertices[1].set(right, bottom, -near_clip);
00470 m_vertices[2].set(right, top, -near_clip);
00471 m_vertices[3].set(left, top, -near_clip);
00472
00473 m_vertices[4].set(left, bottom, -far_clip);;
00474 m_vertices[5].set(right, bottom, -far_clip);
00475 m_vertices[6].set(right, top, -far_clip);
00476 m_vertices[7].set(left, top, -far_clip);
00477 #endif
00478
00479 m_num_planes = 6;
00480 return true;
00481 }
00482
00483 #ifdef SGL_FRUSTUM_DEBUG
00484
00485 template <class T>
00486 inline void sglFrustum<T>::drawImmediate() const
00487 {
00488
00489
00490
00491
00492 glColor3f(1.f, 1.f, 1.f);
00493
00494 glBegin(GL_LINE_STRIP);
00495 glVertex3f(m_vertices[0][0], m_vertices[0][1], m_vertices[0][2]);
00496 glVertex3f(m_vertices[1][0], m_vertices[1][1], m_vertices[1][2]);
00497 glVertex3f(m_vertices[2][0], m_vertices[2][1], m_vertices[2][2]);
00498 glVertex3f(m_vertices[3][0], m_vertices[3][1], m_vertices[3][2]);
00499 glVertex3f(m_vertices[0][0], m_vertices[0][1], m_vertices[0][2]);
00500 glVertex3f(m_vertices[4][0], m_vertices[4][1], m_vertices[4][2]);
00501 glVertex3f(m_vertices[5][0], m_vertices[5][1], m_vertices[5][2]);
00502 glVertex3f(m_vertices[6][0], m_vertices[6][1], m_vertices[6][2]);
00503 glVertex3f(m_vertices[7][0], m_vertices[7][1], m_vertices[7][2]);
00504 glVertex3f(m_vertices[4][0], m_vertices[4][1], m_vertices[4][2]);
00505 glEnd();
00506
00507 glBegin(GL_LINES);
00508 glVertex3f(m_vertices[1][0], m_vertices[1][1], m_vertices[1][2]);
00509 glVertex3f(m_vertices[5][0], m_vertices[5][1], m_vertices[5][2]);
00510 glVertex3f(m_vertices[2][0], m_vertices[2][1], m_vertices[2][2]);
00511 glVertex3f(m_vertices[6][0], m_vertices[6][1], m_vertices[6][2]);
00512 glVertex3f(m_vertices[3][0], m_vertices[3][1], m_vertices[3][2]);
00513 glVertex3f(m_vertices[7][0], m_vertices[7][1], m_vertices[7][2]);
00514 glEnd();
00515 }
00516 #endif // SGL_FRUSTUM_DEBUG
00517
00518 #endif