frustum.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00013 #ifndef frustum_h
00014 #define frustum_h
00015 
00016 #include <cml/mathlib/matrix_concat.h>
00017 #include <cml/mathlib/checking.h>
00018 
00019 namespace cml {
00020 
00021 /* @todo: plane class, and perhaps named arguments instead of an array. */
00022 
00023 /* Extract the planes of a frustum given a modelview matrix and a projection
00024  * matrix with the given near z-clipping range. The planes are normalized by
00025  * default, but this can be turned off with the 'normalize' argument.
00026  *
00027  * The planes are in ax+by+cz+d = 0 form, and are in the order:
00028  *     left
00029  *     right
00030  *     bottom
00031  *     top
00032  *     near
00033  *     far
00034  */
00035 
00036 template < class MatT, typename Real > void
00037 extract_frustum_planes(
00038     const MatT& modelview,
00039     const MatT& projection,
00040     Real planes[6][4],
00041     ZClip z_clip,
00042     bool normalize = true)
00043 {
00044     extract_frustum_planes(
00045         detail::matrix_concat_transforms_4x4(modelview,projection),
00046         planes,
00047         z_clip,
00048         normalize
00049     );
00050 }
00051 
00052 /* Extract the planes of a frustum from a single matrix assumed to contain any
00053  * model and view transforms followed by a projection transform with the given
00054  * near z-cliping range. The planes are normalized by default, but this can be
00055  * turned off with the 'normalize' argument.
00056  *
00057  * The planes are in ax+by+cz+d = 0 form, and are in the order:
00058  *     left
00059  *     right
00060  *     bottom
00061  *     top
00062  *     near
00063  *     far
00064  */
00065 
00066 template < class MatT, typename Real > void
00067 extract_frustum_planes(
00068     const MatT& m,
00069     Real planes[6][4],
00070     ZClip z_clip,
00071     bool normalize = true)
00072 {
00073     detail::CheckMatHomogeneous3D(m);
00074 
00075     /* Left:   [03+00, 13+10, 23+20, 33+30] */
00076     
00077     planes[0][0] = m.basis_element(0,3) + m.basis_element(0,0);
00078     planes[0][1] = m.basis_element(1,3) + m.basis_element(1,0);
00079     planes[0][2] = m.basis_element(2,3) + m.basis_element(2,0);  
00080     planes[0][3] = m.basis_element(3,3) + m.basis_element(3,0);
00081     
00082     /* Right:  [03-00, 13-10, 23-20, 33-30] */
00083     
00084     planes[1][0] = m.basis_element(0,3) - m.basis_element(0,0);
00085     planes[1][1] = m.basis_element(1,3) - m.basis_element(1,0);
00086     planes[1][2] = m.basis_element(2,3) - m.basis_element(2,0);  
00087     planes[1][3] = m.basis_element(3,3) - m.basis_element(3,0);
00088     
00089     /* Bottom: [03+01, 13+11, 23+21, 33+31] */
00090     
00091     planes[2][0] = m.basis_element(0,3) + m.basis_element(0,1);
00092     planes[2][1] = m.basis_element(1,3) + m.basis_element(1,1);
00093     planes[2][2] = m.basis_element(2,3) + m.basis_element(2,1);  
00094     planes[2][3] = m.basis_element(3,3) + m.basis_element(3,1);
00095     
00096     /* Top:    [03-01, 13-11, 23-21, 33-31] */
00097     
00098     planes[3][0] = m.basis_element(0,3) - m.basis_element(0,1);
00099     planes[3][1] = m.basis_element(1,3) - m.basis_element(1,1);
00100     planes[3][2] = m.basis_element(2,3) - m.basis_element(2,1);  
00101     planes[3][3] = m.basis_element(3,3) - m.basis_element(3,1);
00102     
00103     /* Far:    [03-02, 13-12, 23-22, 33-32] */
00104     
00105     planes[5][0] = m.basis_element(0,3) - m.basis_element(0,2);
00106     planes[5][1] = m.basis_element(1,3) - m.basis_element(1,2);
00107     planes[5][2] = m.basis_element(2,3) - m.basis_element(2,2);  
00108     planes[5][3] = m.basis_element(3,3) - m.basis_element(3,2);
00109     
00110     /* Near:   [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */
00111     extract_near_frustum_plane(m, planes[4], z_clip);
00112 
00113     /* @todo: This will be handled by the plane class */
00114     if (normalize) {
00115         for (size_t i = 0; i < 6; ++i) {
00116             Real invl = inv_sqrt(planes[i][0] * planes[i][0] +
00117                                  planes[i][1] * planes[i][1] +
00118                                  planes[i][2] * planes[i][2]);
00119                                 
00120             planes[i][0] *= invl;
00121             planes[i][1] *= invl;
00122             planes[i][2] *= invl;
00123             planes[i][3] *= invl;
00124         }
00125     }
00126 }
00127 
00137 template < class MatT, class PlaneT > void
00138 extract_near_frustum_plane(
00139     const MatT& m,
00140     PlaneT& plane,
00141     ZClip z_clip
00142     )
00143 {
00144     /* Near:   [03+02, 13+12, 23+22, 33+32] : [02, 12, 22, 32] */
00145     if (z_clip == z_clip_neg_one) {       
00146         plane[0] = m.basis_element(0,3) + m.basis_element(0,2);
00147         plane[1] = m.basis_element(1,3) + m.basis_element(1,2);
00148         plane[2] = m.basis_element(2,3) + m.basis_element(2,2);  
00149         plane[3] = m.basis_element(3,3) + m.basis_element(3,2);
00150     } else { // z_clip == z_clip_zero
00151         plane[0] = m.basis_element(0,2);
00152         plane[1] = m.basis_element(1,2);
00153         plane[2] = m.basis_element(2,2);  
00154         plane[3] = m.basis_element(3,2);
00155     }
00156 }
00157 
00158 namespace detail {
00159 
00160 /* This is currently only in support of finding the corners of a frustum.
00161  * The input planes are assumed to have a single unique intersection, so
00162  * no tolerance is used.
00163  */
00164 
00165 template < typename Real > vector< Real, fixed<3> >
00166 intersect_planes(Real p1[4], Real p2[4], Real p3[4])
00167 {
00168     typedef vector< Real, fixed<3> > vector_type;
00169     typedef typename vector_type::value_type value_type;
00170 
00171     vector_type n1(p1[0],p1[1],p1[2]);
00172     vector_type n2(p2[0],p2[1],p2[2]);
00173     vector_type n3(p3[0],p3[1],p3[2]);
00174     
00175     value_type d1 = -p1[3];
00176     value_type d2 = -p2[3];
00177     value_type d3 = -p3[3];
00178     
00179     vector_type numer =
00180         d1*cross(n2,n3) + d2*cross(n3,n1) + d3*cross(n1,n2);
00181     value_type denom = triple_product(n1,n2,n3);
00182     return numer/denom;
00183 }
00184 
00185 } // namespace detail
00186 
00187 /* Get the corners of a frustum defined by 6 planes. The planes are in
00188  * ax+by+cz+d = 0 form, and are in the order:
00189  *     left
00190  *     right
00191  *     bottom
00192  *     top
00193  *     near
00194  *     far
00195  *
00196  * The corners are in CCW order starting in the lower-left, first at the near
00197  * plane, then at the far plane.
00198  */
00199 
00200 template < typename Real, typename E, class A > void
00201 get_frustum_corners(Real planes[6][4], vector<E,A> corners[8])
00202 {
00203     // NOTE: Prefixed with 'PLANE_' due to symbol conflict with Windows
00204     // macros PLANE_LEFT and PLANE_RIGHT.
00205     enum {
00206         PLANE_LEFT,
00207         PLANE_RIGHT,
00208         PLANE_BOTTOM,
00209         PLANE_TOP,
00210         PLANE_NEAR,
00211         PLANE_FAR
00212     };
00213 
00214     corners[0] = detail::intersect_planes(
00215         planes[PLANE_LEFT],
00216         planes[PLANE_BOTTOM],
00217         planes[PLANE_NEAR]
00218     );
00219     corners[1] = detail::intersect_planes(
00220         planes[PLANE_RIGHT],
00221         planes[PLANE_BOTTOM],
00222         planes[PLANE_NEAR]
00223     );
00224     corners[2] = detail::intersect_planes(
00225         planes[PLANE_RIGHT],
00226         planes[PLANE_TOP],
00227         planes[PLANE_NEAR]
00228     );
00229     corners[3] = detail::intersect_planes(
00230         planes[PLANE_LEFT],
00231         planes[PLANE_TOP],
00232         planes[PLANE_NEAR]
00233     );
00234     corners[4] = detail::intersect_planes(
00235         planes[PLANE_LEFT],
00236         planes[PLANE_BOTTOM],
00237         planes[PLANE_FAR]
00238     );
00239     corners[5] = detail::intersect_planes(
00240         planes[PLANE_RIGHT],
00241         planes[PLANE_BOTTOM],
00242         planes[PLANE_FAR]
00243     );
00244     corners[6] = detail::intersect_planes(
00245         planes[PLANE_RIGHT],
00246         planes[PLANE_TOP],
00247         planes[PLANE_FAR]
00248     );
00249     corners[7] = detail::intersect_planes(
00250         planes[PLANE_LEFT],
00251         planes[PLANE_TOP],
00252         planes[PLANE_FAR]
00253     );
00254 }
00255 
00256 } // namespace cml
00257 
00258 #endif

Generated on Sat Jul 18 19:35:21 2009 for CML 1.0 by  doxygen 1.5.9