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
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							264 lines
						
					
					
						
							5.8 KiB
						
					
					
				| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr> | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
|  | |
| #include "camera.h" | |
|  | |
| #include "gpuhelper.h" | |
| #include <GL/glu.h> | |
|  | |
| #include "Eigen/LU" | |
| using namespace StormEigen; | |
| 
 | |
| Camera::Camera() | |
|     : mViewIsUptodate(false), mProjIsUptodate(false) | |
| { | |
|     mViewMatrix.setIdentity(); | |
|      | |
|     mFovY = M_PI/3.; | |
|     mNearDist = 1.; | |
|     mFarDist = 50000.; | |
|      | |
|     mVpX = 0; | |
|     mVpY = 0; | |
| 
 | |
|     setPosition(Vector3f::Constant(100.)); | |
|     setTarget(Vector3f::Zero()); | |
| } | |
| 
 | |
| Camera& Camera::operator=(const Camera& other) | |
| { | |
|     mViewIsUptodate = false; | |
|     mProjIsUptodate = false; | |
|      | |
|     mVpX = other.mVpX; | |
|     mVpY = other.mVpY; | |
|     mVpWidth = other.mVpWidth; | |
|     mVpHeight = other.mVpHeight; | |
| 
 | |
|     mTarget = other.mTarget; | |
|     mFovY = other.mFovY; | |
|     mNearDist = other.mNearDist; | |
|     mFarDist = other.mFarDist; | |
|      | |
|     mViewMatrix = other.mViewMatrix; | |
|     mProjectionMatrix = other.mProjectionMatrix; | |
| 
 | |
|     return *this; | |
| } | |
| 
 | |
| Camera::Camera(const Camera& other) | |
| { | |
|     *this = other; | |
| } | |
| 
 | |
| Camera::~Camera() | |
| { | |
| } | |
| 
 | |
| 
 | |
