picking.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 picking_h
00014 #define picking_h
00015 
00016 #include <cml/mathlib/projection.h>
00017 
00018 /* Functions for picking with rays, volumes, and drag-enclosed volumes. */
00019 
00020 namespace cml {
00021 
00022 /* Support function for extracting the near and far depth range values from
00023  * a viewport matrix.
00024   */
00025  
00026 namespace detail {
00027 
00028 // NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around windows.h
00029 // 'near' and 'far' macros.
00030 
00031 template < class MatT, typename Real > void
00032 depth_range_from_viewport_matrix(const MatT& viewport, Real& n, Real& f)
00033 {
00034     detail::CheckMatHomogeneous3D(viewport);
00035     
00036     n = viewport.basis_element(3,2);
00037     f = viewport.basis_element(2,2) + n;
00038 }
00039 
00040 } // namespace detail
00041 
00042 /* Make a pick ray given screen coordinates and view, projection, and viewport
00043  * matrices. The origin of the ray lies in the near plane of the frustum; the
00044  * direction vector extends to the far plane if 'normalize' is false, and is
00045  * made unit-length if 'normalize' is true (its default value).
00046  *
00047  * Note that the origin of the ray lies in the near plane rather than
00048  * coinciding with the position of the virtual camera, as the latter gives
00049  * incorrect results when the projection is orthographic.
00050  *
00051  * Note also that the screen y coordinate increases from bottom to top rather
00052  * than top to bottom. If mouse coordinates are returned in window space where
00053  * the y coordinate increases from top to bottom (as is often the case), the
00054  * y value should be recomputed as 'y = <window height> - y' before being
00055  * submitted to this function.
00056  */
00057 
00058 template < class MatT_1, class MatT_2, class MatT_3, typename E, class A >
00059 void make_pick_ray(
00060     E pick_x,
00061     E pick_y,
00062     const MatT_1& view,
00063     const MatT_2& projection,
00064     const MatT_3& viewport,
00065     vector<E,A>& origin,
00066     vector<E,A>& direction,
00067     bool normalize = true)
00068 {
00069     typedef vector<E,A> vector_type;
00070     typedef typename vector_type::value_type value_type;
00071 
00072     // NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around
00073     // windows.h 'near' and 'far' macros.
00074     value_type n, f;
00075     detail::depth_range_from_viewport_matrix(viewport, n, f);
00076 
00077     origin =
00078         unproject_point(
00079             view,projection,viewport,vector_type(pick_x,pick_y,n)
00080         );
00081     direction =
00082         unproject_point(
00083             view,projection,viewport,vector_type(pick_x,pick_y,f)
00084         ) - origin;
00085     if (normalize) {
00086         direction.normalize();
00087     }
00088 }
00089 
00090 /* Make a pick volume given the screen coordinates of the center of the
00091  * picking rect, the width and height of the picking rect, and view and
00092  * projection matrices.
00093  *
00094  * The volume is loaded into the 'planes' array. The planes are of the form
00095  * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far.
00096  *
00097  * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and
00098  * should correspond to the near z-clipping range of the projection matrix
00099  * argument.
00100  *
00101  * The 'normalize' argument indicates whether the output planes should be
00102  * normalized; its default value is 'true'.
00103  *
00104  * Note that the screen y coordinate increases from bottom to top rather
00105  * than top to bottom. If mouse coordinates are returned in window space where
00106  * the y coordinate increases from top to bottom (as is often the case), the
00107  * y value should be recomputed as 'y = <window height> - y' before being
00108  * submitted to this function.
00109  */
00110 
00111 template < class MatT_1, class MatT_2, typename Real >
00112 void make_pick_volume(
00113     Real pick_x,
00114     Real pick_y,
00115     Real pick_width,
00116     Real pick_height,
00117     Real viewport_x,
00118     Real viewport_y,
00119     Real viewport_width,
00120     Real viewport_height,
00121     const MatT_1& view,
00122     const MatT_2& projection,
00123     Real planes[6][4],
00124     ZClip z_clip,
00125     bool normalize = true)
00126 {
00127     // FIXME: Should be promoted type...
00128     typedef matrix<
00129         Real, fixed<4,4>,
00130         typename MatT_1::basis_orient, typename MatT_1::layout >
00131     matrix_type;
00132     
00133     matrix_type pick;
00134     matrix_pick(
00135         pick, pick_x, pick_y, pick_width, pick_height,
00136         viewport_x, viewport_y, viewport_width, viewport_height
00137     );
00138     cml::extract_frustum_planes(
00139         view,detail::matrix_concat_transforms_4x4(projection,pick),
00140         planes,z_clip,normalize);
00141 }
00142 
00143 /* Make a pick volume given two opposite corners of a rectangle in screen
00144  * space, and view and projection matrices. The corners of the screen rect
00145  * need not be in any particular 'order' with regard to the values of the
00146  * coordinates.
00147  *
00148  * The volume is loaded into the 'planes' array. The planes are of the form
00149  * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far.
00150  *
00151  * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and
00152  * should correspond to the near z-clipping range of the projection matrix
00153  * argument.
00154  *
00155  * The 'normalize' argument indicates whether the output planes should be
00156  * normalized; its default value is 'true'.
00157  *
00158  * Note that the screen y coordinate increases from bottom to top rather
00159  * than top to bottom. If mouse coordinates are returned in window space where
00160  * the y coordinate increases from top to bottom (as is often the case), the
00161  * y value should be recomputed as 'y = <window height> - y' before being
00162  * submitted to this function.
00163  */
00164 
00165 template < class MatT_1, class MatT_2, typename Real >
00166 void make_pick_drag_volume(
00167     Real pick_x1,
00168     Real pick_y1,
00169     Real pick_x2,
00170     Real pick_y2,
00171     Real viewport_x,
00172     Real viewport_y,
00173     Real viewport_width,
00174     Real viewport_height,
00175     const MatT_1& view,
00176     const MatT_2& projection,
00177     Real planes[6][4],
00178     ZClip z_clip,
00179     bool normalize = true)
00180 {
00181     typedef Real value_type;
00182 
00183     make_pick_volume(
00184         (pick_x1+pick_x2)*value_type(.5),
00185         (pick_y1+pick_y2)*value_type(.5),
00186         std::fabs(pick_x2-pick_x1),
00187         std::fabs(pick_y2-pick_y1),
00188         viewport_x, viewport_y, viewport_width, viewport_height,
00189         view, projection, planes, z_clip, normalize
00190     );
00191 }
00192 
00193 } // namespace cml
00194 
00195 #endif

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