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.