Home | History | Annotate | Download | only in opengl
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud (at) inria.fr>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #include "camera.h"
     11 
     12 #include "gpuhelper.h"
     13 #include <GL/glu.h>
     14 
     15 #include "Eigen/LU"
     16 using namespace Eigen;
     17 
     18 Camera::Camera()
     19     : mViewIsUptodate(false), mProjIsUptodate(false)
     20 {
     21     mViewMatrix.setIdentity();
     22 
     23     mFovY = M_PI/3.;
     24     mNearDist = 1.;
     25     mFarDist = 50000.;
     26 
     27     mVpX = 0;
     28     mVpY = 0;
     29 
     30     setPosition(Vector3f::Constant(100.));
     31     setTarget(Vector3f::Zero());
     32 }
     33 
     34 Camera& Camera::operator=(const Camera& other)
     35 {
     36     mViewIsUptodate = false;
     37     mProjIsUptodate = false;
     38 
     39     mVpX = other.mVpX;
     40     mVpY = other.mVpY;
     41     mVpWidth = other.mVpWidth;
     42     mVpHeight = other.mVpHeight;
     43 
     44     mTarget = other.mTarget;
     45     mFovY = other.mFovY;
     46     mNearDist = other.mNearDist;
     47     mFarDist = other.mFarDist;
     48 
     49     mViewMatrix = other.mViewMatrix;
     50     mProjectionMatrix = other.mProjectionMatrix;
     51 
     52     return *this;
     53 }
     54 
     55 Camera::Camera(const Camera& other)
     56 {
     57     *this = other;
     58 }
     59 
     60 Camera::~Camera()
     61 {
     62 }
     63 
     64 
     65 void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height)
     66 {
     67     mVpX = offsetx;
     68     mVpY = offsety;
     69     mVpWidth = width;
     70     mVpHeight = height;
     71 
     72     mProjIsUptodate = false;
     73 }
     74 
     75 void Camera::setViewport(uint width, uint height)
     76 {
     77     mVpWidth = width;
     78     mVpHeight = height;
     79 
     80     mProjIsUptodate = false;
     81 }
     82 
     83 void Camera::setFovY(float value)
     84 {
     85     mFovY = value;
     86     mProjIsUptodate = false;
     87 }
     88 
     89 Vector3f Camera::direction(void) const
     90 {
     91     return - (orientation() * Vector3f::UnitZ());
     92 }
     93 Vector3f Camera::up(void) const
     94 {
     95     return orientation() * Vector3f::UnitY();
     96 }
     97 Vector3f Camera::right(void) const
     98 {
     99     return orientation() * Vector3f::UnitX();
    100 }
    101 
    102 void Camera::setDirection(const Vector3f& newDirection)
    103 {
    104     // TODO implement it computing the rotation between newDirection and current dir ?
    105     Vector3f up = this->up();
    106 
    107     Matrix3f camAxes;
    108 
    109     camAxes.col(2) = (-newDirection).normalized();
    110     camAxes.col(0) = up.cross( camAxes.col(2) ).normalized();
    111     camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized();
    112     setOrientation(Quaternionf(camAxes));
    113 
    114     mViewIsUptodate = false;
    115 }
    116 
    117 void Camera::setTarget(const Vector3f& target)
    118 {
    119     mTarget = target;
    120     if (!mTarget.isApprox(position()))
    121     {
    122         Vector3f newDirection = mTarget - position();
    123         setDirection(newDirection.normalized());
    124     }
    125 }
    126 
    127 void Camera::setPosition(const Vector3f& p)
    128 {
    129     mFrame.position = p;
    130     mViewIsUptodate = false;
    131 }
    132 
    133 void Camera::setOrientation(const Quaternionf& q)
    134 {
    135     mFrame.orientation = q;
    136     mViewIsUptodate = false;
    137 }
    138 
    139 void Camera::setFrame(const Frame& f)
    140 {
    141   mFrame = f;
    142   mViewIsUptodate = false;
    143 }
    144 
    145 void Camera::rotateAroundTarget(const Quaternionf& q)
    146 {
    147     Matrix4f mrot, mt, mtm;
    148 
    149     // update the transform matrix
    150     updateViewMatrix();
    151     Vector3f t = mViewMatrix * mTarget;
    152 
    153     mViewMatrix = Translation3f(t)
    154                 * q
    155                 * Translation3f(-t)
    156                 * mViewMatrix;
    157 
    158     Quaternionf qa(mViewMatrix.linear());
    159     qa = qa.conjugate();
    160     setOrientation(qa);
    161     setPosition(- (qa * mViewMatrix.translation()) );
    162 
    163     mViewIsUptodate = true;
    164 }
    165 
    166 void Camera::localRotate(const Quaternionf& q)
    167 {
    168     float dist = (position() - mTarget).norm();
    169     setOrientation(orientation() * q);
    170     mTarget = position() + dist * direction();
    171     mViewIsUptodate = false;
    172 }
    173 
    174 void Camera::zoom(float d)
    175 {
    176     float dist = (position() - mTarget).norm();
    177     if(dist > d)
    178     {
    179         setPosition(position() + direction() * d);
    180         mViewIsUptodate = false;
    181     }
    182 }
    183 
    184 void Camera::localTranslate(const Vector3f& t)
    185 {
    186   Vector3f trans = orientation() * t;
    187   setPosition( position() + trans );
    188   setTarget( mTarget + trans );
    189 
    190   mViewIsUptodate = false;
    191 }
    192 
    193 void Camera::updateViewMatrix(void) const
    194 {
    195     if(!mViewIsUptodate)
    196     {
    197         Quaternionf q = orientation().conjugate();
    198         mViewMatrix.linear() = q.toRotationMatrix();
    199         mViewMatrix.translation() = - (mViewMatrix.linear() * position());
    200 
    201         mViewIsUptodate = true;
    202     }
    203 }
    204 
    205 const Affine3f& Camera::viewMatrix(void) const
    206 {
    207   updateViewMatrix();
    208   return mViewMatrix;
    209 }
    210 
    211 void Camera::updateProjectionMatrix(void) const
    212 {
    213   if(!mProjIsUptodate)
    214   {
    215     mProjectionMatrix.setIdentity();
    216     float aspect = float(mVpWidth)/float(mVpHeight);
    217     float theta = mFovY*0.5;
    218     float range = mFarDist - mNearDist;
    219     float invtan = 1./tan(theta);
    220 
    221     mProjectionMatrix(0,0) = invtan / aspect;
    222     mProjectionMatrix(1,1) = invtan;
    223     mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range;
    224     mProjectionMatrix(3,2) = -1;
    225     mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range;
    226     mProjectionMatrix(3,3) = 0;
    227 
    228     mProjIsUptodate = true;
    229   }
    230 }
    231 
    232 const Matrix4f& Camera::projectionMatrix(void) const
    233 {
    234   updateProjectionMatrix();
    235   return mProjectionMatrix;
    236 }
    237 
    238 void Camera::activateGL(void)
    239 {
    240   glViewport(vpX(), vpY(), vpWidth(), vpHeight());
    241   gpu.loadMatrix(projectionMatrix(),GL_PROJECTION);
    242   gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW);
    243 }
    244 
    245 
    246 Vector3f Camera::unProject(const Vector2f& uv, float depth) const
    247 {
    248     Matrix4f inv = mViewMatrix.inverse().matrix();
    249     return unProject(uv, depth, inv);
    250 }
    251 
    252 Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const
    253 {
    254     updateViewMatrix();
    255     updateProjectionMatrix();
    256 
    257     Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.);
    258     a.x() *= depth/mProjectionMatrix(0,0);
    259     a.y() *= depth/mProjectionMatrix(1,1);
    260     a.z() = -depth;
    261     // FIXME /\/|
    262     Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.);
    263     return Vector3f(b.x(), b.y(), b.z());
    264 }
    265