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