mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-09-16 03:13:14 +08:00
started a small OpenGL demo making use of Eigen's geometry features
This commit is contained in:
parent
12e9de4abb
commit
31c33b9ed4
@ -1,3 +1,4 @@
|
||||
IF(BUILD_DEMOS)
|
||||
ADD_SUBDIRECTORY(mandelbrot)
|
||||
ADD_SUBDIRECTORY(opengl)
|
||||
ENDIF(BUILD_DEMOS)
|
||||
|
17
demos/opengl/CMakeLists.txt
Normal file
17
demos/opengl/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
FIND_PACKAGE(Qt4 REQUIRED)
|
||||
|
||||
set(QT_USE_QTOPENGL TRUE)
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
INCLUDE_DIRECTORIES( ${QT_INCLUDE_DIR} )
|
||||
|
||||
SET(quaternion_demo_SRCS gpuhelper.cpp camera.cpp trackball.cpp quaternion_demo.cpp)
|
||||
|
||||
QT4_AUTOMOC(${quaternion_demo_SRCS})
|
||||
|
||||
ADD_EXECUTABLE(quaternion_demo ${quaternion_demo_SRCS})
|
||||
|
||||
TARGET_LINK_LIBRARIES(quaternion_demo ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY})
|
13
demos/opengl/README
Normal file
13
demos/opengl/README
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
Navigation:
|
||||
left button: rotate around the target
|
||||
middle button: zoom
|
||||
left button + ctrl quake rotate (rotate around camera position)
|
||||
middle button + ctrl walk (progress along camera's z direction)
|
||||
left button: pan (translate in the XY camera's plane)
|
||||
|
||||
R : move the camera to initial position
|
||||
A : start/stop animation
|
||||
C : clear the animation
|
||||
G : add a key frame
|
||||
|
284
demos/opengl/camera.cpp
Normal file
284
demos/opengl/camera.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#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(50.));
|
||||
|
||||
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::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::localRotate(float dTheta, float dPhi)
|
||||
{
|
||||
float dist = (position() - mTarget).norm();
|
||||
|
||||
setOrientation( AngleAxisf(dTheta, up())
|
||||
* AngleAxisf(dPhi, right())
|
||||
* orientation());
|
||||
mTarget = position() + dist * direction();
|
||||
|
||||
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 Transform3f& 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();
|
||||
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());
|
||||
}
|
130
demos/opengl/camera.h
Normal file
130
demos/opengl/camera.h
Normal file
@ -0,0 +1,130 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_CAMERA_H
|
||||
#define EIGEN_CAMERA_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <QObject>
|
||||
// #include <frame.h>
|
||||
|
||||
class Frame
|
||||
{
|
||||
public:
|
||||
inline Frame(const Eigen::Vector3f& pos = Eigen::Vector3f::Zero(),
|
||||
const Eigen::Quaternionf& o = Eigen::Quaternionf())
|
||||
: orientation(o), position(pos)
|
||||
{}
|
||||
Frame lerp(float alpha, const Frame& other) const
|
||||
{
|
||||
return Frame((1.f-alpha)*position + alpha * other.position,
|
||||
orientation.slerp(alpha,other.orientation));
|
||||
}
|
||||
|
||||
Eigen::Quaternionf orientation;
|
||||
Eigen::Vector3f position;
|
||||
};
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
|
||||
Camera(void);
|
||||
|
||||
Camera(const Camera& other);
|
||||
|
||||
virtual ~Camera();
|
||||
|
||||
Camera& operator=(const Camera& other);
|
||||
|
||||
void setViewport(uint offsetx, uint offsety, uint width, uint height);
|
||||
void setViewport(uint width, uint height);
|
||||
|
||||
inline uint vpX(void) const { return mVpX; }
|
||||
inline uint vpY(void) const { return mVpY; }
|
||||
inline uint vpWidth(void) const { return mVpWidth; }
|
||||
inline uint vpHeight(void) const { return mVpHeight; }
|
||||
|
||||
inline float fovY(void) const { return mFovY; }
|
||||
void setFovY(float value);
|
||||
|
||||
void setPosition(const Eigen::Vector3f& pos);
|
||||
inline const Eigen::Vector3f& position(void) const { return mFrame.position; }
|
||||
|
||||
void setOrientation(const Eigen::Quaternionf& q);
|
||||
inline const Eigen::Quaternionf& orientation(void) const { return mFrame.orientation; }
|
||||
|
||||
void setFrame(const Frame& f);
|
||||
const Frame& frame(void) const { return mFrame; }
|
||||
|
||||
void setDirection(const Eigen::Vector3f& newDirection);
|
||||
Eigen::Vector3f direction(void) const;
|
||||
void setUp(const Eigen::Vector3f& vectorUp);
|
||||
Eigen::Vector3f up(void) const;
|
||||
Eigen::Vector3f right(void) const;
|
||||
|
||||
void setTarget(const Eigen::Vector3f& target);
|
||||
inline const Eigen::Vector3f& target(void) { return mTarget; }
|
||||
|
||||
const Eigen::Transform3f& viewMatrix(void) const;
|
||||
const Eigen::Matrix4f& projectionMatrix(void) const;
|
||||
|
||||
void rotateAroundTarget(const Eigen::Quaternionf& q);
|
||||
void zoom(float d);
|
||||
|
||||
void localTranslate(const Eigen::Vector3f& t);
|
||||
void localRotate(float dTheta, float dPhi);
|
||||
|
||||
/** Setup OpenGL matrices and viewport */
|
||||
void activateGL(void);
|
||||
|
||||
Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth, const Eigen::Matrix4f& invModelview) const;
|
||||
Eigen::Vector3f unProject(const Eigen::Vector2f& uv, float depth) const;
|
||||
|
||||
protected:
|
||||
void updateViewMatrix(void) const;
|
||||
void updateProjectionMatrix(void) const;
|
||||
|
||||
protected:
|
||||
|
||||
uint mVpX, mVpY;
|
||||
uint mVpWidth, mVpHeight;
|
||||
|
||||
Frame mFrame;
|
||||
|
||||
mutable Eigen::Transform3f mViewMatrix;
|
||||
mutable Eigen::Matrix4f mProjectionMatrix;
|
||||
|
||||
mutable bool mViewIsUptodate;
|
||||
mutable bool mProjIsUptodate;
|
||||
|
||||
// used by rotateAroundTarget
|
||||
Eigen::Vector3f mTarget;
|
||||
|
||||
float mFovY;
|
||||
float mNearDist;
|
||||
float mFarDist;
|
||||
};
|
||||
|
||||
#endif // EIGEN_CAMERA_H
|
211
demos/opengl/gpuhelper.cpp
Normal file
211
demos/opengl/gpuhelper.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "gpuhelper.h"
|
||||
#include <GL/glu.h>
|
||||
// PLEASE don't look at this old code... ;)
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
GpuHelper gpu;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// icosahedron
|
||||
//--------------------------------------------------------------------------------
|
||||
#define X .525731112119133606
|
||||
#define Z .850650808352039932
|
||||
|
||||
static GLfloat vdata[12][3] = {
|
||||
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
|
||||
{0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
|
||||
{Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
|
||||
};
|
||||
|
||||
static GLint tindices[20][3] = {
|
||||
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
|
||||
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
|
||||
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
|
||||
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
GpuHelper::GpuHelper()
|
||||
{
|
||||
mVpWidth = mVpHeight = 0;
|
||||
mCurrentMatrixTarget = 0;
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
GpuHelper::~GpuHelper()
|
||||
{
|
||||
}
|
||||
|
||||
void GpuHelper::pushProjectionMode2D(ProjectionMode2D pm)
|
||||
{
|
||||
// switch to 2D projection
|
||||
pushMatrix(Matrix4f::Identity(),GL_PROJECTION);
|
||||
|
||||
if(pm==PM_Normalized)
|
||||
{
|
||||
//glOrtho(-1., 1., -1., 1., 0., 1.);
|
||||
}
|
||||
else if(pm==PM_Viewport)
|
||||
{
|
||||
GLint vp[4];
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
glOrtho(0., vp[2], 0., vp[3], -1., 1.);
|
||||
}
|
||||
|
||||
pushMatrix(Matrix4f::Identity(),GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::popProjectionMode2D(void)
|
||||
{
|
||||
popMatrix(GL_PROJECTION);
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect /* = 50.*/)
|
||||
{
|
||||
static GLUquadricObj *cylindre = gluNewQuadric();
|
||||
glColor4fv(color.data());
|
||||
float length = vec.norm();
|
||||
pushMatrix(GL_MODELVIEW);
|
||||
glTranslatef(position.x(), position.y(), position.z());
|
||||
Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
|
||||
ax.normalize();
|
||||
Vector3f tmp = vec;
|
||||
tmp.normalize();
|
||||
float angle = 180.f/M_PI * acos(tmp.z());
|
||||
if (angle>1e-3)
|
||||
glRotatef(angle, ax.x(), ax.y(), ax.z());
|
||||
gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
|
||||
glTranslatef(0.0,0.0,0.8*length);
|
||||
gluCylinder(cylindre, 2.0*length/aspect, 0.0, 0.2*length, 10, 10);
|
||||
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect)
|
||||
{
|
||||
static GLUquadricObj *cylindre = gluNewQuadric();
|
||||
glColor4fv(color.data());
|
||||
float length = vec.norm();
|
||||
pushMatrix(GL_MODELVIEW);
|
||||
glTranslatef(position.x(), position.y(), position.z());
|
||||
Vector3f ax = Matrix3f::Identity().col(2).cross(vec);
|
||||
ax.normalize();
|
||||
Vector3f tmp = vec;
|
||||
tmp.normalize();
|
||||
float angle = 180.f/M_PI * acos(tmp.z());
|
||||
if (angle>1e-3)
|
||||
glRotatef(angle, ax.x(), ax.y(), ax.z());
|
||||
gluCylinder(cylindre, length/aspect, length/aspect, 0.8*length, 10, 10);
|
||||
glTranslatef(0.0,0.0,0.8*length);
|
||||
glScalef(4.0*length/aspect,4.0*length/aspect,4.0*length/aspect);
|
||||
drawUnitCube();
|
||||
popMatrix(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void GpuHelper::drawUnitCube(void)
|
||||
{
|
||||
static float vertices[][3] = {
|
||||
{-0.5,-0.5,-0.5},
|
||||
{ 0.5,-0.5,-0.5},
|
||||
{-0.5, 0.5,-0.5},
|
||||
{ 0.5, 0.5,-0.5},
|
||||
{-0.5,-0.5, 0.5},
|
||||
{ 0.5,-0.5, 0.5},
|
||||
{-0.5, 0.5, 0.5},
|
||||
{ 0.5, 0.5, 0.5}};
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0,0,-1); glVertex3fv(vertices[0]); glVertex3fv(vertices[2]); glVertex3fv(vertices[3]); glVertex3fv(vertices[1]);
|
||||
glNormal3f(0,0, 1); glVertex3fv(vertices[4]); glVertex3fv(vertices[5]); glVertex3fv(vertices[7]); glVertex3fv(vertices[6]);
|
||||
glNormal3f(0,-1,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[1]); glVertex3fv(vertices[5]); glVertex3fv(vertices[4]);
|
||||
glNormal3f(0, 1,0); glVertex3fv(vertices[2]); glVertex3fv(vertices[6]); glVertex3fv(vertices[7]); glVertex3fv(vertices[3]);
|
||||
glNormal3f(-1,0,0); glVertex3fv(vertices[0]); glVertex3fv(vertices[4]); glVertex3fv(vertices[6]); glVertex3fv(vertices[2]);
|
||||
glNormal3f( 1,0,0); glVertex3fv(vertices[1]); glVertex3fv(vertices[3]); glVertex3fv(vertices[7]); glVertex3fv(vertices[5]);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void _normalize(float* v)
|
||||
{
|
||||
float s = 1.f/ei_sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
for (uint k=0; k<3; ++k)
|
||||
v[k] *= s;
|
||||
}
|
||||
|
||||
void _subdivide(float *v1, float *v2, float *v3, long depth)
|
||||
{
|
||||
GLfloat v12[3], v23[3], v31[3];
|
||||
GLint i;
|
||||
|
||||
if (depth == 0) {
|
||||
//drawtriangle(v1, v2, v3);
|
||||
glNormal3fv(v1);
|
||||
glVertex3fv(v1);
|
||||
|
||||
glNormal3fv(v3);
|
||||
glVertex3fv(v3);
|
||||
|
||||
glNormal3fv(v2);
|
||||
glVertex3fv(v2);
|
||||
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
v12[i] = v1[i]+v2[i];
|
||||
v23[i] = v2[i]+v3[i];
|
||||
v31[i] = v3[i]+v1[i];
|
||||
}
|
||||
_normalize(v12);
|
||||
_normalize(v23);
|
||||
_normalize(v31);
|
||||
_subdivide(v1, v12, v31, depth-1);
|
||||
_subdivide(v2, v23, v12, depth-1);
|
||||
_subdivide(v3, v31, v23, depth-1);
|
||||
_subdivide(v12, v23, v31, depth-1);
|
||||
}
|
||||
|
||||
void GpuHelper::drawUnitLightSphere(int level)
|
||||
{
|
||||
static int dlId = 0;
|
||||
if (!dlId)
|
||||
{
|
||||
dlId = glGenLists(1);
|
||||
glNewList(dlId, GL_COMPILE);
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
_subdivide(&vdata[tindices[i][0]][0], &vdata[tindices[i][1]][0], &vdata[tindices[i][2]][0], 1);
|
||||
}
|
||||
glEnd();
|
||||
glEndList();
|
||||
}
|
||||
glCallList(dlId);
|
||||
}
|
||||
|
||||
|
222
demos/opengl/gpuhelper.h
Normal file
222
demos/opengl/gpuhelper.h
Normal file
@ -0,0 +1,222 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_GPUHELPER_H
|
||||
#define EIGEN_GPUHELPER_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include <GL/gl.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
typedef Vector4f Color;
|
||||
|
||||
class GpuHelper
|
||||
{
|
||||
public:
|
||||
|
||||
GpuHelper();
|
||||
|
||||
~GpuHelper();
|
||||
|
||||
enum ProjectionMode2D { PM_Normalized = 1, PM_Viewport = 2 };
|
||||
void pushProjectionMode2D(ProjectionMode2D pm);
|
||||
void popProjectionMode2D();
|
||||
|
||||
/** Multiply the OpenGL matrix \a matrixTarget by the matrix \a mat.
|
||||
Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
|
||||
and does a proper call to the right glMultMatrix*() function according to the scalar type
|
||||
and storage order.
|
||||
\warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
|
||||
\sa Matrix, loadMatrix(), forceMatrixMode()
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
void multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
/** Load the matrix \a mat to the OpenGL matrix \a matrixTarget.
|
||||
Essentially, this helper function automatically calls glMatrixMode(matrixTarget) if required
|
||||
and does a proper call to the right glLoadMatrix*() or glLoadIdentity() function according to the scalar type
|
||||
and storage order.
|
||||
\warning glMatrixMode() must never be called directly. If your're unsure, use forceMatrixMode().
|
||||
\sa Matrix, multMatrix(), forceMatrixMode()
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
void loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void loadMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::ei_scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget);
|
||||
|
||||
/** Make the matrix \a matrixTarget the current OpenGL matrix target.
|
||||
Call this function before loadMatrix() or multMatrix() if you cannot guarrantee that glMatrixMode()
|
||||
has never been called after the last loadMatrix() or multMatrix() calls.
|
||||
\todo provides a debug mode checking the sanity of the cached matrix mode.
|
||||
*/
|
||||
inline void forceMatrixTarget(GLenum matrixTarget) {glMatrixMode(mCurrentMatrixTarget=matrixTarget);}
|
||||
|
||||
inline void setMatrixTarget(GLenum matrixTarget);
|
||||
|
||||
/** Push the OpenGL matrix \a matrixTarget and load \a mat.
|
||||
*/
|
||||
template<typename Scalar, int _Flags>
|
||||
inline void pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget);
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void pushMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::ei_scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget);
|
||||
|
||||
/** Push and clone the OpenGL matrix \a matrixTarget
|
||||
*/
|
||||
inline void pushMatrix(GLenum matrixTarget);
|
||||
|
||||
/** Pop the OpenGL matrix \a matrixTarget
|
||||
*/
|
||||
inline void popMatrix(GLenum matrixTarget);
|
||||
|
||||
void drawVector(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
|
||||
void drawVectorBox(const Vector3f& position, const Vector3f& vec, const Color& color, float aspect = 50.);
|
||||
void drawUnitCube(void);
|
||||
void drawUnitLightSphere(int level=0);
|
||||
|
||||
/// draw the \a nofElement first elements
|
||||
inline void draw(GLenum mode, uint nofElement);
|
||||
|
||||
/// draw a range of elements
|
||||
inline void draw(GLenum mode, uint start, uint end);
|
||||
|
||||
/// draw an indexed subset
|
||||
inline void draw(GLenum mode, const std::vector<uint>* pIndexes);
|
||||
|
||||
protected:
|
||||
|
||||
void update(void);
|
||||
|
||||
GLuint mColorBufferId;
|
||||
int mVpWidth, mVpHeight;
|
||||
GLenum mCurrentMatrixTarget;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
/** Singleton shortcut
|
||||
*/
|
||||
extern GpuHelper gpu;
|
||||
|
||||
|
||||
/** \internal
|
||||
*/
|
||||
template<bool RowMajor, int _Flags> struct GlMatrixHelper;
|
||||
|
||||
template<int _Flags> struct GlMatrixHelper<false,_Flags>
|
||||
{
|
||||
static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.data()); }
|
||||
static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.data()); }
|
||||
static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.data()); }
|
||||
static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.data()); }
|
||||
};
|
||||
|
||||
template<int _Flags> struct GlMatrixHelper<true,_Flags>
|
||||
{
|
||||
static void loadMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glLoadMatrixf(mat.transpose().eval().data()); }
|
||||
static void loadMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glLoadMatrixd(mat.transpose().eval().data()); }
|
||||
static void multMatrix(const Matrix<float, 4,4, _Flags, 4,4>& mat) { glMultMatrixf(mat.transpose().eval().data()); }
|
||||
static void multMatrix(const Matrix<double,4,4, _Flags, 4,4>& mat) { glMultMatrixd(mat.transpose().eval().data()); }
|
||||
};
|
||||
|
||||
inline void GpuHelper::setMatrixTarget(GLenum matrixTarget)
|
||||
{
|
||||
if (matrixTarget != mCurrentMatrixTarget)
|
||||
glMatrixMode(mCurrentMatrixTarget=matrixTarget);
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
void GpuHelper::multMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
GlMatrixHelper<_Flags&Eigen::RowMajorBit, _Flags>::multMatrix(mat);
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void GpuHelper::loadMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::ei_scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
void GpuHelper::loadMatrix(const Eigen::Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
GlMatrixHelper<(_Flags&Eigen::RowMajorBit)!=0, _Flags>::loadMatrix(mat);
|
||||
}
|
||||
|
||||
inline void GpuHelper::pushMatrix(GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glPushMatrix();
|
||||
}
|
||||
|
||||
template<typename Scalar, int _Flags>
|
||||
inline void GpuHelper::pushMatrix(const Matrix<Scalar,4,4, _Flags, 4,4>& mat, GLenum matrixTarget)
|
||||
{
|
||||
pushMatrix(matrixTarget);
|
||||
GlMatrixHelper<_Flags&Eigen::RowMajorBit,_Flags>::loadMatrix(mat);
|
||||
}
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
void GpuHelper::pushMatrix(
|
||||
const Eigen::CwiseNullaryOp<Eigen::ei_scalar_identity_op<Scalar>,Derived>&,
|
||||
GLenum matrixTarget)
|
||||
{
|
||||
pushMatrix(matrixTarget);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
inline void GpuHelper::popMatrix(GLenum matrixTarget)
|
||||
{
|
||||
setMatrixTarget(matrixTarget);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, uint nofElement)
|
||||
{
|
||||
glDrawArrays(mode, 0, nofElement);
|
||||
}
|
||||
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, const std::vector<uint>* pIndexes)
|
||||
{
|
||||
glDrawElements(mode, pIndexes->size(), GL_UNSIGNED_INT, &(pIndexes->front()));
|
||||
}
|
||||
|
||||
inline void GpuHelper::draw(GLenum mode, uint start, uint end)
|
||||
{
|
||||
glDrawArrays(mode, start, end-start);
|
||||
}
|
||||
|
||||
#endif // EIGEN_GPUHELPER_H
|
315
demos/opengl/quaternion_demo.cpp
Normal file
315
demos/opengl/quaternion_demo.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "quaternion_demo.h"
|
||||
|
||||
#include <Eigen/Array>
|
||||
#include <Eigen/QR>
|
||||
#include <Eigen/LU>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QInputDialog>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
|
||||
|
||||
template<typename T> T lerp(float t, const T& a, const T& b)
|
||||
{
|
||||
return a*(1-t) + b*t;
|
||||
}
|
||||
|
||||
template<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
|
||||
{ return a.slerp(t,b); }
|
||||
|
||||
template<> AngleAxisf lerp(float t, const AngleAxisf& a, const AngleAxisf& b)
|
||||
{
|
||||
return AngleAxisf(lerp(t,a.angle(),b.angle()),
|
||||
lerp(t,a.axis(),b.axis()).normalized());
|
||||
}
|
||||
|
||||
template<typename OrientationType>
|
||||
inline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b)
|
||||
{
|
||||
return Frame(::lerp(alpha,a.position,b.position),
|
||||
Quaternionf(::lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation))));
|
||||
}
|
||||
|
||||
QuaternionDemo::QuaternionDemo()
|
||||
{
|
||||
mAnimate = false;
|
||||
mTrackMode = TM_NO_TRACK;
|
||||
mTrackball.setCamera(&mCamera);
|
||||
}
|
||||
|
||||
void QuaternionDemo::grabFrame(void)
|
||||
{
|
||||
// ask user for a time
|
||||
bool ok = false;
|
||||
double t = 0;
|
||||
if (!m_timeline.empty())
|
||||
t = (--m_timeline.end())->first + 1.;
|
||||
t = QInputDialog::getDouble(this, "Eigen's QuaternionDemo", "time value: ",
|
||||
t, 0, 1e3, 1, &ok);
|
||||
if (ok)
|
||||
{
|
||||
Frame aux;
|
||||
aux.orientation = mCamera.viewMatrix().linear();
|
||||
aux.position = mCamera.viewMatrix().translation();
|
||||
m_timeline[t] = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void QuaternionDemo::drawScene()
|
||||
{
|
||||
float length = 50;
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitX(), Color(1,0,0,1));
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitY(), Color(0,1,0,1));
|
||||
gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1));
|
||||
}
|
||||
|
||||
void QuaternionDemo::drawPath()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QuaternionDemo::animate()
|
||||
{
|
||||
m_alpha += double(m_timer.interval()) * 1e-3;
|
||||
|
||||
TimeLine::const_iterator hi = m_timeline.upper_bound(m_alpha);
|
||||
TimeLine::const_iterator lo = hi;
|
||||
--lo;
|
||||
|
||||
Frame currentFrame;
|
||||
|
||||
if(hi==m_timeline.end())
|
||||
{
|
||||
// end
|
||||
currentFrame = lo->second;
|
||||
stopAnimation();
|
||||
}
|
||||
else if(hi==m_timeline.begin())
|
||||
{
|
||||
// start
|
||||
currentFrame = hi->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
float s = (m_alpha - lo->first)/(hi->first - lo->first);
|
||||
currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
|
||||
currentFrame.orientation.coeffs().normalize();
|
||||
}
|
||||
|
||||
currentFrame.orientation = currentFrame.orientation.inverse();
|
||||
currentFrame.position = - (currentFrame.orientation * currentFrame.position);
|
||||
mCamera.setFrame(currentFrame);
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void QuaternionDemo::keyPressEvent(QKeyEvent * e)
|
||||
{
|
||||
switch(e->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
mCamera.zoom(2);
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
mCamera.zoom(-2);
|
||||
break;
|
||||
// add a frame
|
||||
case Qt::Key_G:
|
||||
grabFrame();
|
||||
break;
|
||||
// clear the time line
|
||||
case Qt::Key_C:
|
||||
m_timeline.clear();
|
||||
break;
|
||||
// move the camera to initial pos
|
||||
case Qt::Key_R:
|
||||
{
|
||||
if (mAnimate)
|
||||
stopAnimation();
|
||||
m_timeline.clear();
|
||||
float duration = 3/*AngleAxisf(mCamera.orientation().inverse()
|
||||
* mInitFrame.orientation).angle()*/;
|
||||
Frame aux = mCamera.frame();
|
||||
aux.orientation = aux.orientation.inverse();
|
||||
aux.position = mCamera.viewMatrix().translation();
|
||||
m_timeline[0] = aux;
|
||||
m_timeline[duration] = mInitFrame;
|
||||
}
|
||||
// start/stop the animation
|
||||
case Qt::Key_A:
|
||||
if (mAnimate)
|
||||
{
|
||||
stopAnimation();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_alpha = 0;
|
||||
connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
|
||||
m_timer.start(1000/30);
|
||||
mAnimate = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void QuaternionDemo::stopAnimation()
|
||||
{
|
||||
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
|
||||
m_timer.stop();
|
||||
mAnimate = false;
|
||||
m_alpha = 0;
|
||||
}
|
||||
|
||||
void QuaternionDemo::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
|
||||
switch(e->button())
|
||||
{
|
||||
case Qt::LeftButton:
|
||||
if(e->modifiers()&Qt::ControlModifier)
|
||||
{
|
||||
mTrackMode = TM_QUAKE_ROTATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mTrackMode = TM_ROTATE_AROUND;
|
||||
mTrackball.reset();
|
||||
mTrackball.track(mMouseCoords);
|
||||
}
|
||||
break;
|
||||
case Qt::MidButton:
|
||||
if(e->modifiers()&Qt::ControlModifier)
|
||||
mTrackMode = TM_QUAKE_WALK;
|
||||
else
|
||||
mTrackMode = TM_ZOOM;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
mTrackMode = TM_QUAKE_PAN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void QuaternionDemo::mouseReleaseEvent(QMouseEvent*)
|
||||
{
|
||||
mTrackMode = TM_NO_TRACK;
|
||||
updateGL();
|
||||
}
|
||||
|
||||
void QuaternionDemo::mouseMoveEvent(QMouseEvent* e)
|
||||
{
|
||||
// tracking
|
||||
if(mTrackMode != TM_NO_TRACK)
|
||||
{
|
||||
float dx = float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
|
||||
float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
|
||||
|
||||
if(e->modifiers() & Qt::ShiftModifier)
|
||||
{
|
||||
dx *= 10.;
|
||||
dy *= 10.;
|
||||
}
|
||||
|
||||
switch(mTrackMode)
|
||||
{
|
||||
case TM_ROTATE_AROUND :
|
||||
mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
|
||||
break;
|
||||
case TM_ZOOM :
|
||||
mCamera.zoom(dy*50);
|
||||
break;
|
||||
case TM_QUAKE_WALK :
|
||||
mCamera.localTranslate(Vector3f(0, 0, dy*100));
|
||||
break;
|
||||
case TM_QUAKE_PAN :
|
||||
mCamera.localTranslate(Vector3f(dx*100, dy*100, 0));
|
||||
break;
|
||||
case TM_QUAKE_ROTATE :
|
||||
mCamera.localRotate(-dx*M_PI, dy*M_PI);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
updateGL();
|
||||
}
|
||||
|
||||
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
|
||||
}
|
||||
|
||||
void QuaternionDemo::paintGL()
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
|
||||
// Clear buffers
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
mCamera.activateGL();
|
||||
|
||||
drawScene();
|
||||
}
|
||||
|
||||
void QuaternionDemo::initializeGL()
|
||||
{
|
||||
glClearColor(1., 1., 1., 0.);
|
||||
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
|
||||
glDepthMask(GL_TRUE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
|
||||
mInitFrame.orientation = mCamera.viewMatrix().linear();
|
||||
mInitFrame.position = mCamera.viewMatrix().translation();
|
||||
}
|
||||
|
||||
void QuaternionDemo::resizeGL(int width, int height)
|
||||
{
|
||||
mCamera.setViewport(width,height);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QuaternionDemo demo;
|
||||
demo.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "quaternion_demo.moc"
|
90
demos/opengl/quaternion_demo.h
Normal file
90
demos/opengl/quaternion_demo.h
Normal file
@ -0,0 +1,90 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_QUATERNION_DEMO_H
|
||||
#define EIGEN_QUATERNION_DEMO_H
|
||||
|
||||
#include "gpuhelper.h"
|
||||
#include "camera.h"
|
||||
#include "trackball.h"
|
||||
#include <map>
|
||||
#include <QTimer>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtOpenGL/QGLWidget>
|
||||
|
||||
class QuaternionDemo : public QGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
typedef std::map<float,Frame> TimeLine;
|
||||
TimeLine m_timeline;
|
||||
Frame lerpFrame(float t);
|
||||
|
||||
Frame mInitFrame;
|
||||
bool mAnimate;
|
||||
float m_alpha;
|
||||
|
||||
|
||||
enum TrackMode {
|
||||
TM_NO_TRACK=0, TM_ROTATE_AROUND, TM_ZOOM,
|
||||
TM_QUAKE_ROTATE, TM_QUAKE_WALK, TM_QUAKE_PAN
|
||||
};
|
||||
|
||||
Camera mCamera;
|
||||
TrackMode mTrackMode;
|
||||
Vector2i mMouseCoords;
|
||||
Trackball mTrackball;
|
||||
|
||||
QTimer m_timer;
|
||||
|
||||
void setupCamera();
|
||||
|
||||
protected slots:
|
||||
|
||||
virtual void animate(void);
|
||||
virtual void drawScene(void);
|
||||
virtual void drawPath(void);
|
||||
|
||||
virtual void grabFrame(void);
|
||||
virtual void stopAnimation();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void initializeGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
virtual void paintGL();
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
virtual void mousePressEvent(QMouseEvent * e);
|
||||
virtual void mouseReleaseEvent(QMouseEvent * e);
|
||||
virtual void mouseMoveEvent(QMouseEvent * e);
|
||||
virtual void keyPressEvent(QKeyEvent * e);
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
QuaternionDemo();
|
||||
~QuaternionDemo() { }
|
||||
};
|
||||
|
||||
#endif // EIGEN_QUATERNION_DEMO_H
|
72
demos/opengl/trackball.cpp
Normal file
72
demos/opengl/trackball.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "trackball.h"
|
||||
#include "camera.h"
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
void Trackball::track(const Vector2i& newPoint2D)
|
||||
{
|
||||
if (mpCamera==0)
|
||||
return;
|
||||
Vector3f newPoint3D;
|
||||
bool newPointOk = mapToSphere(newPoint2D, newPoint3D);
|
||||
|
||||
if (mLastPointOk && newPointOk)
|
||||
{
|
||||
Vector3f axis = mLastPoint3D.cross(newPoint3D).normalized();
|
||||
float cos_angle = mLastPoint3D.dot(newPoint3D);
|
||||
if ( ei_abs(cos_angle) < 1.0 )
|
||||
{
|
||||
float angle = 2.0 * acos(cos_angle);
|
||||
mpCamera->rotateAroundTarget(Quaternionf(AngleAxisf(angle, axis)));
|
||||
}
|
||||
}
|
||||
|
||||
mLastPoint2D = newPoint2D;
|
||||
mLastPoint3D = newPoint3D;
|
||||
mLastPointOk = newPointOk;
|
||||
}
|
||||
|
||||
bool Trackball::mapToSphere(const Vector2i& p2, Vector3f& v3)
|
||||
{
|
||||
if ((p2.x() >= 0) && (p2.x() <= int(mpCamera->vpWidth())) &&
|
||||
(p2.y() >= 0) && (p2.y() <= int(mpCamera->vpHeight())) )
|
||||
{
|
||||
double x = (double)(p2.x() - 0.5*mpCamera->vpWidth()) / (double)mpCamera->vpWidth();
|
||||
double y = (double)(0.5*mpCamera->vpHeight() - p2.y()) / (double)mpCamera->vpHeight();
|
||||
double sinx = sin(M_PI * x * 0.5);
|
||||
double siny = sin(M_PI * y * 0.5);
|
||||
double sinx2siny2 = sinx * sinx + siny * siny;
|
||||
|
||||
v3.x() = sinx;
|
||||
v3.y() = siny;
|
||||
v3.z() = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
55
demos/opengl/trackball.h
Normal file
55
demos/opengl/trackball.h
Normal file
@ -0,0 +1,55 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra. Eigen itself is part of the KDE project.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||
//
|
||||
// Eigen is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Alternatively, you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of
|
||||
// the License, or (at your option) any later version.
|
||||
//
|
||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License and a copy of the GNU General Public License along with
|
||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef EIGEN_TRACKBALL_H
|
||||
#define EIGEN_TRACKBALL_H
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
class Camera;
|
||||
|
||||
class Trackball
|
||||
{
|
||||
public:
|
||||
|
||||
Trackball() : mpCamera(0) {}
|
||||
|
||||
void reset() { mLastPointOk = false; }
|
||||
|
||||
void setCamera(Camera* pCam) { mpCamera = pCam; }
|
||||
|
||||
void track(const Eigen::Vector2i& newPoint2D);
|
||||
|
||||
protected:
|
||||
|
||||
bool mapToSphere( const Eigen::Vector2i& p2, Eigen::Vector3f& v3);
|
||||
|
||||
Camera* mpCamera;
|
||||
Eigen::Vector2i mLastPoint2D;
|
||||
Eigen::Vector3f mLastPoint3D;
|
||||
bool mLastPointOk;
|
||||
|
||||
};
|
||||
|
||||
#endif // EIGEN_TRACKBALL_H
|
Loading…
x
Reference in New Issue
Block a user