| void Camera::setViewport(uint offsetx, uint offsety, uint width, uint height) | |
| { | |
|     mVpX = offsetx; | |
|     mVpY = offsety; | |
|     mVpWidth = width; | |
|     mVpHeight = height; | |
|      | |
|     mProjIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::setViewport(uint width, uint height) | |
| { | |
|     mVpWidth = width; | |
|     mVpHeight = height; | |
|      | |
|     mProjIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::setFovY(float value) | |
| { | |
|     mFovY = value; | |
|     mProjIsUptodate = false; | |
| } | |
| 
 | |
| Vector3f Camera::direction(void) const | |
| { | |
|     return - (orientation() * Vector3f::UnitZ()); | |
| } | |
| Vector3f Camera::up(void) const | |
| { | |
|     return orientation() * Vector3f::UnitY(); | |
| } | |
| Vector3f Camera::right(void) const | |
| { | |
|     return orientation() * Vector3f::UnitX(); | |
| } | |
| 
 | |
| void Camera::setDirection(const Vector3f& newDirection) | |
| { | |
|     // TODO implement it computing the rotation between newDirection and current dir ? | |
|     Vector3f up = this->up(); | |
|      | |
|     Matrix3f camAxes; | |
| 
 | |
|     camAxes.col(2) = (-newDirection).normalized(); | |
|     camAxes.col(0) = up.cross( camAxes.col(2) ).normalized(); | |
|     camAxes.col(1) = camAxes.col(2).cross( camAxes.col(0) ).normalized(); | |
|     setOrientation(Quaternionf(camAxes)); | |
|      | |
|     mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::setTarget(const Vector3f& target) | |
| { | |
|     mTarget = target; | |
|     if (!mTarget.isApprox(position())) | |
|     { | |
|         Vector3f newDirection = mTarget - position(); | |
|         setDirection(newDirection.normalized()); | |
|     } | |
| } | |
| 
 | |
| void Camera::setPosition(const Vector3f& p) | |
| { | |
|     mFrame.position = p; | |
|     mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::setOrientation(const Quaternionf& q) | |
| { | |
|     mFrame.orientation = q; | |
|     mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::setFrame(const Frame& f) | |
| { | |
|   mFrame = f; | |
|   mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::rotateAroundTarget(const Quaternionf& q) | |
| { | |
|     Matrix4f mrot, mt, mtm; | |
|      | |
|     // update the transform matrix | |
|     updateViewMatrix(); | |
|     Vector3f t = mViewMatrix * mTarget; | |
| 
 | |
|     mViewMatrix = Translation3f(t) | |
|                 * q | |
|                 * Translation3f(-t) | |
|                 * mViewMatrix; | |
|      | |
|     Quaternionf qa(mViewMatrix.linear()); | |
|     qa = qa.conjugate(); | |
|     setOrientation(qa); | |
|     setPosition(- (qa * mViewMatrix.translation()) ); | |
| 
 | |
|     mViewIsUptodate = true; | |
| } | |
| 
 | |
| void Camera::localRotate(const Quaternionf& q) | |
| { | |
|     float dist = (position() - mTarget).norm(); | |
|     setOrientation(orientation() * q); | |
|     mTarget = position() + dist * direction(); | |
|     mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::zoom(float d) | |
| { | |
|     float dist = (position() - mTarget).norm(); | |
|     if(dist > d) | |
|     { | |
|         setPosition(position() + direction() * d); | |
|         mViewIsUptodate = false; | |
|     } | |
| } | |
| 
 | |
| void Camera::localTranslate(const Vector3f& t) | |
| { | |
|   Vector3f trans = orientation() * t; | |
|   setPosition( position() + trans ); | |
|   setTarget( mTarget + trans ); | |
| 
 | |
|   mViewIsUptodate = false; | |
| } | |
| 
 | |
| void Camera::updateViewMatrix(void) const | |
| { | |
|     if(!mViewIsUptodate) | |
|     { | |
|         Quaternionf q = orientation().conjugate(); | |
|         mViewMatrix.linear() = q.toRotationMatrix(); | |
|         mViewMatrix.translation() = - (mViewMatrix.linear() * position()); | |
| 
 | |
|         mViewIsUptodate = true; | |
|     } | |
| } | |
| 
 | |
| const Affine3f& Camera::viewMatrix(void) const | |
| { | |
|   updateViewMatrix(); | |
|   return mViewMatrix; | |
| } | |
| 
 | |
| void Camera::updateProjectionMatrix(void) const | |
| { | |
|   if(!mProjIsUptodate) | |
|   { | |
|     mProjectionMatrix.setIdentity(); | |
|     float aspect = float(mVpWidth)/float(mVpHeight); | |
|     float theta = mFovY*0.5; | |
|     float range = mFarDist - mNearDist; | |
|     float invtan = 1./tan(theta); | |
| 
 | |
|     mProjectionMatrix(0,0) = invtan / aspect; | |
|     mProjectionMatrix(1,1) = invtan; | |
|     mProjectionMatrix(2,2) = -(mNearDist + mFarDist) / range; | |
|     mProjectionMatrix(3,2) = -1; | |
|     mProjectionMatrix(2,3) = -2 * mNearDist * mFarDist / range; | |
|     mProjectionMatrix(3,3) = 0; | |
|      | |
|     mProjIsUptodate = true; | |
|   } | |
| } | |
| 
 | |
| const Matrix4f& Camera::projectionMatrix(void) const | |
| { | |
|   updateProjectionMatrix(); | |
|   return mProjectionMatrix; | |
| } | |
| 
 | |
| void Camera::activateGL(void) | |
| { | |
|   glViewport(vpX(), vpY(), vpWidth(), vpHeight()); | |
|   gpu.loadMatrix(projectionMatrix(),GL_PROJECTION); | |
|   gpu.loadMatrix(viewMatrix().matrix(),GL_MODELVIEW); | |
| } | |
| 
 | |
| 
 | |
| Vector3f Camera::unProject(const Vector2f& uv, float depth) const | |
| { | |
|     Matrix4f inv = mViewMatrix.inverse().matrix(); | |
|     return unProject(uv, depth, inv); | |
| } | |
| 
 | |
| Vector3f Camera::unProject(const Vector2f& uv, float depth, const Matrix4f& invModelview) const | |
| { | |
|     updateViewMatrix(); | |
|     updateProjectionMatrix(); | |
|      | |
|     Vector3f a(2.*uv.x()/float(mVpWidth)-1., 2.*uv.y()/float(mVpHeight)-1., 1.); | |
|     a.x() *= depth/mProjectionMatrix(0,0); | |
|     a.y() *= depth/mProjectionMatrix(1,1); | |
|     a.z() = -depth; | |
|     // FIXME /\/| | |
|     Vector4f b = invModelview * Vector4f(a.x(), a.y(), a.z(), 1.); | |
|     return Vector3f(b.x(), b.y(), b.z()); | |
| }
 |