Home | Documentation | Download | Screenshots | Developper |
A more complex exemple that combines manipulatedFrames, selection and constraints.
This exemple illustrates different functions of the viewer. It displays a famous luxoŽ lamp (ŠPixar) that can be interactively manipulated with the mouse. It illustrates the use of several ManipulatedFrames in the same scene.
Shift click on any part of the lamp to select it, and then move it with the mouse. To move the camera select the background or press the Alt key (default modifier keys are switched).
A simpler object selection example is given in select
.
A simpler frame displacement example is given in manipulatedFrame
.
A simpler constrained frame example is given in constrainedFrame
.
#include "qglviewer.h" class Luxo { public : Luxo(); void draw(const bool names=false); qglviewer::ManipulatedFrame* frame(const unsigned short i) { return frame_[i]; } void setSelectedFrameNumber(const unsigned short nb) { selected = nb; } private : // The four articulations of the viewer qglviewer::ManipulatedFrame* frame_[4]; unsigned short selected; void drawCone(const float zMin,const float zMax, const float r1, const float r2, const float nbSub); void drawBase(); void drawArm(); void drawAxis(); void setColor(const unsigned short nb); void drawHead(); }; class Viewer : public QGLViewer { protected : void draw(); void init(); void help(); void initSpotLight(); void mousePressEvent(QMouseEvent *e); void select(QMouseEvent*); Luxo luxo; };
#include "luxo.h" #include <math.h> using namespace qglviewer; using namespace std; ////////////////////////////////// V i e w e r //////////////////////////////////////// void Viewer::help() { cout << endl << "\t\t- - L u x o Š - -" << endl << endl; cout << "This example illustrates several functionnalities of QGLViewer," << endl; cout << "showing how easy it is to create a moderately complex application." << endl << endl; cout << "The famous luxoŽ lamp (ŠPixar) that can be interactively manipulated" << endl; cout << "with the mouse. Shift left click on an a part of the lamp to select it," << endl; cout << "and then move it with the mouse. Select the background to move the camera," << endl; cout << "or press the Alt key (the default shortcut modifier keys have been changed). " << endl << endl; cout << "A simpler object selection example is given in select." << endl; cout << "A simpler frame displacement example is given in manipulatedFrame." << endl; cout << "A simpler constrained frame example is given in constrainedFrame." << endl << endl; cout << "Feel free to use this code as the starting point of a multiple frame manipulation" << endl; cout << "application." << endl << endl; } void Viewer::initSpotLight() { glMatrixMode(GL_MODELVIEW); glEnable(GL_LIGHT1); glLoadIdentity(); // Light default parameters GLfloat spot_dir[3] = {0.0, 0.0, 1.0}; GLfloat light_ambient[4] = {0.5, 0.5, 0.5, 1.0}; GLfloat light_specular[4] = {1.0, 1.0, 1.0, 1.0}; GLfloat light_diffuse[4] = {3.0, 3.0, 1.0, 1.0}; glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir); glLightf( GL_LIGHT1, GL_SPOT_EXPONENT, 3.0); glLightf( GL_LIGHT1, GL_SPOT_CUTOFF, 50.0); glLightf( GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.5); glLightf( GL_LIGHT1, GL_LINEAR_ATTENUATION, 1.0); glLightf( GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 1.5); glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); } void Viewer::init() { // Make camera the default manipulated frame. setManipulatedFrame( &(camera.frame) ); // The frames can be moved without any key pressed setMouseStateKey(QGLViewer::FRAME, Qt::NoButton); // The camera can always be moved with the Alt key. setMouseStateKey(QGLViewer::CAMERA, Qt::AltButton); initSpotLight(); } void Viewer::mousePressEvent(QMouseEvent *e) { if (((e->state() & ~Qt::MouseButtonMask) == Qt::ShiftButton) && (e->button() == Qt::LeftButton)) { select(e); updateGL(); } else QGLViewer::mousePressEvent(e); } void Viewer::draw() { // Draw the ground glColor3f(.4,.4,.4); const float nbPatches = 100; glNormal3f(0.0,0.0,1.0); for (int j=0; j<nbPatches; ++j) { glBegin(GL_QUAD_STRIP); for (int i=0; i<=nbPatches; ++i) { glVertex2f((2*i/nbPatches-1.0), (2*j/nbPatches-1.0)); glVertex2f((2*i/nbPatches-1.0), (2*(j+1)/nbPatches-1.0)); } glEnd(); } luxo.draw(); } void Viewer::select(QMouseEvent* e) { // Make openGL context current makeCurrent(); const int SENSITIVITY = 4; const int NB_HITS_MAX = 1000; // Prepare the selection mode static GLuint hits[NB_HITS_MAX]; static GLint nb_hits = 0; glSelectBuffer(NB_HITS_MAX, hits); glRenderMode(GL_SELECT); glInitNames(); // Loads the matrices glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); gluPickMatrix(static_cast<GLdouble>(e->x()), static_cast<GLdouble>(viewport[3] - e->y()), SENSITIVITY, SENSITIVITY, viewport); // Don't use loadProjectionMatrix() directly as it clears the GL_PROJECTION matrix with a glLoadIdentity. // The false flag indicates that no glLoadIdentity should be called, in order to combine the matrices. loadProjectionMatrix(false); loadModelViewMatrix(); // Render scene with objects ids luxo.draw(true); glFlush(); // Get the results nb_hits = glRenderMode(GL_RENDER); // Interpret results unsigned int zMin = UINT_MAX; short selected = -1; for (int i=0; i<nb_hits; ++i) { if (hits[i*4+1] < zMin) { zMin = hits[i*4+1]; selected = hits[i*4+3]; } } if (selected >= 0) { setManipulatedFrame(luxo.frame(selected)); luxo.setSelectedFrameNumber(selected); } else { // Camera will be the default frame is no selection occurs. setManipulatedFrame( &(camera.frame) ); luxo.setSelectedFrameNumber(4); // dummy value } } ////////////////////////////////// L u x o //////////////////////////////////////// Luxo::Luxo() { for (unsigned short i=0; i<4; ++i) frame_[i] = new ManipulatedFrame(); // Creates a hierarchy of frames. for (unsigned short i=1; i<4; ++i) frame(i)->setReferenceFrame(frame(i-1)); // Initialize frames frame(1)->setTranslation(Vec(0.0, 0.0, 0.08)); // Base height frame(2)->setTranslation(Vec(0.0, 0.0, 0.5)); // Arm length frame(3)->setTranslation(Vec(0.0, 0.0, 0.5)); // Arm length frame(1)->setRotation(Quaternion(Vec(1.0,0.0,0.0), 0.6)); frame(2)->setRotation(Quaternion(Vec(1.0,0.0,0.0), -2.0)); frame(3)->setRotation(Quaternion(Vec(1.0,-0.3,0.0), -1.7)); // Set frame constraints WorldConstraint* baseConstraint = new WorldConstraint(); baseConstraint->setTranslationConstraint(AxisPlaneConstraint::PLANE, Vec(0.0,0.0,1.0)); baseConstraint->setRotationConstraint(AxisPlaneConstraint::AXIS, Vec(0.0,0.0,1.0)); frame(0)->setConstraint(baseConstraint); LocalConstraint* XAxis = new LocalConstraint(); XAxis->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN, Vec(0.0,0.0,0.0)); XAxis->setRotationConstraint (AxisPlaneConstraint::AXIS, Vec(1.0,0.0,0.0)); frame(1)->setConstraint(XAxis); frame(2)->setConstraint(XAxis); LocalConstraint* headConstraint = new LocalConstraint(); headConstraint->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN, Vec(0.0,0.0,0.0)); frame(3)->setConstraint(headConstraint); // Means camera is selected. selected = 4; } void Luxo::draw(const bool names) { // Luxo's local frame glMultMatrixd(frame(0)->matrix()); if (names) glPushName(0); setColor(0); drawBase(); if (names) glPopName(); if (names) glPushName(1); glMultMatrixd(frame(1)->matrix()); setColor(1); drawAxis(); drawArm(); if (names) glPopName(); if (names) glPushName(2); glMultMatrixd(frame(2)->matrix()); setColor(2); drawAxis(); drawArm(); if (names) glPopName(); if (names) glPushName(3); glMultMatrixd(frame(3)->matrix()); setColor(3); drawHead(); if (names) glPopName(); // Add light const GLfloat pos[4] = {0.0,0.0,0.0,1.0}; glLightfv(GL_LIGHT1, GL_POSITION, pos); GLfloat spot_dir[3] = {0.0, 0.0, 1.0}; glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir); } void Luxo::drawBase() { drawCone(0.0,0.03, 0.15, 0.15, 30); drawCone(0.03,0.05, 0.15, 0.13, 30); drawCone(0.05,0.07, 0.13, 0.01, 30); drawCone(0.07,0.09, 0.01, 0.01, 10); } void Luxo::drawArm() { glTranslatef(0.02, 0.0, 0.0); drawCone(0.0,0.5, 0.01, 0.01, 10); glTranslatef(-0.04, 0.0, 0.0); drawCone(0.0,0.5, 0.01, 0.01, 10); glTranslatef(0.02, 0.0, 0.0); } void Luxo::drawHead() { drawCone(-0.02,0.06, 0.04, 0.04, 30); drawCone(0.06,0.15, 0.04, 0.17, 30); drawCone(0.15,0.17, 0.17, 0.17, 30); } void Luxo::drawAxis() { glPushMatrix(); glRotatef(90, 0.0,1.0,0.0); drawCone(-0.05,0.05, 0.02, 0.02, 20); glPopMatrix(); } void Luxo::setColor(const unsigned short nb) { if (nb == selected) glColor3f(.9,.9,.0); else glColor3f(.9,.9,.9); } // Draws a truncated cone aligned with the Z axis. void Luxo::drawCone(const float zMin,const float zMax, const float r1, const float r2, const float nbSub) { float angle,c,s; Vec normal, p1, p2; glBegin(GL_QUAD_STRIP); for (unsigned short i=0; i<=nbSub; ++i) { angle = 2.0 * M_PI * i / nbSub; c = cos(angle); s = sin(angle); p1 = Vec(r1*c, r1*s, zMin); p2 = Vec(r2*c, r2*s, zMax); normal = cross(Vec(-s,c,0.0) , (p2-p1)); normal.normalize(); glNormal3fv(normal.address()); glVertex3fv(p1.address()); glVertex3fv(p2.address()); } glEnd(); }
#include "luxo.h" #include <qapplication.h> int main(int argc, char** argv) { // Read command lines arguments. QApplication application(argc,argv); // Instantiate the viewer. Viewer v; // Make the viewer window visible on screen. v.show(); // Set the viewer as the application main widget. application.setMainWidget(&v); // Run main loop. return application.exec(); }
Back to the main page