matrix_projection.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 matrix_projection_h
00014 #define matrix_projection_h
00015 
00016 #include <cml/mathlib/checking.h>
00017 #include <cml/mathlib/helper.h>
00018 
00019 /* Functions for building matrix transforms other than rotations
00020  * (matrix_rotation.h) and viewing projections (matrix_projection.h).
00021  *
00022  * @todo: Clean up comments and documentation throughout.
00023  */
00024 
00025 // NOTE: Changed 'near' and 'far' to 'n' and 'f' throughout to work around
00026 // windows.h 'near' and 'far' macros.
00027 
00028 namespace cml {
00029 
00031 // 3D perspective projection from frustum
00033 
00038 template < typename E, class A, class B, class L > void
00039 matrix_perspective(matrix<E,A,B,L>& m, E left, E right, E bottom, E top,
00040     E n, E f, Handedness handedness,
00041     ZClip z_clip)
00042 {
00043     typedef matrix<E,A,B,L> matrix_type;
00044     typedef typename matrix_type::value_type value_type;
00045 
00046     /* Checking */
00047     detail::CheckMatHomogeneous3D(m);
00048 
00049     identity_transform(m);
00050     
00051     value_type inv_width = value_type(1) / (right - left);
00052     value_type inv_height = value_type(1) / (top - bottom);
00053     value_type inv_depth = value_type(1) / (f - n);
00054     value_type near2 = value_type(2) * n;
00055     value_type s = handedness == left_handed ? 1 : -1;
00056 
00057     if (z_clip == z_clip_neg_one) {
00058         m.set_basis_element(2,2,s * (f + n) * inv_depth);
00059         m.set_basis_element(3,2,value_type(-2) * f * n * inv_depth);
00060     } else { // z_clip == z_clip_zero
00061         m.set_basis_element(2,2,s * f * inv_depth);
00062         m.set_basis_element(3,2,-s * n * m.basis_element(2,2));
00063     }
00064     
00065     m.set_basis_element(0,0,near2 * inv_width               );
00066     m.set_basis_element(1,1,near2 * inv_height              );
00067     m.set_basis_element(2,0,-s * (right + left) * inv_width );
00068     m.set_basis_element(2,1,-s * (top + bottom) * inv_height);
00069     m.set_basis_element(2,3,s                               );
00070     m.set_basis_element(3,3,value_type(0)                   );
00071 }
00072 
00077 template < typename E, class A, class B, class L > void
00078 matrix_perspective(matrix<E,A,B,L>& m, E width, E height, E n, E f,
00079     Handedness handedness, ZClip z_clip)
00080 {
00081     typedef matrix<E,A,B,L> matrix_type;
00082     typedef typename matrix_type::value_type value_type;
00083     
00084     value_type half_width = width * value_type(.5);
00085     value_type half_height = height * value_type(.5);
00086     matrix_perspective(m, -half_width, half_width,
00087         -half_height, half_height, n, f, handedness, z_clip);
00088 }
00089 
00091 template < typename E, class A, class B, class L > void
00092 matrix_perspective_LH(matrix<E,A,B,L>& m, E left, E right, E bottom,
00093     E top, E n, E f, ZClip z_clip)
00094 {
00095     matrix_perspective(m, left, right, bottom, top, n, f,
00096         left_handed, z_clip);
00097 }
00098 
00100 template < typename E, class A, class B, class L > void
00101 matrix_perspective_RH(matrix<E,A,B,L>& m, E left, E right, E bottom,
00102     E top, E n, E f, ZClip z_clip)
00103 {
00104     matrix_perspective(m, left, right, bottom, top, n, f,
00105         right_handed, z_clip);
00106 }
00107 
00109 template < typename E, class A, class B, class L > void
00110 matrix_perspective_LH(matrix<E,A,B,L>& m, E width, E height, E n,
00111     E f, ZClip z_clip)
00112 {
00113     matrix_perspective(m, width, height, n, f, left_handed, z_clip);
00114 }
00115 
00117 template < typename E, class A, class B, class L > void
00118 matrix_perspective_RH(matrix<E,A,B,L>& m, E width, E height, E n,
00119     E f, ZClip z_clip)
00120 {
00121     matrix_perspective(m, width, height, n, f, right_handed, z_clip);
00122 }
00123 
00125 // 3D perspective projection from horizontal field of view
00127 
00129 template < typename E, class A, class B, class L > void
00130 matrix_perspective_xfov(matrix<E,A,B,L>& m, E xfov, E aspect, E n,
00131     E f, Handedness handedness, ZClip z_clip)
00132 {
00133     typedef matrix<E,A,B,L> matrix_type;
00134     typedef typename matrix_type::value_type value_type;
00135     
00136     value_type width = value_type(2) * std::tan(xfov * value_type(.5)) * n;
00137     matrix_perspective(m, width, width / aspect, n, f,
00138         handedness, z_clip);
00139 }
00140 
00142 template < typename E, class A, class B, class L > void
00143 matrix_perspective_xfov_LH(matrix<E,A,B,L>& m, E xfov, E aspect, E n,
00144     E f, ZClip z_clip)
00145 {
00146     matrix_perspective_xfov(m,xfov,aspect,n,f,left_handed,z_clip);
00147 }
00148 
00150 template < typename E, class A, class B, class L > void
00151 matrix_perspective_xfov_RH(matrix<E,A,B,L>& m, E xfov, E aspect, E n,
00152     E f, ZClip z_clip)
00153 {
00154     matrix_perspective_xfov(m,xfov,aspect,n,f,right_handed,z_clip);
00155 }
00156 
00158 // 3D perspective projection from vertical field of view
00160 
00162 template < typename E, class A, class B, class L > void
00163 matrix_perspective_yfov(matrix<E,A,B,L>& m, E yfov, E aspect, E n,
00164     E f, Handedness handedness, ZClip z_clip)
00165 {
00166     typedef matrix<E,A,B,L> matrix_type;
00167     typedef typename matrix_type::value_type value_type;
00168     
00169     value_type height = value_type(2) * std::tan(yfov * value_type(.5)) * n;
00170     matrix_perspective(m, height * aspect, height, n, f,
00171         handedness, z_clip);
00172 }
00173 
00175 template < typename E, class A, class B, class L > void
00176 matrix_perspective_yfov_LH(matrix<E,A,B,L>& m, E yfov, E aspect, E n,
00177     E f, ZClip z_clip)
00178 {
00179     matrix_perspective_yfov(m,yfov,aspect,n,f,left_handed,z_clip);
00180 }
00181 
00183 template < typename E, class A, class B, class L > void
00184 matrix_perspective_yfov_RH(matrix<E,A,B,L>& m, E yfov, E aspect, E n,
00185     E f, ZClip z_clip)
00186 {
00187     matrix_perspective_yfov(m,yfov,aspect,n,f,right_handed,z_clip);
00188 }
00189 
00191 // 3D orthographic projection from frustum
00193 
00199 template < typename E, class A, class B, class L > void
00200 matrix_orthographic(matrix<E,A,B,L>& m, E left, E right, E bottom, E top,
00201     E n, E f, Handedness handedness,
00202     ZClip z_clip)
00203 {
00204     typedef matrix<E,A,B,L> matrix_type;
00205     typedef typename matrix_type::value_type value_type;
00206 
00207     /* Checking */
00208     detail::CheckMatHomogeneous3D(m);
00209 
00210     identity_transform(m);
00211     
00212     value_type inv_width = value_type(1) / (right - left);
00213     value_type inv_height = value_type(1) / (top - bottom);
00214     value_type inv_depth = value_type(1) / (f - n);
00215     value_type s = handedness == left_handed ? 1 : -1;
00216 
00217     if (z_clip == z_clip_neg_one) {
00218         m.set_basis_element(2,2,s * value_type(2) * inv_depth);
00219         m.set_basis_element(3,2,-(f + n) * inv_depth);
00220     } else { // z_clip.z_clip() == 0
00221         m.set_basis_element(2,2,s * inv_depth);
00222         m.set_basis_element(3,2,-n * inv_depth);
00223     }
00224     
00225     m.set_basis_element(0,0,value_type(2) * inv_width   );
00226     m.set_basis_element(1,1,value_type(2) * inv_height  );
00227     m.set_basis_element(3,0,-(right + left) * inv_width );
00228     m.set_basis_element(3,1,-(top + bottom) * inv_height);
00229 }
00230 
00232 template < typename E, class A, class B, class L > void
00233 matrix_orthographic(matrix<E,A,B,L>& m, E width, E height, E n, E f,
00234     Handedness handedness, ZClip z_clip)
00235 {
00236     typedef matrix<E,A,B,L> matrix_type;
00237     typedef typename matrix_type::value_type value_type;
00238     
00239     value_type half_width = width * value_type(.5);
00240     value_type half_height = height * value_type(.5);
00241     matrix_orthographic(m, -half_width, half_width,
00242         -half_height, half_height, n, f, handedness, z_clip);
00243 }
00244 
00246 template < typename E, class A, class B, class L > void
00247 matrix_orthographic_LH(matrix<E,A,B,L>& m, E left, E right, E bottom,
00248     E top, E n, E f, ZClip z_clip)
00249 {
00250     matrix_orthographic(m, left, right, bottom, top, n, f,
00251         left_handed, z_clip);
00252 }
00253 
00255 template < typename E, class A, class B, class L > void
00256 matrix_orthographic_RH(matrix<E,A,B,L>& m, E left, E right, E bottom,
00257     E top, E n, E f, ZClip z_clip)
00258 {
00259     matrix_orthographic(m, left, right, bottom, top, n, f,
00260         right_handed, z_clip);
00261 }
00262 
00264 template < typename E, class A, class B, class L > void
00265 matrix_orthographic_LH(matrix<E,A,B,L>& m, E width, E height, E n,
00266     E f, ZClip z_clip)
00267 {
00268     matrix_orthographic(m, width, height, n, f, left_handed,
00269         z_clip);
00270 }
00271 
00273 template < typename E, class A, class B, class L > void
00274 matrix_orthographic_RH(matrix<E,A,B,L>& m, E width, E height, E n,
00275     E f, ZClip z_clip)
00276 {
00277     matrix_orthographic(m, width, height, n, f, right_handed,
00278         z_clip);
00279 }
00280 
00282 // 3D viewport
00284 
00285 /* Build a viewport matrix
00286  *
00287  * Note: A viewport matrix is in a sense the opposite of an orthographics
00288  * projection matrix, and can be build by constructing and inverting the
00289  * latter.
00290  *
00291  * @todo: Need to look into D3D viewport conventions and see if this needs to
00292  * be adapted accordingly.
00293  */
00294 
00295 template < typename E, class A, class B, class L > void
00296 matrix_viewport(matrix<E,A,B,L>& m, E left, E right, E bottom,
00297     E top, ZClip z_clip, E n = E(0), E f = E(1))
00298 {
00299     matrix_orthographic_LH(m, left, right, bottom, top, n, f, z_clip);
00300     /* @todo: invert(m), when available */
00301     m = inverse(m);
00302 }
00303 
00305 // 3D picking volume
00307 
00308 /* Build a pick volume matrix
00309  *
00310  * When post-concatenated with a projection matrix, the pick matrix modifies
00311  * the view volume to create a 'picking volume'. This volume corresponds to
00312  * a screen rectangle centered at (pick_x, pick_y) and with dimensions
00313  * pick_widthXpick_height.
00314  *
00315  * @todo: Representation of viewport between this function and
00316  * matrix_viewport() is inconsistent (position and dimensions vs. bounds).
00317  * Should this be addressed?
00318  */
00319 
00320 template < typename E, class A, class B, class L > void
00321 matrix_pick(
00322     matrix<E,A,B,L>& m, E pick_x, E pick_y, E pick_width, E pick_height,
00323     E viewport_x, E viewport_y, E viewport_width, E viewport_height)
00324 {
00325     typedef matrix<E,A,B,L> matrix_type;
00326     typedef typename matrix_type::value_type value_type;
00327 
00328     /* Checking */
00329     detail::CheckMatHomogeneous3D(m);
00330 
00331     identity_transform(m);
00332     
00333     value_type inv_width = value_type(1) / pick_width;
00334     value_type inv_height = value_type(1) / pick_height;
00335     
00336     m.set_basis_element(0,0,viewport_width*inv_width);
00337     m.set_basis_element(1,1,viewport_height*inv_height);
00338     m.set_basis_element(3,0,
00339         (viewport_width+value_type(2)*(viewport_x-pick_x))*inv_width);
00340     m.set_basis_element(3,1,
00341         (viewport_height+value_type(2)*(viewport_y-pick_y))*inv_height);
00342 }
00343 
00344 } // namespace cml
00345 
00346 #endif

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