00001
00002
00003
00004
00005
00006
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
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
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
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
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
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
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
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
00111 extract_near_frustum_plane(m, planes[4], z_clip);
00112
00113
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
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 {
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
00161
00162
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 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
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
00204
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 }
00257
00258 #endif