Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 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 mLeft = mRight = mTop = mBottom = -1; 00054 mViewport = new Viewport; 00055 00056 mProjectionMatrix = mat4::getPerspective(fov(), 640.0f/480.0f, nearPlane(), farPlane()); 00057 mProjectionType = PMT_PerspectiveProjection; 00058 } 00059 //----------------------------------------------------------------------------- 00060 void Camera::applyModelViewMatrix(const mat4& model_matrix) const 00061 { 00062 /* some OpenGL drivers (ATI) require this instead of the more general (and mathematically correct) viewMatrix() */ 00063 mat4 viewm = viewMatrix(); 00064 viewm.e(3,0) = 0.0; 00065 viewm.e(3,1) = 0.0; 00066 viewm.e(3,2) = 0.0; 00067 viewm.e(3,3) = 1.0; 00068 00069 glMatrixMode(GL_MODELVIEW); 00070 #if 0 00071 VL_glLoadMatrix( viewm.ptr() ); 00072 VL_glMultMatrix( matrix.ptr() ); 00073 #elif 0 00074 viewm = viewm * matrix; 00075 VL_glLoadMatrix( viewm.ptr() ); 00076 #else 00077 VL_glLoadMatrix( (viewm * model_matrix).ptr() ); 00078 #endif 00079 } 00080 //----------------------------------------------------------------------------- 00081 void Camera::applyProjMatrix() const 00082 { 00083 // projection matrix 00084 glMatrixMode( GL_PROJECTION ); 00085 VL_glLoadMatrix( projectionMatrix().ptr() ); 00086 } 00087 //----------------------------------------------------------------------------- 00088 void Camera::applyViewMatrix() const 00089 { 00090 /* some OpenGL drivers (ATI) require this instead of the more general (and mathematically correct) viewMatrix() */ 00091 mat4 viewm = viewMatrix(); 00092 viewm.e(3,0) = 0.0; 00093 viewm.e(3,1) = 0.0; 00094 viewm.e(3,2) = 0.0; 00095 viewm.e(3,3) = 1.0; 00096 glMatrixMode(GL_MODELVIEW); 00097 VL_glLoadMatrix( viewm.ptr() ); 00098 } 00099 //----------------------------------------------------------------------------- 00100 void Camera::computeNearFarOptimizedProjMatrix(const Sphere& scene_bounding_sphere) 00101 { 00102 // near/far clipping planes optimization 00103 if (!scene_bounding_sphere.isNull()) 00104 { 00105 // transform the sphere in camera coordinates 00106 Sphere camera_sphere; 00107 scene_bounding_sphere.transformed(camera_sphere, viewMatrix()); 00108 00109 // visible objects are in the negative z, but we need a positive distance for the near and far clipping planes 00110 mNearPlane = -(camera_sphere.center().z() + camera_sphere.radius()); 00111 mFarPlane = -(camera_sphere.center().z() - camera_sphere.radius()); 00112 00113 // clamp to positive epsilon: can't let near and far clipping planes go behind the camera! 00114 real epsilon = camera_sphere.radius() / 1000.0f; 00115 mFarPlane = max(mFarPlane, epsilon * 2); // alway more than the near 00116 mNearPlane = max(mNearPlane, epsilon * 1); 00117 00118 switch(projectionMatrixType()) 00119 { 00120 case PMT_OrthographicProjection: setProjectionOrtho(mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane); 00121 break; 00122 case PMT_PerspectiveProjection: setProjectionPerspective(); 00123 break; 00124 00125 // we cannot do this: if we change the near plane we have to recompute also left, right, bottom and top! 00126 // case PMT_PerspectiveProjectionFrustum: setProjectionFrustum(mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane); 00127 // break; 00128 00129 default: 00130 Log::bug("Camera::computeNearFarOptimizedProjMatrix() called on unsupported projection type.\n"); 00131 } 00132 } 00133 } 00134 //----------------------------------------------------------------------------- 00135 void Camera::adjustView(const AABB& aabb, const vec3& dir, const vec3& up, real bias) 00136 { 00137 VL_CHECK(bias >= 0) 00138 VL_CHECK(!aabb.isNull()) 00139 if (bias < 0) 00140 vl::Log::bug("Camera::adjustView(): 'bias' must be >= 0.\n"); 00141 00142 vec3 center = aabb.center(); 00143 00144 Sphere sphere(aabb); 00145 const vec3& C = modelingMatrix().getT(); 00146 const vec3& V = -modelingMatrix().getZ(); 00147 const real R = sphere.radius(); 00148 00149 // extract the frustum planes based on the current view and projection matrices 00150 mat4 viewproj = projectionMatrix() * viewMatrix(); 00151 Frustum frustum; frustum.planes().resize(6); 00152 extractPlanes( &frustum.planes()[0], viewproj ); 00153 // iterate over left/right/top/bottom clipping planes. the planes are in world coords. 00154 real max_t = 0; 00155 for(int i=0; i<4; ++i) 00156 { 00157 const vec3& O = frustum.plane(i).origin() * frustum.plane(i).normal(); 00158 const vec3& N = frustum.plane(i).normal(); 00159 real t = - (R + dot(O,N) - dot(C,N)) / dot(N,V); 00160 VL_CHECK(t>=0) 00161 if (t > max_t) 00162 max_t = t; 00163 } 00164 real dist = max_t; 00165 mat4 m = mat4::getLookAt(center+dir*dist*bias,center,up); 00166 setViewMatrix(m); 00167 } 00168 //----------------------------------------------------------------------------- 00169 void Camera::computeFrustumPlanes() 00170 { 00171 // build modelview matrix 00172 mat4 viewproj = projectionMatrix() * viewMatrix(); 00173 // frustum plane extraction 00174 mFrustum.planes().resize(6); 00175 extractPlanes( &mFrustum.planes()[0], viewproj ); 00176 } 00177 //----------------------------------------------------------------------------- 00178 void Camera::setProjectionFrustum(real left, real right, real bottom, real top, real near, real far) 00179 { 00180 // see http://www.opengl.org/resources/faq/technical/transformations.htm 00181 setFOV( 2.0f*atan((top-bottom)*0.5f/near) ); 00182 setNearPlane(near); 00183 setFarPlane(far); 00184 setProjectionMatrix(mat4::getFrustum(left, right, bottom, top, near, far), PMT_PerspectiveProjectionFrustum); 00185 } 00186 //----------------------------------------------------------------------------- 00187 void Camera::setProjectionPerspective(real fov, real near, real far) 00188 { 00189 setFOV(fov); 00190 setNearPlane(near); 00191 setFarPlane(far); 00192 setProjectionMatrix(mat4::getPerspective(fov, aspectRatio(), near, far), PMT_PerspectiveProjection); 00193 } 00194 //----------------------------------------------------------------------------- 00195 void Camera::setProjectionPerspective() 00196 { 00197 setProjectionMatrix(mat4::getPerspective(fov(), aspectRatio(), nearPlane(), farPlane()), PMT_PerspectiveProjection); 00198 } 00199 //----------------------------------------------------------------------------- 00200 void Camera::setProjectionOrtho() 00201 { 00202 mLeft = 0; 00203 mRight = (real)mViewport->width(); 00204 mBottom = 0; 00205 mTop = (real)mViewport->height(); 00206 mFOV = -1; 00207 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection ); 00208 } 00209 //----------------------------------------------------------------------------- 00210 void Camera::setProjectionOrtho(real left, real right, real bottom, real top, real znear, real zfar) 00211 { 00212 mLeft = left; 00213 mRight = right; 00214 mBottom = bottom; 00215 mTop = top; 00216 mFOV = -1; 00217 mNearPlane = znear; 00218 mFarPlane = zfar; 00219 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection ); 00220 } 00221 //----------------------------------------------------------------------------- 00222 void Camera::setProjectionOrtho(real offset) 00223 { 00224 mLeft = offset; 00225 mRight = viewport()->width() + offset; 00226 mBottom = offset; 00227 mTop = viewport()->height() + offset; 00228 mFOV = -1; 00229 mNearPlane = -1; 00230 mFarPlane = +1; 00231 setProjectionMatrix( mat4::getOrtho( mLeft, mRight, mBottom, mTop, mNearPlane, mFarPlane), PMT_OrthographicProjection ); 00232 } 00233 //----------------------------------------------------------------------------- 00234 void Camera::setViewMatrixLookAt( const vec3& eye, const vec3& at, const vec3& up) 00235 { 00236 // note: this sets both the local matrix and the view matrix 00237 setViewMatrix( mat4::getLookAt(eye, at, up) ); 00238 } 00239 //----------------------------------------------------------------------------- 00240 void Camera::getViewMatrixAsLookAt( vec3& eye, vec3& at, vec3& up, vec3& right) const 00241 { 00242 mModelingMatrix.getAsLookAtModeling(eye, at, up, right); 00243 } 00244 //----------------------------------------------------------------------------- 00245 bool Camera::project(const vec4& in, vec4& out) const 00246 { 00247 out = mProjectionMatrix * mViewMatrix * in; 00248 00249 if (out.w() == 0.0f) 00250 return false; 00251 00252 out.x() /= out.w(); 00253 out.y() /= out.w(); 00254 out.z() /= out.w(); 00255 00256 // map to range 0-1 00257 out.x() = out.x() * 0.5f + 0.5f; 00258 out.y() = out.y() * 0.5f + 0.5f; 00259 out.z() = out.z() * 0.5f + 0.5f; 00260 00261 // map to viewport 00262 out.x() = out.x() * mViewport->width() + mViewport->x(); 00263 out.y() = out.y() * mViewport->height() + mViewport->y(); 00264 return true; 00265 } 00266 //----------------------------------------------------------------------------- 00267 bool Camera::unproject(const vec3& win, vec4& out) const 00268 { 00269 vec4 v; 00270 v.x() = win.x(); 00271 v.y() = win.y(); 00272 v.z() = win.z(); 00273 v.w() = 1.0; 00274 00275 // map from viewport to 0-1 00276 v.x() = (v.x() - mViewport->x()) / mViewport->width(); 00277 v.y() = (v.y() - mViewport->y()) / mViewport->height(); 00278 00279 // map to range -1 to 1 00280 v.x() = v.x() * 2.0f - 1.0f; 00281 v.y() = v.y() * 2.0f - 1.0f; 00282 v.z() = v.z() * 2.0f - 1.0f; 00283 00284 real det=0; 00285 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det); 00286 if (!det) 00287 return false; 00288 00289 v = inverse * v; 00290 if (v.w() == 0.0) 00291 return false; 00292 00293 out = v / v.w(); 00294 return true; 00295 } 00296 //----------------------------------------------------------------------------- 00297 bool Camera::unproject(std::vector<vec3>& win) const 00298 { 00299 real det=0; 00300 mat4 inverse = (mProjectionMatrix * mViewMatrix).getInverse(&det); 00301 if (!det) 00302 return false; 00303 00304 bool ok = true; 00305 for(unsigned i=0; i<win.size(); ++i) 00306 { 00307 vec4 v; 00308 v = vec4( win[i], 1.0 ); 00309 00310 // map from viewport to 0-1 00311 v.x() = (v.x() - mViewport->x()) / mViewport->width(); 00312 v.y() = (v.y() - mViewport->y()) / mViewport->height(); 00313 00314 // map to range -1 to 1 00315 v.x() = v.x() * 2.0f - 1.0f; 00316 v.y() = v.y() * 2.0f - 1.0f; 00317 v.z() = v.z() * 2.0f - 1.0f; 00318 00319 v = inverse * v; 00320 if (v.w() == 0.0) 00321 { 00322 ok = false; 00323 continue; 00324 } 00325 00326 v = v / v.w(); 00327 win[i] = v.xyz(); 00328 } 00329 return ok; 00330 } 00331 //----------------------------------------------------------------------------- 00332 Ray Camera::computeRay(int winx, int winy) 00333 { 00334 vl::vec4 out; 00335 if (!unproject( vl::vec3((real)winx,(real)winy,0), out )) 00336 return Ray(); 00337 else 00338 { 00339 vl::Ray ray; 00340 ray.setOrigin(out.xyz()); 00341 ray.setDirection( (out.xyz() - modelingMatrix().getT()).normalize() ); 00342 return ray; 00343 } 00344 } 00345 //----------------------------------------------------------------------------- 00346 Frustum Camera::computeRayFrustum(int winx, int winy) 00347 { 00348 /* 00349 n3 00350 D-----C 00351 | | 00352 n4| O |n2 00353 | | 00354 A-----B 00355 n1 00356 */ 00357 // compute the frustum passing through the adjacent pixels 00358 vl::vec4 A1,B1,C1,D1; 00359 vl::vec4 A2,B2,C2,D2; 00360 unproject( vl::vec3((real)winx-1,(real)winy-1,0), A1 ); 00361 unproject( vl::vec3((real)winx+1,(real)winy-1,0), B1 ); 00362 unproject( vl::vec3((real)winx+1,(real)winy+1,0), C1 ); 00363 unproject( vl::vec3((real)winx-1,(real)winy+1,0), D1 ); 00364 unproject( vl::vec3((real)winx-1,(real)winy-1,0.1f), A2 ); 00365 unproject( vl::vec3((real)winx+1,(real)winy-1,0.1f), B2 ); 00366 unproject( vl::vec3((real)winx+1,(real)winy+1,0.1f), C2 ); 00367 unproject( vl::vec3((real)winx-1,(real)winy+1,0.1f), D2 ); 00368 00369 vec3 n1 = -cross(A2.xyz()-A1.xyz(),B1.xyz()-A1.xyz()); 00370 vec3 n2 = -cross(B2.xyz()-B1.xyz(),C1.xyz()-B1.xyz()); 00371 vec3 n3 = -cross(C2.xyz()-C1.xyz(),D1.xyz()-C1.xyz()); 00372 vec3 n4 = -cross(D2.xyz()-D1.xyz(),A1.xyz()-D1.xyz()); 00373 Frustum frustum; 00374 frustum.planes().push_back( Plane( A1.xyz(), n1 ) ); 00375 frustum.planes().push_back( Plane( B1.xyz(), n2 ) ); 00376 frustum.planes().push_back( Plane( C1.xyz(), n3 ) ); 00377 frustum.planes().push_back( Plane( D1.xyz(), n4 ) ); 00378 return frustum; 00379 } 00380 //-----------------------------------------------------------------------------