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@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" 16using namespace Eigen; 17 18Camera::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 34Camera& 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 55Camera::Camera(const Camera& other) 56{ 57 *this = other; 58} 59 60Camera::~Camera() 61{ 62} 63 64 65void 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 75void Camera::setViewport(uint width, uint height) 76{ 77 mVpWidth = width; 78 mVpHeight = height; 79 80 mProjIsUptodate = false; 81} 82 83void Camera::setFovY(float value) 84{ 85 mFovY = value; 86 mProjIsUptodate = false; 87} 88 89Vector3f Camera::direction(void) const 90{ 91 return - (orientation() * Vector3f::UnitZ()); 92} 93Vector3f Camera::up(void) const 94{ 95 return orientation() * Vector3f::UnitY(); 96} 97Vector3f Camera::right(void) const 98{ 99 return orientation() * Vector3f::UnitX(); 100} 101 102void 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 117void 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 127void Camera::setPosition(const Vector3f& p) 128{ 129 mFrame.position = p; 130 mViewIsUptodate = false; 131} 132 133void Camera::setOrientation(const Quaternionf& q) 134{ 135 mFrame.orientation = q; 136 mViewIsUptodate = false; 137} 138 139void Camera::setFrame(const Frame& f) 140{ 141 mFrame = f; 142 mViewIsUptodate = false; 143} 144 145void 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 166void 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 174void 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 184void 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 193void 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 205const Affine3f& Camera::viewMatrix(void) const 206{ 207 updateViewMatrix(); 208 return mViewMatrix; 209} 210 211void 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 232const Matrix4f& Camera::projectionMatrix(void) const 233{ 234 updateProjectionMatrix(); 235 return mProjectionMatrix; 236} 237 238void 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 246Vector3f Camera::unProject(const Vector2f& uv, float depth) const 247{ 248 Matrix4f inv = mViewMatrix.inverse().matrix(); 249 return unProject(uv, depth, inv); 250} 251 252Vector3f 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