From 146c9e449443453f3932b60cd1bab47f688403e7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 9 Sep 2008 18:50:45 +0000 Subject: various stuff in opengl demos such as a better model, stable trackball for the fly navigation mode, and started to put some GUI elements... --- demos/opengl/quaternion_demo.cpp | 345 +++++++++++++++++++++++++++++++++------ 1 file changed, 295 insertions(+), 50 deletions(-) (limited to 'demos/opengl/quaternion_demo.cpp') diff --git a/demos/opengl/quaternion_demo.cpp b/demos/opengl/quaternion_demo.cpp index aef6083e2..f4bea262d 100644 --- a/demos/opengl/quaternion_demo.cpp +++ b/demos/opengl/quaternion_demo.cpp @@ -23,6 +23,7 @@ // Eigen. If not, see . #include "quaternion_demo.h" +#include "icosphere.h" #include #include @@ -31,6 +32,11 @@ #include #include #include +#include +#include +#include +#include +#include using namespace Eigen; @@ -57,21 +63,27 @@ inline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b) Quaternionf(::lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation)))); } -QuaternionDemo::QuaternionDemo() +RenderingWidget::RenderingWidget() { mAnimate = false; - mTrackMode = TM_NO_TRACK; + mCurrentTrackingMode = TM_NO_TRACK; + mNavMode = NavTurnAround; + mLerpMode = LerpQuaternion; + mRotationMode = RotationStable; mTrackball.setCamera(&mCamera); + + // required to capture key press events + setFocusPolicy(Qt::ClickFocus); } -void QuaternionDemo::grabFrame(void) +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 QuaternionDemo", "time value: ", + t = QInputDialog::getDouble(this, "Eigen's RenderingWidget", "time value: ", t, 0, 1e3, 1, &ok); if (ok) { @@ -82,20 +94,47 @@ void QuaternionDemo::grabFrame(void) } } -void QuaternionDemo::drawScene() +void RenderingWidget::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() -{ + // draw the fractal object + float sqrt3 = ei_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); + + glColor3f(0.4, 0.7, 0.4); + 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 QuaternionDemo::animate() +void RenderingWidget::animate() { m_alpha += double(m_timer.interval()) * 1e-3; @@ -130,7 +169,7 @@ void QuaternionDemo::animate() updateGL(); } -void QuaternionDemo::keyPressEvent(QKeyEvent * e) +void RenderingWidget::keyPressEvent(QKeyEvent * e) { switch(e->key()) { @@ -150,18 +189,8 @@ void QuaternionDemo::keyPressEvent(QKeyEvent * e) 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; - } + resetCamera(); + break; // start/stop the animation case Qt::Key_A: if (mAnimate) @@ -183,7 +212,7 @@ void QuaternionDemo::keyPressEvent(QKeyEvent * e) updateGL(); } -void QuaternionDemo::stopAnimation() +void RenderingWidget::stopAnimation() { disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate())); m_timer.stop(); @@ -191,46 +220,48 @@ void QuaternionDemo::stopAnimation() m_alpha = 0; } -void QuaternionDemo::mousePressEvent(QMouseEvent* e) +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(e->modifiers()&Qt::ControlModifier) + if(fly) { - mTrackMode = TM_QUAKE_ROTATE; + mCurrentTrackingMode = TM_LOCAL_ROTATE; + mTrackball.start(Trackball::Local); } else { - mTrackMode = TM_ROTATE_AROUND; - mTrackball.reset(); - mTrackball.track(mMouseCoords); + mCurrentTrackingMode = TM_ROTATE_AROUND; + mTrackball.start(Trackball::Around); } + mTrackball.track(mMouseCoords); break; case Qt::MidButton: - if(e->modifiers()&Qt::ControlModifier) - mTrackMode = TM_QUAKE_WALK; + if(fly) + mCurrentTrackingMode = TM_FLY_Z; else - mTrackMode = TM_ZOOM; + mCurrentTrackingMode = TM_ZOOM; break; case Qt::RightButton: - mTrackMode = TM_QUAKE_PAN; + mCurrentTrackingMode = TM_FLY_PAN; break; default: break; } } -void QuaternionDemo::mouseReleaseEvent(QMouseEvent*) +void RenderingWidget::mouseReleaseEvent(QMouseEvent*) { - mTrackMode = TM_NO_TRACK; + mCurrentTrackingMode = TM_NO_TRACK; updateGL(); } -void QuaternionDemo::mouseMoveEvent(QMouseEvent* e) +void RenderingWidget::mouseMoveEvent(QMouseEvent* e) { // tracking - if(mTrackMode != TM_NO_TRACK) + 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()); @@ -241,23 +272,21 @@ void QuaternionDemo::mouseMoveEvent(QMouseEvent* e) dy *= 10.; } - switch(mTrackMode) + switch(mCurrentTrackingMode) { - case TM_ROTATE_AROUND : + case TM_ROTATE_AROUND: + case TM_LOCAL_ROTATE: 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)); + case TM_FLY_Z : + mCamera.localTranslate(Vector3f(0, 0, -dy*100)); break; - case TM_QUAKE_PAN : + case TM_FLY_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; } @@ -268,7 +297,7 @@ void QuaternionDemo::mouseMoveEvent(QMouseEvent* e) mMouseCoords = Vector2i(e->pos().x(), e->pos().y()); } -void QuaternionDemo::paintGL() +void RenderingWidget::paintGL() { glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -288,26 +317,242 @@ void QuaternionDemo::paintGL() drawScene(); } -void QuaternionDemo::initializeGL() +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); - mInitFrame.orientation = mCamera.viewMatrix().linear(); + mCamera.setPosition(Vector3f(-200, -200, -200)); + mCamera.setTarget(Vector3f(0, 0, 0)); + mInitFrame.orientation = mCamera.orientation().inverse(); mInitFrame.position = mCamera.viewMatrix().translation(); + + // create a kind of fractal sphere + { + IcoSphere pattern; + + int levels = 3; + float scale = 0.45; + float radius = 100; + std::vector centers; + std::vector parents; + std::vector radii; + centers.push_back(Vector3f::Zero()); + parents.push_back(-1); + radii.push_back(radius); + radius *= scale; + + // generate level 1 using icosphere vertices + { + float dist = radii[0]*0.9; + for (int i=0; i<12; ++i) + { + centers.push_back(pattern.vertices()[i] * dist); + radii.push_back(radius); + parents.push_back(0); + } + } + + scale = 0.33; + 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; + float maxAngle = M_PI/2; + for (int l=1; l& sphereIndices = pattern.indices(2); + std::cout << "instanciate geometry... (" << sphereIndices.size() * centers.size() << " vertices)\n"; + mVertices.reserve(sphereIndices.size() * centers.size()); + mNormals.reserve(sphereIndices.size() * centers.size()); + int end = centers.size(); + for (int i=0; iM_PI) + rangle = 2.*M_PI - rangle; + float duration = rangle * 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 teh 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(); + + { + // navigation mode + QButtonGroup* group = new QButtonGroup(panel); + QRadioButton* but; + but = new QRadioButton("turn around"); + group->addButton(but, NavTurnAround); + layout->addWidget(but); + but = new QRadioButton("fly"); + group->addButton(but, NavFly); + layout->addWidget(but); + group->button(mNavMode)->setChecked(true); + connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int))); + } + { + QPushButton* but = new QPushButton("reset"); + layout->addWidget(but); + connect(but, SIGNAL(clicked()), this, SLOT(resetCamera())); + } + { + // track ball, rotation mode + QButtonGroup* group = new QButtonGroup(panel); + QRadioButton* but; + but = new QRadioButton("stable trackball"); + group->addButton(but, RotationStable); + layout->addWidget(but); + but = new QRadioButton("standard rotation"); + group->addButton(but, RotationStandard); + layout->addWidget(but); + but->setEnabled(false); + group->button(mRotationMode)->setChecked(true); + connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int))); + } + { + // interpolation mode + QButtonGroup* group = new QButtonGroup(panel); + QRadioButton* but; + but = new QRadioButton("quaternion slerp"); + group->addButton(but, LerpQuaternion); + layout->addWidget(but); + but = new QRadioButton("euler angles"); + group->addButton(but, LerpEulerAngles); + layout->addWidget(but); + but->setEnabled(false); + group->button(mNavMode)->setChecked(true); + connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int))); + } + 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::RightDockWidgetArea | Qt::LeftDockWidgetArea)); + addDockWidget(Qt::RightDockWidgetArea, panel); + panel->setWidget(mRenderingWidget->createNavigationControlWidget()); +} + int main(int argc, char *argv[]) { QApplication app(argc, argv); QuaternionDemo demo; + demo.resize(600,500); demo.show(); return app.exec(); } -- cgit v1.2.3