# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlGraphics/Camera.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.com                                               */
    00005 /*                                                                                    */
    00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
    00007 /*  All rights reserved.                                                              */
    00008 /*                                                                                    */
    00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
    00010 /*  are permitted provided that the following conditions are met:                     */
    00011 /*                                                                                    */
    00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
    00013 /*  list of conditions and the following disclaimer.                                  */
    00014 /*                                                                                    */
    00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
    00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
    00017 /*  other materials provided with the distribution.                                   */
    00018 /*                                                                                    */
    00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
    00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
    00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
    00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
    00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
    00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
    00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
    00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
    00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
    00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
    00029 /*                                                                                    */
    00030 /**************************************************************************************/
    00031
    00032 #include <vlGraphics/Camera.hpp>
    00033 #include <vlGraphics/OpenGL.hpp>
    00034 #include <vlCore/AABB.hpp>
    00035 #include <vlCore/Log.hpp>
    00036 #include <vlCore/Say.hpp>
    00037
    00038 #undef near
    00039 #undef far
    00040
    00041 using namespace vl;
    00042
    00043 //-----------------------------------------------------------------------------
    00044 // Camera
    00045 //-----------------------------------------------------------------------------
    00046 Camera::Camera()
    00047 {
    00048   VL_DEBUG_SET_OBJECT_NAME()
    00049   mFrustum.planes().resize(6);
    00050   mFOV = 60.0;
    00051   mNearPlane = (Real)0.05;
    00052   mFarPlane  = (Real)10000.0;
    00053   mViewport = new Viewport;
    00054
    00055   mProjectionMatrix  = mat4::getPerspective(fov(), 640.0f/480.0f, nearPlane(), farPlane());
    00056 }
    00057 //-----------------------------------------------------------------------------
    00058 void Camera::applyModelViewMatrix(const mat4& model_matrix) const
    00059 {
    00060   /* some OpenGL drivers (ATI) require this instead of the more general (and mathematically correct) viewMatrix() */
    00061   mat4 viewm = viewMatrix();
    00062   viewm.e(3,0) = 0.0;
    00063   viewm.e(3,1) = 0.0;
    00064   viewm.e(3,2) = 0.0;
    00065   viewm.e(3,3) = 1.0;
    00066
    00067   glMatrixMode(GL_MODELVIEW);
    00068 #if 0
    00069   VL_glLoadMatrix( viewm.ptr() );
    00070   VL_glMultMatrix( matrix.ptr() );
    00071 #elif 0
    00072   viewm = viewm * matrix;
    00073   VL_glLoadMatrix( viewm.ptr() );
    00074 #else
    00075   VL_glLoadMatrix( (viewm * model_matrix).ptr() );
    00076 #endif
    00077 }
    00078 //-----------------------------------------------------------------------------
    00079 void Camera::applyProjMatrix() const
    00080 {
    00081   // projection matrix
    00082   glMatrixMode( GL_PROJECTION );
    00083   VL_glLoadMatrix( projectionMatrix().ptr() );
    00084 }
    00085 //-----------------------------------------------------------------------------
    00086 void Camera::applyViewMatrix() const
    00087 {
    00088   /* some OpenGL drivers (ATI) require this instead of the more general (and mathematically correct) viewMatrix() */
    00089   mat4 viewm = viewMatrix();
    00090   viewm.e(3,0) = 0.0;
    00091   viewm.e(3,1) = 0.0;
    00092   viewm.e(3,2) = 0.0;
    00093   viewm.e(3,3) = 1.0;
    00094   glMatrixMode(GL_MODELVIEW);
    00095   VL_glLoadMatrix( viewm.ptr() );
    00096 }
    00097 //-----------------------------------------------------------------------------
    00098 void Camera::computeNearFarOptimizedProjMatrix(const Sphere& scene_bounding_sphere)
    00099 {
    00100   // near/far clipping planes optimization
    00101   if (!scene_bounding_sphere.isNull())
    00102   {
    00103     // compute the sphere in camera coordinates
    00104     Sphere camera_sphere;
    00105     scene_bounding_sphere.transformed(camera_sphere, viewMatrix());
    00106     mNearPlane = -(camera_sphere.center().z() + camera_sphere.radius() * (Real)1.01);
    00107     mFarPlane  = -(camera_sphere.center().z() - camera_sphere.radius() * (Real)1.01);
    00108     #if 0
    00109       far  = max(far,  (Real)1.0e-5);
    00110       near = max(near, (Real)1.0e-6);
    00111     #else
    00112       // prevents z-thrashing when very large objects are zoomed a lot
    00113       Real ratio = camera_sphere.radius() * (Real)2.01 / (Real)2000.0;
    00114       mNearPlane = max(mNearPlane, ratio*1);
    00115       mFarPlane  = max(mFarPlane,  ratio*2);
    00116     #endif
    00117     // supports only perspective projection matrices
    00118     setProjectionAsPerspective();
    00119   }
    00120 }
    00121 //-----------------------------------------------------------------------------
    00122 void Camera::adjustView(const AABB& aabb, const vec3& dir, const vec3& up, Real bias)
    00123 {
    00124   VL_CHECK(bias >= 0)
    00125   if (bias < 0)
    00126     vl::Log::bug("Camera::adjustView(): 'bias' must be >= 0.\n");
    00127
    00128   vec3 center = aabb.center();
    00129
    00130   Sphere sphere(aabb);
    00131   const vec3& C = inverseViewMatrix().getT();
    00132   const vec3& V = -inverseViewMatrix().getZ();
    00133   const Real  R = sphere.radius();
    00134
    00135   // extract the frustum planes based on the current view and projection matrices
    00136   mat4 viewproj = projectionMatrix() * viewMatrix();
    00137   Frustum frustum; frustum.planes().resize(6);
    00138   extractPlanes( &frustum.planes()[0], viewproj );
    00139   // iterate over left/right/top/bottom clipping planes. the planes are in world coords.
    00140   Real max_t = 0;
    00141   for(int i=0; i<4; ++i)
    00142   {
    00143     const vec3& O = frustum.plane(i).origin() * frustum.plane(i).normal();
    00144     const vec3& N = frustum.plane(i).normal();
    00145     Real t = - (R + dot(O,N) - dot(C,N)) / dot(N,V);
    00146     VL_CHECK(t>=0)
    00147     if (t > max_t)
    00148       max_t = t;
    00149   }
    00150   Real dist = max_t;
    00151   mat4 m = mat4::getLookAt(center+dir*dist*bias,center,up);
    00152   setInverseViewMatrix(m);
    00153 }
    00154 //-----------------------------------------------------------------------------
    00155 void Camera::computeFrustumPlanes()
    00156 {
    00157   // build modelview matrix
    00158   mat4 viewproj = projectionMatrix() * viewMatrix();
    00159   // frustum plane extraction
    00160   mFrustum.planes().resize(6);
    00161   extractPlanes( &mFrustum.planes()[0], viewproj );
    00162 }
    00163 //-----------------------------------------------------------------------------
    00164 void Camera::setProjectionAsFrustum(Real left, Real right, Real bottom, Real top, Real near, Real far)
    00165 {
    00166   setFOV(-1);
    00167   setNearPlane(near);
    00168   setFarPlane(far);
    00169   mProjectionMatrix = mat4::getFrustum(left, right, bottom, top, near, far);
    00170 }
    00171 //-----------------------------------------------------------------------------
    00172 void Camera::setProjectionAsPerspective(Real fov, Real near, Real far)
    00173 {
    00174   setFOV(fov);
    00175   setNearPlane(near);
    00176   setFarPlane(far);
    00177   mProjectionMatrix = mat4::getPerspective(fov, aspectRatio(), near, far);
    00178 }
    00179 //-----------------------------------------------------------------------------
    00180 void Camera::setProjectionAsPerspective()
    00181 {
    00182   mProjectionMatrix = mat4::getPerspective(fov(), aspectRatio(), nearPlane(), farPlane());
    00183 }
    00184 //-----------------------------------------------------------------------------
    00185 void Camera::setProjectionAsOrtho(Real offset)
    00186 {
    00187   setProjectionMatrix(
    00188     mat4::getOrtho(
    00189       offset, (Real)mViewport->width()  + offset,
    00190       offset, (Real)mViewport->height() + offset,
    00191       nearPlane(), farPlane())
    00192   );
    00193 }
    00194 //-----------------------------------------------------------------------------
    00195 void Camera::setProjectionAsOrtho2D(Real offset)
    00196 {
    00197   setProjectionMatrix(
    00198     mat4::getOrtho(
    00199       offset, (Real)mViewport->width()  + offset,
    00200       offset, (Real)mViewport->height() + offset,
    00201       -1, +1)
    00202   );
    00203 }
    00204 //-----------------------------------------------------------------------------
    00205 void Camera::setViewMatrixAsLookAt( const vec3& eye, const vec3& center, const vec3& up)
    00206 {
    00207   mat4 m = mat4::getLookAt(eye, center, up);
    00208   // this sets both the frame matrix and the view matrix
    00209   setInverseViewMatrix(m);
    00210 }
    00211 //-----------------------------------------------------------------------------
    00212 void Camera::getViewMatrixAsLookAt( vec3& eye, vec3& look, vec3& up, vec3& right) const
    00213 {
    00214   mInverseViewMatrix.getAsLookAt(eye,look,up,right);
    00215 }
    00216 //-----------------------------------------------------------------------------
    00217 bool Camera::project(const vec4& in, vec4& out) const
    00218 {
    00219   out = mProjectionMatrix * mViewMatrix * in;
    00220
    00221   if (out.w() == 0.0f)
    00222     return false;
    00223
    00224   out.x() /= out.w();
    00225   out.y() /= out.w();
    00226   out.z() /= out.w();
    00227
    00228   // map to range 0-1
    00229   out.x() = out.x() * 0.5f + 0.5f;
    00230   out.y() = out.y() * 0.5f + 0.5f;
    00231   out.z() = out.z() * 0.5f + 0.5f;
    00232
    00233   // map to viewport
    00234   out.x() = out.x() * mViewport->width()  + mViewport->x();
    00235   out.y() = out.y() * mViewport->height() + mViewport->y();
    00236   return true;
    00237 }
    00238 //-----------------------------------------------------------------------------
    00239 bool Camera::unproject(const vec3& win, vec4& out) const
    00240 {
    00241     vec4 v;
    00242     v.x() = win.x();
    00243     v.y() = win.y();
    00244     v.z() = win.z();
    00245     v.w() = 1.0;
    00246
    00247     // map from viewport to 0-1
    00248     v.x() = (v.x() - mViewport->x()) / mViewport->width();
    00249     v.y() = (v.y() - mViewport->y()) / mViewport->height();
    00250
    00251     // map to range -1 to 1
    00252     v.x() = v.x() * 2.0f - 1.0f;
    00253     v.y() = v.y() * 2.0f - 1.0f;
    00254     v.z() = v.z() * 2.0f - 1.0f;
    00255
    00256     Real det=0;
    00257     mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
    00258     if (!det)
    00259       return false;
    00260
    00261     v = inverse * v;
    00262     if (v.w() == 0.0)
    00263       return false;
    00264
    00265     out = v / v.w();
    00266     return true;
    00267 }
    00268 //-----------------------------------------------------------------------------
    00269 bool Camera::unproject(std::vector<vec3>& win) const
    00270 {
    00271   Real det=0;
    00272   mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det);
    00273   if (!det)
    00274     return false;
    00275
    00276   bool ok = true;
    00277   for(unsigned i=0; i<win.size(); ++i)
    00278   {
    00279     vec4 v;
    00280     v = vec4( win[i], 1.0 );
    00281
    00282     // map from viewport to 0-1
    00283     v.x() = (v.x() - mViewport->x()) / mViewport->width();
    00284     v.y() = (v.y() - mViewport->y()) / mViewport->height();
    00285
    00286     // map to range -1 to 1
    00287     v.x() = v.x() * 2.0f - 1.0f;
    00288     v.y() = v.y() * 2.0f - 1.0f;
    00289     v.z() = v.z() * 2.0f - 1.0f;
    00290
    00291     v = inverse * v;
    00292     if (v.w() == 0.0)
    00293     {
    00294       ok = false;
    00295       continue;
    00296     }
    00297
    00298     v = v / v.w();
    00299     win[i] = v.xyz();
    00300   }
    00301   return ok;
    00302 }
    00303 //-----------------------------------------------------------------------------
    00304 Ray Camera::computeRay(int winx, int winy)
    00305 {
    00306   vl::vec4 out;
    00307   if (!unproject( vl::vec3((Real)winx,(Real)winy,0), out ))
    00308     return Ray();
    00309   else
    00310   {
    00311     vl::Ray ray;
    00312     ray.setOrigin(out.xyz());
    00313     ray.setDirection( (out.xyz() - inverseViewMatrix().getT()).normalize() );
    00314     return ray;
    00315   }
    00316 }
    00317 //-----------------------------------------------------------------------------
    00318 Frustum Camera::computeRayFrustum(int winx, int winy)
    00319 {
    00320   /*
    00321       n3
    00322     D-----C
    00323     |     |
    00324   n4|  O  |n2
    00325     |     |
    00326     A-----B
    00327       n1
    00328   */
    00329   // compute the frustum passing through the adjacent pixels
    00330   vl::vec4 A1,B1,C1,D1;
    00331   vl::vec4 A2,B2,C2,D2;
    00332   unproject( vl::vec3((Real)winx-1,(Real)winy-1,0),    A1 );
    00333   unproject( vl::vec3((Real)winx+1,(Real)winy-1,0),    B1 );
    00334   unproject( vl::vec3((Real)winx+1,(Real)winy+1,0),    C1 );
    00335   unproject( vl::vec3((Real)winx-1,(Real)winy+1,0),    D1 );
    00336   unproject( vl::vec3((Real)winx-1,(Real)winy-1,0.1f), A2 );
    00337   unproject( vl::vec3((Real)winx+1,(Real)winy-1,0.1f), B2 );
    00338   unproject( vl::vec3((Real)winx+1,(Real)winy+1,0.1f), C2 );
    00339   unproject( vl::vec3((Real)winx-1,(Real)winy+1,0.1f), D2 );
    00340
    00341   vec3 n1 = -cross(A2.xyz()-A1.xyz(),B1.xyz()-A1.xyz());
    00342   vec3 n2 = -cross(B2.xyz()-B1.xyz(),C1.xyz()-B1.xyz());
    00343   vec3 n3 = -cross(C2.xyz()-C1.xyz(),D1.xyz()-C1.xyz());
    00344   vec3 n4 = -cross(D2.xyz()-D1.xyz(),A1.xyz()-D1.xyz());
    00345   Frustum frustum;
    00346   frustum.planes().push_back( Plane( A1.xyz(), n1 ) );
    00347   frustum.planes().push_back( Plane( B1.xyz(), n2 ) );
    00348   frustum.planes().push_back( Plane( C1.xyz(), n3 ) );
    00349   frustum.planes().push_back( Plane( D1.xyz(), n4 ) );
    00350   return frustum;
    00351 }
    00352 //-----------------------------------------------------------------------------

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:22.
Permission is granted to use this page to write and publish articles regarding Visualization Library.