Selection of scene objects using select()
and an GL_SELECT render mode.
Use the select()
callback function to implement your object selection function. This
examples is based on a generic GL_SELECT implementation that can easily be cut and pasted in your
applications.
Analytic intersection computations are also possible once the screen coordinates have be converted
to a half line using convertClickToLine()
. Make a selection and then move the camera
to see a representation of the intersection line.
#include <QGLViewer/qglviewer.h> class Viewer : public QGLViewer { protected : virtual void draw(); virtual void drawWithNames(); virtual void postSelection(const QPoint& point); virtual void init(); virtual QString helpString() const; private : qglviewer::Vec orig, dir, selectedPoint; };
#include "select.h" #include <qmessagebox.h> #include <math.h> using namespace std; static void drawSpiral(const bool specialColor = false) { const float nbSteps = 100.0; glBegin(GL_QUAD_STRIP); for (float i=0; i<nbSteps; ++i) { float ratio = i/nbSteps; float angle = 21.0*ratio; float c = cos(angle); float s = sin(angle); float r1 = 0.5 - 0.3*ratio; float r2 = 0.3 - 0.3*ratio; float alt = ratio - 0.5; const float nor = .5; const float up = sqrt(1.0-nor*nor); if (specialColor) glColor3f(1.0-ratio, 0.8f , ratio/2.0); else glColor3f(1.0-ratio, 0.2f, ratio); glNormal3f(nor*c, nor*s, up); glVertex3f(r2*c, r2*s, alt+0.05f); glVertex3f(r1*c, r1*s, alt); } glEnd(); } void Viewer::drawWithNames() { // Draw spirals, pushing a name (id) for each of them const int nb = 10; for (int i=0; i<nb; ++i) { glPushMatrix(); glTranslatef(cos(2.0*i*M_PI/nb), sin(2.0*i*M_PI/nb), 0.); glPushName(i); drawSpiral(); glPopName(); glPopMatrix(); } } void Viewer::postSelection(const QPoint& point) { // Compute orig and dir, used to draw a representation of the intersecting line camera()->convertClickToLine(point, orig, dir); // Find the selectedPoint coordinates, using camera()->pointUnderPixel(). bool found; selectedPoint = camera()->pointUnderPixel(point, found); selectedPoint -= 0.01f*dir; // Small offset to make point clearly visible. // Note that "found" is different from (selectedObjectId()>=0) because of the size of the select region. if (selectedName() == -1) QMessageBox::information(this, "No selection", "No object selected under pixel " + QString::number(point.x()) + "," + QString::number(point.y())); else QMessageBox::information(this, "Selection", "Spiral number " + QString::number(selectedName()) + " selected under pixel " + QString::number(point.x()) + "," + QString::number(point.y())); } void Viewer::init() { restoreStateFromFile(); glLineWidth(3.0); glPointSize(10.0); help(); } void Viewer::draw() { // Draw ten spirals const int nb = 10; for (int i=0; i<nb; ++i) { glPushMatrix(); glTranslatef(cos(2.0*i*M_PI/nb), sin(2.0*i*M_PI/nb), 0.0); drawSpiral(i == selectedName()); glPopMatrix(); } // Draw the intersection line glBegin(GL_LINES); glVertex3fv(orig); glVertex3fv(orig + 100.0*dir); glEnd(); // Draw (approximated) intersection point on selected object if (selectedName() >= 0) { glColor3f(0.9f, 0.2f, 0.1f); glBegin(GL_POINTS); glVertex3fv(selectedPoint); glEnd(); } } QString Viewer::helpString() const { QString text("<h2>S e l e c t</h2>"); text += "Left click while pressing the <b>Shift</b> key to select an object of the scene.<br><br>"; text += "A line is drawn between the selected point and the camera selection position. "; text += "using <i>convertClickToLine()</i>, a useful function for analytical intersections.<br><br>"; text += "To add object selection in your viewer, all you need to do is to define the <i>drawWithNames</i> function. "; text += "It gives a name to each selectable object and selection is then performed using the OpenGL <i>GL_SELECT</i> render mode.<br><br>"; text += "Feel free to cut and paste this implementation in your own applications."; return text; }
#include "select.h" #include <qapplication.h> int main(int argc, char** argv) { QApplication application(argc,argv); Viewer viewer; #if QT_VERSION < 0x040000 // Set the viewer as the application main widget. application.setMainWidget(&viewer); #else viewer.setWindowTitle("select"); #endif viewer.show(); return application.exec(); }
Back to the examples main page.