Disabled external gits

This commit is contained in:
2022-04-07 18:46:57 +02:00
parent 88cb3426ad
commit 15e7120d6d
5316 changed files with 4563444 additions and 6 deletions

View File

@@ -0,0 +1,28 @@
find_package(Qt4)
find_package(OpenGL)
if(QT4_FOUND AND OPENGL_FOUND)
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 icosphere.cpp camera.cpp trackball.cpp quaternion_demo.cpp)
qt4_automoc(${quaternion_demo_SRCS})
add_executable(quaternion_demo ${quaternion_demo_SRCS})
add_dependencies(demos quaternion_demo)
target_link_libraries(quaternion_demo
${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}
${QT_QTOPENGL_LIBRARY} ${OPENGL_LIBRARIES} )
else()
message(STATUS "OpenGL demo disabled because Qt4 and/or OpenGL have not been found.")
endif()

View 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

View File

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

View File

@@ -0,0 +1,118 @@
// 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/.
#ifndef EIGEN_CAMERA_H
#define EIGEN_CAMERA_H
#include <Eigen/Geometry>
#include <QObject>
// #include <frame.h>
class Frame
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
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:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
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::Affine3f& viewMatrix(void) const;
const Eigen::Matrix4f& projectionMatrix(void) const;
void rotateAroundTarget(const Eigen::Quaternionf& q);
void localRotate(const Eigen::Quaternionf& q);
void zoom(float d);
void localTranslate(const Eigen::Vector3f& t);
/** 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::Affine3f 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

View File

@@ -0,0 +1,126 @@
// 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 "gpuhelper.h"
#include "icosphere.h"
#include <GL/glu.h>
// PLEASE don't look at this old code... ;)
#include <fstream>
#include <algorithm>
GpuHelper gpu;
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 GpuHelper::drawUnitSphere(int level)
{
static IcoSphere sphere;
sphere.draw(level);
}

View File

@@ -0,0 +1,207 @@
// 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/.
#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::internal::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 guarantee 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::internal::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 drawUnitSphere(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::internal::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::internal::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

View File

@@ -0,0 +1,120 @@
// 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 "icosphere.h"
#include <GL/gl.h>
#include <map>
using namespace Eigen;
//--------------------------------------------------------------------------------
// icosahedron data
//--------------------------------------------------------------------------------
#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} };
//--------------------------------------------------------------------------------
IcoSphere::IcoSphere(unsigned int levels)
{
// init with an icosahedron
for (int i = 0; i < 12; i++)
mVertices.push_back(Map<Vector3f>(vdata[i]));
mIndices.push_back(new std::vector<int>);
std::vector<int>& indices = *mIndices.back();
for (int i = 0; i < 20; i++)
{
for (int k = 0; k < 3; k++)
indices.push_back(tindices[i][k]);
}
mListIds.push_back(0);
while(mIndices.size()<levels)
_subdivide();
}
const std::vector<int>& IcoSphere::indices(int level) const
{
while (level>=int(mIndices.size()))
const_cast<IcoSphere*>(this)->_subdivide();
return *mIndices[level];
}
void IcoSphere::_subdivide(void)
{
typedef unsigned long long Key;
std::map<Key,int> edgeMap;
const std::vector<int>& indices = *mIndices.back();
mIndices.push_back(new std::vector<int>);
std::vector<int>& refinedIndices = *mIndices.back();
int end = indices.size();
for (int i=0; i<end; i+=3)
{
int ids0[3], // indices of outer vertices
ids1[3]; // indices of edge vertices
for (int k=0; k<3; ++k)
{
int k1 = (k+1)%3;
int e0 = indices[i+k];
int e1 = indices[i+k1];
ids0[k] = e0;
if (e1>e0)
std::swap(e0,e1);
Key edgeKey = Key(e0) | (Key(e1)<<32);
std::map<Key,int>::iterator it = edgeMap.find(edgeKey);
if (it==edgeMap.end())
{
ids1[k] = mVertices.size();
edgeMap[edgeKey] = ids1[k];
mVertices.push_back( (mVertices[e0]+mVertices[e1]).normalized() );
}
else
ids1[k] = it->second;
}
refinedIndices.push_back(ids0[0]); refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[2]);
refinedIndices.push_back(ids0[1]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[0]);
refinedIndices.push_back(ids0[2]); refinedIndices.push_back(ids1[2]); refinedIndices.push_back(ids1[1]);
refinedIndices.push_back(ids1[0]); refinedIndices.push_back(ids1[1]); refinedIndices.push_back(ids1[2]);
}
mListIds.push_back(0);
}
void IcoSphere::draw(int level)
{
while (level>=int(mIndices.size()))
const_cast<IcoSphere*>(this)->_subdivide();
if (mListIds[level]==0)
{
mListIds[level] = glGenLists(1);
glNewList(mListIds[level], GL_COMPILE);
glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
glNormalPointer(GL_FLOAT, 0, mVertices[0].data());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glDrawElements(GL_TRIANGLES, mIndices[level]->size(), GL_UNSIGNED_INT, &(mIndices[level]->at(0)));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glEndList();
}
glCallList(mListIds[level]);
}

View File

@@ -0,0 +1,30 @@
// 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/.
#ifndef EIGEN_ICOSPHERE_H
#define EIGEN_ICOSPHERE_H
#include <Eigen/Core>
#include <vector>
class IcoSphere
{
public:
IcoSphere(unsigned int levels=1);
const std::vector<Eigen::Vector3f>& vertices() const { return mVertices; }
const std::vector<int>& indices(int level) const;
void draw(int level);
protected:
void _subdivide();
std::vector<Eigen::Vector3f> mVertices;
std::vector<std::vector<int>*> mIndices;
std::vector<int> mListIds;
};
#endif // EIGEN_ICOSPHERE_H

View File

@@ -0,0 +1,656 @@
// 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 "quaternion_demo.h"
#include "icosphere.h"
#include <Eigen/Geometry>
#include <Eigen/QR>
#include <Eigen/LU>
#include <iostream>
#include <QEvent>
#include <QMouseEvent>
#include <QInputDialog>
#include <QGridLayout>
#include <QButtonGroup>
#include <QRadioButton>
#include <QDockWidget>
#include <QPushButton>
#include <QGroupBox>
using namespace Eigen;
class FancySpheres
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
FancySpheres()
{
const int levels = 4;
const float scale = 0.33;
float radius = 100;
std::vector<int> parents;
// leval 0
mCenters.push_back(Vector3f::Zero());
parents.push_back(-1);
mRadii.push_back(radius);
// generate level 1 using icosphere vertices
radius *= 0.45;
{
float dist = mRadii[0]*0.9;
for (int i=0; i<12; ++i)
{
mCenters.push_back(mIcoSphere.vertices()[i] * dist);
mRadii.push_back(radius);
parents.push_back(0);
}
}
static const float angles [10] = {
0, 0,
M_PI, 0.*M_PI,
M_PI, 0.5*M_PI,
M_PI, 1.*M_PI,
M_PI, 1.5*M_PI
};
// generate other levels
int start = 1;
for (int l=1; l<levels; l++)
{
radius *= scale;
int end = mCenters.size();
for (int i=start; i<end; ++i)
{
Vector3f c = mCenters[i];
Vector3f ax0 = (c - mCenters[parents[i]]).normalized();
Vector3f ax1 = ax0.unitOrthogonal();
Quaternionf q;
q.setFromTwoVectors(Vector3f::UnitZ(), ax0);
Affine3f t = Translation3f(c) * q * Scaling(mRadii[i]+radius);
for (int j=0; j<5; ++j)
{
Vector3f newC = c + ( (AngleAxisf(angles[j*2+1], ax0)
* AngleAxisf(angles[j*2+0] * (l==1 ? 0.35 : 0.5), ax1)) * ax0)
* (mRadii[i] + radius*0.8);
mCenters.push_back(newC);
mRadii.push_back(radius);
parents.push_back(i);
}
}
start = end;
}
}
void draw()
{
int end = mCenters.size();
glEnable(GL_NORMALIZE);
for (int i=0; i<end; ++i)
{
Affine3f t = Translation3f(mCenters[i]) * Scaling(mRadii[i]);
gpu.pushMatrix(GL_MODELVIEW);
gpu.multMatrix(t.matrix(),GL_MODELVIEW);
mIcoSphere.draw(2);
gpu.popMatrix(GL_MODELVIEW);
}
glDisable(GL_NORMALIZE);
}
protected:
std::vector<Vector3f> mCenters;
std::vector<float> mRadii;
IcoSphere mIcoSphere;
};
// generic linear interpolation method
template<typename T> T lerp(float t, const T& a, const T& b)
{
return a*(1-t) + b*t;
}
// quaternion slerp
template<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
{ return a.slerp(t,b); }
// linear interpolation of a frame using the type OrientationType
// to perform the interpolation of the orientations
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))));
}
template<typename _Scalar> class EulerAngles
{
public:
enum { Dim = 3 };
typedef _Scalar Scalar;
typedef Matrix<Scalar,3,3> Matrix3;
typedef Matrix<Scalar,3,1> Vector3;
typedef Quaternion<Scalar> QuaternionType;
protected:
Vector3 m_angles;
public:
EulerAngles() {}
inline EulerAngles(Scalar a0, Scalar a1, Scalar a2) : m_angles(a0, a1, a2) {}
inline EulerAngles(const QuaternionType& q) { *this = q; }
const Vector3& coeffs() const { return m_angles; }
Vector3& coeffs() { return m_angles; }
EulerAngles& operator=(const QuaternionType& q)
{
Matrix3 m = q.toRotationMatrix();
return *this = m;
}
EulerAngles& operator=(const Matrix3& m)
{
// mat = cy*cz -cy*sz sy
// cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
m_angles.coeffRef(1) = std::asin(m.coeff(0,2));
m_angles.coeffRef(0) = std::atan2(-m.coeff(1,2),m.coeff(2,2));
m_angles.coeffRef(2) = std::atan2(-m.coeff(0,1),m.coeff(0,0));
return *this;
}
Matrix3 toRotationMatrix(void) const
{
Vector3 c = m_angles.array().cos();
Vector3 s = m_angles.array().sin();
Matrix3 res;
res << c.y()*c.z(), -c.y()*s.z(), s.y(),
c.z()*s.x()*s.y()+c.x()*s.z(), c.x()*c.z()-s.x()*s.y()*s.z(), -c.y()*s.x(),
-c.x()*c.z()*s.y()+s.x()*s.z(), c.z()*s.x()+c.x()*s.y()*s.z(), c.x()*c.y();
return res;
}
operator QuaternionType() { return QuaternionType(toRotationMatrix()); }
};
// Euler angles slerp
template<> EulerAngles<float> lerp(float t, const EulerAngles<float>& a, const EulerAngles<float>& b)
{
EulerAngles<float> res;
res.coeffs() = lerp(t, a.coeffs(), b.coeffs());
return res;
}
RenderingWidget::RenderingWidget()
{
mAnimate = false;
mCurrentTrackingMode = TM_NO_TRACK;
mNavMode = NavTurnAround;
mLerpMode = LerpQuaternion;
mRotationMode = RotationStable;
mTrackball.setCamera(&mCamera);
// required to capture key press events
setFocusPolicy(Qt::ClickFocus);
}
void RenderingWidget::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 RenderingWidget", "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 RenderingWidget::drawScene()
{
static FancySpheres sFancySpheres;
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));
// draw the fractal object
float sqrt3 = std::sqrt(3.);
glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data());
glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data());
glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data());
glLightfv(GL_LIGHT0, GL_POSITION, Vector4f(-sqrt3,-sqrt3,sqrt3,0).data());
glLightfv(GL_LIGHT1, GL_AMBIENT, Vector4f(0,0,0,1).data());
glLightfv(GL_LIGHT1, GL_DIFFUSE, Vector4f(1,0.5,0.5,1).data());
glLightfv(GL_LIGHT1, GL_SPECULAR, Vector4f(1,1,1,1).data());
glLightfv(GL_LIGHT1, GL_POSITION, Vector4f(-sqrt3,sqrt3,-sqrt3,0).data());
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Vector4f(0.7, 0.7, 0.7, 1).data());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Vector4f(0.8, 0.75, 0.6, 1).data());
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Vector4f(1, 1, 1, 1).data());
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
sFancySpheres.draw();
glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
glNormalPointer(GL_FLOAT, 0, mNormals[0].data());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, mVertices.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_LIGHTING);
}
void RenderingWidget::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);
if (mLerpMode==LerpEulerAngles)
currentFrame = ::lerpFrame<EulerAngles<float> >(s, lo->second, hi->second);
else if (mLerpMode==LerpQuaternion)
currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
else
{
std::cerr << "Invalid rotation interpolation mode (abort)\n";
exit(2);
}
currentFrame.orientation.coeffs().normalize();
}
currentFrame.orientation = currentFrame.orientation.inverse();
currentFrame.position = - (currentFrame.orientation * currentFrame.position);
mCamera.setFrame(currentFrame);
updateGL();
}
void RenderingWidget::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:
resetCamera();
break;
// 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 RenderingWidget::stopAnimation()
{
disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
m_timer.stop();
mAnimate = false;
m_alpha = 0;
}
void RenderingWidget::mousePressEvent(QMouseEvent* e)
{
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
bool fly = (mNavMode==NavFly) || (e->modifiers()&Qt::ControlModifier);
switch(e->button())
{
case Qt::LeftButton:
if(fly)
{
mCurrentTrackingMode = TM_LOCAL_ROTATE;
mTrackball.start(Trackball::Local);
}
else
{
mCurrentTrackingMode = TM_ROTATE_AROUND;
mTrackball.start(Trackball::Around);
}
mTrackball.track(mMouseCoords);
break;
case Qt::MidButton:
if(fly)
mCurrentTrackingMode = TM_FLY_Z;
else
mCurrentTrackingMode = TM_ZOOM;
break;
case Qt::RightButton:
mCurrentTrackingMode = TM_FLY_PAN;
break;
default:
break;
}
}
void RenderingWidget::mouseReleaseEvent(QMouseEvent*)
{
mCurrentTrackingMode = TM_NO_TRACK;
updateGL();
}
void RenderingWidget::mouseMoveEvent(QMouseEvent* e)
{
// tracking
if(mCurrentTrackingMode != TM_NO_TRACK)
{
float dx = float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
// speedup the transformations
if(e->modifiers() & Qt::ShiftModifier)
{
dx *= 10.;
dy *= 10.;
}
switch(mCurrentTrackingMode)
{
case TM_ROTATE_AROUND:
case TM_LOCAL_ROTATE:
if (mRotationMode==RotationStable)
{
// use the stable trackball implementation mapping
// the 2D coordinates to 3D points on a sphere.
mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
}
else
{
// standard approach mapping the x and y displacements as rotations
// around the camera's X and Y axes.
Quaternionf q = AngleAxisf( dx*M_PI, Vector3f::UnitY())
* AngleAxisf(-dy*M_PI, Vector3f::UnitX());
if (mCurrentTrackingMode==TM_LOCAL_ROTATE)
mCamera.localRotate(q);
else
mCamera.rotateAroundTarget(q);
}
break;
case TM_ZOOM :
mCamera.zoom(dy*100);
break;
case TM_FLY_Z :
mCamera.localTranslate(Vector3f(0, 0, -dy*200));
break;
case TM_FLY_PAN :
mCamera.localTranslate(Vector3f(dx*200, dy*200, 0));
break;
default:
break;
}
updateGL();
}
mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
}
void RenderingWidget::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 RenderingWidget::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);
mCamera.setPosition(Vector3f(-200, -200, -200));
mCamera.setTarget(Vector3f(0, 0, 0));
mInitFrame.orientation = mCamera.orientation().inverse();
mInitFrame.position = mCamera.viewMatrix().translation();
}
void RenderingWidget::resizeGL(int width, int height)
{
mCamera.setViewport(width,height);
}
void RenderingWidget::setNavMode(int m)
{
mNavMode = NavMode(m);
}
void RenderingWidget::setLerpMode(int m)
{
mLerpMode = LerpMode(m);
}
void RenderingWidget::setRotationMode(int m)
{
mRotationMode = RotationMode(m);
}
void RenderingWidget::resetCamera()
{
if (mAnimate)
stopAnimation();
m_timeline.clear();
Frame aux0 = mCamera.frame();
aux0.orientation = aux0.orientation.inverse();
aux0.position = mCamera.viewMatrix().translation();
m_timeline[0] = aux0;
Vector3f currentTarget = mCamera.target();
mCamera.setTarget(Vector3f::Zero());
// compute the rotation duration to move the camera to the target
Frame aux1 = mCamera.frame();
aux1.orientation = aux1.orientation.inverse();
aux1.position = mCamera.viewMatrix().translation();
float duration = aux0.orientation.angularDistance(aux1.orientation) * 0.9;
if (duration<0.1) duration = 0.1;
// put the camera at that time step:
aux1 = aux0.lerp(duration/2,mInitFrame);
// and make it look at the target again
aux1.orientation = aux1.orientation.inverse();
aux1.position = - (aux1.orientation * aux1.position);
mCamera.setFrame(aux1);
mCamera.setTarget(Vector3f::Zero());
// add this camera keyframe
aux1.orientation = aux1.orientation.inverse();
aux1.position = mCamera.viewMatrix().translation();
m_timeline[duration] = aux1;
m_timeline[2] = mInitFrame;
m_alpha = 0;
animate();
connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
m_timer.start(1000/30);
mAnimate = true;
}
QWidget* RenderingWidget::createNavigationControlWidget()
{
QWidget* panel = new QWidget();
QVBoxLayout* layout = new QVBoxLayout();
{
QPushButton* but = new QPushButton("reset");
but->setToolTip("move the camera to initial position (with animation)");
layout->addWidget(but);
connect(but, SIGNAL(clicked()), this, SLOT(resetCamera()));
}
{
// navigation mode
QGroupBox* box = new QGroupBox("navigation mode");
QVBoxLayout* boxLayout = new QVBoxLayout;
QButtonGroup* group = new QButtonGroup(panel);
QRadioButton* but;
but = new QRadioButton("turn around");
but->setToolTip("look around an object");
group->addButton(but, NavTurnAround);
boxLayout->addWidget(but);
but = new QRadioButton("fly");
but->setToolTip("free navigation like a spaceship\n(this mode can also be enabled pressing the \"shift\" key)");
group->addButton(but, NavFly);
boxLayout->addWidget(but);
group->button(mNavMode)->setChecked(true);
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int)));
box->setLayout(boxLayout);
layout->addWidget(box);
}
{
// track ball, rotation mode
QGroupBox* box = new QGroupBox("rotation mode");
QVBoxLayout* boxLayout = new QVBoxLayout;
QButtonGroup* group = new QButtonGroup(panel);
QRadioButton* but;
but = new QRadioButton("stable trackball");
group->addButton(but, RotationStable);
boxLayout->addWidget(but);
but->setToolTip("use the stable trackball implementation mapping\nthe 2D coordinates to 3D points on a sphere");
but = new QRadioButton("standard rotation");
group->addButton(but, RotationStandard);
boxLayout->addWidget(but);
but->setToolTip("standard approach mapping the x and y displacements\nas rotations around the camera's X and Y axes");
group->button(mRotationMode)->setChecked(true);
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int)));
box->setLayout(boxLayout);
layout->addWidget(box);
}
{
// interpolation mode
QGroupBox* box = new QGroupBox("spherical interpolation");
QVBoxLayout* boxLayout = new QVBoxLayout;
QButtonGroup* group = new QButtonGroup(panel);
QRadioButton* but;
but = new QRadioButton("quaternion slerp");
group->addButton(but, LerpQuaternion);
boxLayout->addWidget(but);
but->setToolTip("use quaternion spherical interpolation\nto interpolate orientations");
but = new QRadioButton("euler angles");
group->addButton(but, LerpEulerAngles);
boxLayout->addWidget(but);
but->setToolTip("use Euler angles to interpolate orientations");
group->button(mNavMode)->setChecked(true);
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int)));
box->setLayout(boxLayout);
layout->addWidget(box);
}
layout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding));
panel->setLayout(layout);
return panel;
}
QuaternionDemo::QuaternionDemo()
{
mRenderingWidget = new RenderingWidget();
setCentralWidget(mRenderingWidget);
QDockWidget* panel = new QDockWidget("navigation", this);
panel->setAllowedAreas((QFlags<Qt::DockWidgetArea>)(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea));
addDockWidget(Qt::RightDockWidgetArea, panel);
panel->setWidget(mRenderingWidget->createNavigationControlWidget());
}
int main(int argc, char *argv[])
{
std::cout << "Navigation:\n";
std::cout << " left button: rotate around the target\n";
std::cout << " middle button: zoom\n";
std::cout << " left button + ctrl quake rotate (rotate around camera position)\n";
std::cout << " middle button + ctrl walk (progress along camera's z direction)\n";
std::cout << " left button: pan (translate in the XY camera's plane)\n\n";
std::cout << "R : move the camera to initial position\n";
std::cout << "A : start/stop animation\n";
std::cout << "C : clear the animation\n";
std::cout << "G : add a key frame\n";
QApplication app(argc, argv);
QuaternionDemo demo;
demo.resize(600,500);
demo.show();
return app.exec();
}
#include "quaternion_demo.moc"

View File

@@ -0,0 +1,114 @@
// 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/.
#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>
#include <QtGui/QMainWindow>
class RenderingWidget : 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_LOCAL_ROTATE, TM_FLY_Z, TM_FLY_PAN
};
enum NavMode {
NavTurnAround,
NavFly
};
enum LerpMode {
LerpQuaternion,
LerpEulerAngles
};
enum RotationMode {
RotationStable,
RotationStandard
};
Camera mCamera;
TrackMode mCurrentTrackingMode;
NavMode mNavMode;
LerpMode mLerpMode;
RotationMode mRotationMode;
Vector2i mMouseCoords;
Trackball mTrackball;
QTimer m_timer;
void setupCamera();
std::vector<Vector3f> mVertices;
std::vector<Vector3f> mNormals;
std::vector<int> mIndices;
protected slots:
virtual void animate(void);
virtual void drawScene(void);
virtual void grabFrame(void);
virtual void stopAnimation();
virtual void setNavMode(int);
virtual void setLerpMode(int);
virtual void setRotationMode(int);
virtual void resetCamera();
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:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
RenderingWidget();
~RenderingWidget() { }
QWidget* createNavigationControlWidget();
};
class QuaternionDemo : public QMainWindow
{
Q_OBJECT
public:
QuaternionDemo();
protected:
RenderingWidget* mRenderingWidget;
};
#endif // EIGEN_QUATERNION_DEMO_H

View File

@@ -0,0 +1,59 @@
// 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 "trackball.h"
#include "camera.h"
using namespace Eigen;
void Trackball::track(const Vector2i& point2D)
{
if (mpCamera==0)
return;
Vector3f newPoint3D;
bool newPointOk = mapToSphere(point2D, newPoint3D);
if (mLastPointOk && newPointOk)
{
Vector3f axis = mLastPoint3D.cross(newPoint3D).normalized();
float cos_angle = mLastPoint3D.dot(newPoint3D);
if ( std::abs(cos_angle) < 1.0 )
{
float angle = 2. * acos(cos_angle);
if (mMode==Around)
mpCamera->rotateAroundTarget(Quaternionf(AngleAxisf(angle, axis)));
else
mpCamera->localRotate(Quaternionf(AngleAxisf(-angle, axis)));
}
}
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;
}

View File

@@ -0,0 +1,42 @@
// 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/.
#ifndef EIGEN_TRACKBALL_H
#define EIGEN_TRACKBALL_H
#include <Eigen/Geometry>
class Camera;
class Trackball
{
public:
enum Mode {Around, Local};
Trackball() : mpCamera(0) {}
void start(Mode m = Around) { mMode = m; 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::Vector3f mLastPoint3D;
Mode mMode;
bool mLastPointOk;
};
#endif // EIGEN_TRACKBALL_H