diff options
Diffstat (limited to 'eigen/demos/opengl/camera.cpp')
-rw-r--r-- | eigen/demos/opengl/camera.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/eigen/demos/opengl/camera.cpp b/eigen/demos/opengl/camera.cpp new file mode 100644 index 0000000..8a2344c --- /dev/null +++ b/eigen/demos/opengl/camera.cpp @@ -0,0 +1,264 @@ +// 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()); +} |