You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
5.8 KiB

  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. #include "camera.h"
  10. #include "gpuhelper.h"
  11. #include <GL/glu.h>
  12. #include "Eigen/LU"
  13. using namespace Eigen;
  14. Camera::Camera()
  15. : mViewIsUptodate(false), mProjIsUptodate(false)
  16. {
  17. mViewMatrix.setIdentity();
  18. mFovY = M_PI/3.;
  19. mNearDist = 1.;
  20. mFarDist = 50000.;
  21. mVpX = 0;
  22. mVpY = 0;
  23. setPosition(Vector3f::Constant(100.));
  24. setTarget(Vector3f::Zero());
  25. }
  26. Camera& Camera::operator=(const Camera& other)
  27. {
  28. mViewIsUptodate = false;
  29. mProjIsUptodate = false;
  30. mVpX = other.mVpX;
  31. mVpY = other.mVpY;
  32. mVpWidth = other.mVpWidth;
  33. mVpHeight = other.mVpHeight;
  34. mTarget = other.mTarget;
  35. mFovY = other.mFovY;
  36. mNearDist = other.mNearDist;
  37. mFarDist = other.mFarDist;
  38. mViewMatrix = other.mViewMatrix;
  39. mProjectionMatrix = other.mProjectionMatrix;
  40. return *this;
  41. }
  42. Camera::Camera(const Camera& other)
  43. {
  44. *this = other;
  45. }
  46. Camera::~Camera()
  47. {
  48. }
  49. void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height)
  50. {
  51. mVpX = offsetx;
  52. mVpY = offsety;
  53. mVpWidth = width;
  54. mVpHeight = height;
  55. mProjIsUptodate = false;
  56. }
  57. void Camera::setViewport(uint width, uint height)
  58. {
  59. mVpWidth = width;
  60. mVpHeight = height;
  61. mProjIsUptodate = false;
  62. }
  63. void Camera::setFovY(float value)
  64. {
  65. mFovY = value;
  66. mProjIsUptodate = false;
  67. }
  68. Vector3f Camera::direction(void) const
  69. {
  70. return - (orientation() * Vector3f::UnitZ());
  71. }
  72. Vector3f Camera::up(void) const
  73. {
  74. return orientation() * Vector3f::UnitY();
  75. }
  76. Vector3f Camera::right(void) const
  77. {
  78. return orientation() * Vector3f::UnitX();
  79. }
  80. void Camera::setDirection(const Vector3f& newDirection)
  81. {
  82. // TODO implement it computing the rotation between newDirection and current dir ?
  83. Vector3f up = this->up();
  84. Matrix3f camAxes;
  85. camAxes.col(2) = (-newDirection).normalized();
  86. camAxes.col(0) = up.cross( camAxes.col(2) ).normalized();
  87. camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized();
  88. setOrientation(Quaternionf(camAxes));
  89. mViewIsUptodate = false;
  90. }
  91. void Camera::setTarget(const Vector3f& target)
  92. {
  93. mTarget = target;
  94. if (!mTarget.isApprox(position()))
  95. {
  96. Vector3f newDirection = mTarget - position();
  97. setDirection(newDirection.normalized());
  98. }
  99. }
  100. void Camera::setPosition(const Vector3f& p)
  101. {
  102. mFrame.position = p;
  103. mViewIsUptodate = false;
  104. }
  105. void Camera::setOrientation(const Quaternionf& q)
  106. {
  107. mFrame.orientation = q;
  108. mViewIsUptodate = false;
  109. }
  110. void Camera::setFrame(const Frame& f)
  111. {
  112. mFrame = f;
  113. mViewIsUptodate = false;
  114. }
  115. void Camera::rotateAroundTarget(const Quaternionf& q)
  116. {
  117. Matrix4f mrot, mt, mtm;
  118. // update the transform matrix
  119. updateViewMatrix();
  120. Vector3f t = mViewMatrix * mTarget;
  121. mViewMatrix = Translation3f(t)
  122. * q
  123. * Translation3f(-t)
  124. * mViewMatrix;
  125. Quaternionf qa(mViewMatrix.linear());
  126. qa = qa.conjugate();
  127. setOrientation(qa);
  128. setPosition(- (qa * mViewMatrix.translation()) );
  129. mViewIsUptodate = true;
  130. }
  131. void Camera::localRotate(const Quaternionf& q)
  132. {
  133. float dist = (position() - mTarget).norm();
  134. setOrientation(orientation() * q);
  135. mTarget = position() + dist * direction();
  136. mViewIsUptodate = false;
  137. }
  138. void Camera::zoom(float d)
  139. {
  140. float dist = (position() - mTarget).norm();
  141. if(dist > d)
  142. {
  143. setPosition(position() + direction() * d);
  144. mViewIsUptodate = false;
  145. }
  146. }
  147. void Camera::localTranslate(const Vector3f& t)
  148. {
  149. Vector3f trans = orientation() * t;
  150. setPosition( position() + trans );
  151. setTarget( mTarget + trans );
  152. mViewIsUptodate = false;
  153. }
  154. void Camera::updateViewMatrix(void) const
  155. {
  156. if(!mViewIsUptodate)
  157. {
  158. Quaternionf q = orientation().conjugate();
  159. mViewMatrix.linear() = q.toRotationMatrix();
  160. mViewMatrix.translation() = - (mViewMatrix.linear() * position());
  161. mViewIsUptodate = true;
  162. }
  163. }
  164. const Affine3f& Camera::viewMatrix(void) const
  165. {
  166. updateViewMatrix();
  167. return mViewMatrix;
  168. }
  169. void Camera::updateProjectionMatrix(void) const
  170. {
  171. if(!mProjIsUptodate)
  172. {
  173. mProjectionMatrix.setIdentity();
  174. float aspect = float(mVpWidth)/float(mVpHeight);
  175. float theta = mFovY*0.5;
  176. float range = mFarDist - mNearDist;
  177. float invtan = 1./tan(theta);
  178. mProjectionMatrix(0,0) = invtan / aspect;
  179. mProjectionMatrix(1,1) = invtan;
  180. mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range;
  181. mProjectionMatrix(3,2) = -1;
  182. mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range;
  183. mProjectionMatrix(3,3) = 0;
  184. mProjIsUptodate = true;
  185. }
  186. }
  187. const Matrix4f& Camera::projectionMatrix(void) const
  188. {
  189. updateProjectionMatrix();
  190. return mProjectionMatrix;
  191. }
  192. void Camera::activateGL(void)
  193. {
  194. glViewport(vpX(), vpY(), vpWidth(), vpHeight());
  195. gpu.loadMatrix(projectionMatrix(),GL_PROJECTION);
  196. gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW);
  197. }
  198. Vector3f Camera::unProject(const Vector2f& uv, float depth) const
  199. {
  200. Matrix4f inv = mViewMatrix.inverse().matrix();
  201. return unProject(uv, depth, inv);
  202. }
  203. Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const
  204. {
  205. updateViewMatrix();
  206. updateProjectionMatrix();
  207. Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.);
  208. a.x() *= depth/mProjectionMatrix(0,0);
  209. a.y() *= depth/mProjectionMatrix(1,1);
  210. a.z() = -depth;
  211. // FIXME /\/|
  212. Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.);
  213. return Vector3f(b.x(), b.y(), b.z());
  214. }