• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KGLLib

camera.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Rivo Laks <rivolaks@hot.ee>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either 
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public 
00015  * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include "camera.h"
00019 
00020 #include <math.h>
00021 
00022 #include <Eigen/LU>
00023 
00024 using namespace Eigen;
00025 
00026 namespace KGLLib
00027 {
00028 
00029 Camera::Camera()
00030 {
00031     mFoV = 45.0f;
00032     mAspect = 1.0f;
00033     mDepthNear = 1.0f;
00034     mDepthFar = 100.0f;
00035     mPosition = Vector3f(-10, 0, 10);
00036     mLookAt = Vector3f(0, 0, 0);
00037     mUp = Vector3f(0, 1, 0);
00038     mModelviewMatrixDirty = true;
00039     mProjectionMatrixDirty = true;
00040 }
00041 
00042 Camera::~Camera()
00043 {
00044 }
00045 
00046 void Camera::setFoV(float fov)
00047 {
00048     mFoV = fov;
00049     mProjectionMatrixDirty = true;
00050 }
00051 
00052 void Camera::setAspect(float aspect)
00053 {
00054     mAspect = aspect;
00055     mProjectionMatrixDirty = true;
00056 }
00057 
00058 void Camera::setDepthRange(float near, float far)
00059 {
00060     mDepthNear = near;
00061     mDepthFar = far;
00062     mProjectionMatrixDirty = true;
00063 }
00064 
00065 void Camera::setPosition(const Eigen::Vector3f& pos)
00066 {
00067     mPosition = pos;
00068     mModelviewMatrixDirty = true;
00069 }
00070 
00071 void Camera::setLookAt(const Eigen::Vector3f& lookat)
00072 {
00073     mLookAt = lookat;
00074     mModelviewMatrixDirty = true;
00075 }
00076 
00077 void Camera::setUp(const Eigen::Vector3f& up)
00078 {
00079     mUp = up;
00080     mModelviewMatrixDirty = true;
00081 }
00082 
00083 void Camera::setDirection(const Eigen::Vector3f& dir)
00084 {
00085     setLookAt(mPosition + dir);
00086 }
00087 
00088 void Camera::setViewport(int x, int y, int width, int height)
00089 {
00090     mViewport[0] = x;
00091     mViewport[1] = y;
00092     mViewport[2] = width;
00093     mViewport[3] = height;
00094 }
00095 
00096 void Camera::applyPerspective()
00097 {
00098     if (mProjectionMatrixDirty) {
00099         recalculateProjectionMatrix();
00100     }
00101 
00102     glMatrixMode(GL_PROJECTION);
00103     glLoadIdentity();
00104     glMultMatrixf(mProjectionMatrix.data());
00105     glMatrixMode(GL_MODELVIEW);
00106 }
00107 
00108 void Camera::applyView(bool reset)
00109 {
00110     if (mModelviewMatrixDirty) {
00111         recalculateModelviewMatrix();
00112     }
00113 
00114     if (reset) {
00115         glLoadIdentity();
00116     }
00117     glMultMatrixf(mModelviewMatrix.data());
00118 }
00119 
00120 void Camera::applyViewport()
00121 {
00122     glViewport(mViewport[0], mViewport[1], mViewport[2], mViewport[3]);
00123 }
00124 
00125 void Camera::recalculateModelviewMatrix()
00126 {
00127     // Code from Mesa project, src/glu/sgi/libutil/project.c
00128     mModelviewMatrixDirty = false;
00129     // Our looking direction
00130     Vector3f forward = (mLookAt - mPosition).normalized();
00131 
00132     Vector3f side = forward.cross(mUp).normalized();
00133 
00134     // Recompute up vector, using cross product
00135     Vector3f up = side.cross(forward);
00136 
00137     mModelviewMatrix.setIdentity();
00138     mModelviewMatrix.linear() << side.transpose(), up.transpose(), -forward.transpose();
00139     mModelviewMatrix.translate(-mPosition);
00140 }
00141 
00142 void Camera::recalculateProjectionMatrix()
00143 {
00144     // Code from Mesa project, src/glu/sgi/libutil/project.c
00145     mProjectionMatrixDirty = false;
00146     mProjectionMatrix.setIdentity();
00147     float radians = mFoV / 2 * M_PI / 180;
00148 
00149     float deltaZ = mDepthFar - mDepthNear;
00150     float sine = ei_sin(radians);
00151     if ((deltaZ == 0) || (sine == 0) || (mAspect == 0)) {
00152         return;
00153     }
00154     float cotangent = ei_cos(radians) / sine;
00155 
00156     mProjectionMatrix(0, 0) = cotangent / mAspect;
00157     mProjectionMatrix(1, 1) = cotangent;
00158     mProjectionMatrix(2, 2) = -(mDepthFar + mDepthNear) / deltaZ;
00159     mProjectionMatrix(3, 2) = -1;
00160     mProjectionMatrix(2, 3) = -2 * mDepthNear * mDepthFar / deltaZ;
00161     mProjectionMatrix(3, 3) = 0;
00162 }
00163 
00164 void Camera::setModelviewMatrix(const Eigen::Transform3f& modelview)
00165 {
00166     mModelviewMatrix = modelview;
00167     mModelviewMatrixDirty = false;
00168 }
00169 
00170 void Camera::setProjectionMatrix(const Eigen::Transform3f& projection)
00171 {
00172     mProjectionMatrix = projection;
00173     mProjectionMatrixDirty = false;
00174 }
00175 
00176 Eigen::Transform3f Camera::modelviewMatrix() const
00177 {
00178     if (mModelviewMatrixDirty) {
00179         const_cast<Camera*>(this)->recalculateModelviewMatrix();
00180     }
00181     return mModelviewMatrix;
00182 }
00183 
00184 Eigen::Transform3f Camera::projectionMatrix() const
00185 {
00186     if (mProjectionMatrixDirty) {
00187         const_cast<Camera*>(this)->recalculateProjectionMatrix();
00188     }
00189     return mProjectionMatrix;
00190 }
00191 
00192 Eigen::Vector3f Camera::project(const Eigen::Vector3f& v, bool* ok) const
00193 {
00194     // TODO add unit test
00195     Vector3f res;
00196     Vector4f p4 = projectionMatrix() * (modelviewMatrix() * Vector4f(v[0],v[1],v[2],1));
00197     if (p4.w()!=0)
00198     {
00199       res = p4.start<3>() / p4.w();
00200       res = (res * 0.5).cwise() + 0.5;
00201       res.start<2>() = Vector2f(mViewport[0],mViewport[1])
00202                      + Vector2f(mViewport[2],mViewport[3]).cwise() * res.start<2>();
00203       if (ok)
00204           *ok = true;
00205     }
00206     else if (ok)
00207         *ok = false;
00208     return res;
00209 }
00210 
00211 Eigen::Vector3f Camera::unProject(const Eigen::Vector3f& v, bool* ok) const
00212 {
00213     // TODO add unit test
00214     if (ok) *ok = true;
00215     Vector4f a;
00216     a << (v.start<2>() - Vector2f(mViewport[0],mViewport[1]))
00217               .cwise() / Vector2f(mViewport[2],mViewport[3]),
00218          v.z(),
00219          1;
00220     a.start<3>() = a.start<3>() * 2 - Vector3f::Constant(1);
00221     // FIXME if we assume the projection matrix always has the structure defined in
00222     // recalculateProjectionMatrix, then the following matrix product could be
00223     // significantly improved !!
00224     a = (projectionMatrix() * modelviewMatrix()).inverse() * a;
00225     if (a.w()==0)
00226     {
00227         if (ok) *ok = false;
00228         return a.start<3>();
00229     }
00230     return a.start<3>() / a.w();
00231 }
00232 
00233 
00234 }

KGLLib

Skip menu "KGLLib"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KGLLib
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal