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