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 Eigen;
							 | 
						|
								
							 | 
						|
								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());
							 | 
						|
								}
							 |