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"
16 using namespace Eigen;
17
Camera()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
operator =(const Camera & other)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
Camera(const Camera & other)55 Camera::Camera(const Camera& other)
56 {
57 *this = other;
58 }
59
~Camera()60 Camera::~Camera()
61 {
62 }
63
64
setViewport(uint offsetx,uint offsety,uint width,uint height)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
setViewport(uint width,uint height)75 void Camera::setViewport(uint width, uint height)
76 {
77 mVpWidth = width;
78 mVpHeight = height;
79
80 mProjIsUptodate = false;
81 }
82
setFovY(float value)83 void Camera::setFovY(float value)
84 {
85 mFovY = value;
86 mProjIsUptodate = false;
87 }
88
direction(void) const89 Vector3f Camera::direction(void) const
90 {
91 return - (orientation() * Vector3f::UnitZ());
92 }
up(void) const93 Vector3f Camera::up(void) const
94 {
95 return orientation() * Vector3f::UnitY();
96 }
right(void) const97 Vector3f Camera::right(void) const
98 {
99 return orientation() * Vector3f::UnitX();
100 }
101
setDirection(const Vector3f & newDirection)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
setTarget(const Vector3f & target)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
setPosition(const Vector3f & p)127 void Camera::setPosition(const Vector3f& p)
128 {
129 mFrame.position = p;
130 mViewIsUptodate = false;
131 }
132
setOrientation(const Quaternionf & q)133 void Camera::setOrientation(const Quaternionf& q)
134 {
135 mFrame.orientation = q;
136 mViewIsUptodate = false;
137 }
138
setFrame(const Frame & f)139 void Camera::setFrame(const Frame& f)
140 {
141 mFrame = f;
142 mViewIsUptodate = false;
143 }
144
rotateAroundTarget(const Quaternionf & q)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
localRotate(const Quaternionf & q)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
zoom(float d)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
localTranslate(const Vector3f & t)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
updateViewMatrix(void) const193 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
viewMatrix(void) const205 const Affine3f& Camera::viewMatrix(void) const
206 {
207 updateViewMatrix();
208 return mViewMatrix;
209 }
210
updateProjectionMatrix(void) const211 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
projectionMatrix(void) const232 const Matrix4f& Camera::projectionMatrix(void) const
233 {
234 updateProjectionMatrix();
235 return mProjectionMatrix;
236 }
237
activateGL(void)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
unProject(const Vector2f & uv,float depth) const246 Vector3f Camera::unProject(const Vector2f& uv, float depth) const
247 {
248 Matrix4f inv = mViewMatrix.inverse().matrix();
249 return unProject(uv, depth, inv);
250 }
251
unProject(const Vector2f & uv,float depth,const Matrix4f & invModelview) const252 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