| Home | Documentation | Download | Screenshots | Developer |
A TriangleSetConstraint constrains the camera displacement.
The camera is constrained to stay above a given 'road' defined by triangles. Camera is in FLY mode.
The example is a little bit complex : the computations needed to get the intersection of the Z-direction and the triangle are cut and pasted from the triangleSetConstraint class, in order to draw interesting debugging informations.
#include "qglviewer.h"
class Viewer : public QGLViewer
{
protected :
void init();
void draw();
void displayConstraint(qglviewer::Vec);
};
#include "triSetConstraint.h"
#include <triangleSetConstraint.h>
#include <math.h>
using namespace qglviewer;
static bool segmentIntersection(const Vec& p, const Vec& dir1, const Vec& norm,
const Vec& s1, const Vec& s2,
Vec& inter)
{
// dir1 is supposed to be normalized.
Vec perp = cross(dir1, norm);
// Check for near-parallel lines
float n = perp.norm();
// Degenerated case : parallel lines
if (n < 1.E-10)
return false;
perp /= n;
float proj = (s2 - s1) * perp;
float alpha = ((p-s1)*perp) / proj;
if ( (alpha < 0.0) || (alpha > 1.0) )
return false;
// else
inter = s1 + (s2-s1) * alpha;
return true;
}
/* Constrain the translation \p trans with respect to a path defined by a triangle set. See addTriangle() and addPoint(). */
void Viewer::displayConstraint(Vec trans)
{
TriangleSetConstraint* tsc = (TriangleSetConstraint*)(camera()->frame()->constraint());
unsigned int currentTriangle = tsc->currentTriangle();
trans = camera()->frame()->inverseTransformOf(trans);
Vec pos, nextPos, start;
start = camera()->position();
pos = start;
unsigned short nextEdge;
const float dist = trans.norm();
if (dist < 1E-8)
return;
trans /= dist;
// Draw the current triangle
glColor3f(.6,.2,6);
glLineWidth(4.0);
glBegin(GL_TRIANGLES);
glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,0)).address());
glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,1)).address());
glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,2)).address());
glEnd();
glColor3f(.8,.5,0);
glPointSize(10.0);
glBegin(GL_POINTS); glVertex3fv(start.address()); glEnd();
glLineWidth(1.0);
glBegin(GL_LINES); glVertex3fv(start.address()); glVertex3fv((start+trans).address()); glEnd();
glColor3f(.4,.6,.7);
glPointSize(5.0);
while (true)
{
float step = -1.0E9f;
nextEdge = 3;
Vec e1 = tsc->point(tsc->trianglePoint(currentTriangle,0)) - tsc->point(tsc->trianglePoint(currentTriangle,1));
Vec e2 = tsc->point(tsc->trianglePoint(currentTriangle,0)) - tsc->point(tsc->trianglePoint(currentTriangle,2));
Vec norm = cross(e1, e2);
Vec res;
for (unsigned short edge=0; edge<3; edge++)
{
if (segmentIntersection(pos, trans, norm,
tsc->point(tsc->trianglePoint(currentTriangle,(edge+1)%3)),
tsc->point(tsc->trianglePoint(currentTriangle,(edge+2)%3)), res))
{
if ((res-pos)*trans > step)
{
step = (res-pos)*trans;
nextPos = res;
nextEdge = edge;
}
}
}
glBegin(GL_POINTS); glVertex3fv(nextPos.address()); glEnd();
float soFar = (nextPos-start)*trans;
if ((soFar > dist) || (tsc->neighTriangle(currentTriangle,nextEdge) == -1))
return;
currentTriangle = tsc->neighTriangle(currentTriangle,nextEdge);
pos = nextPos;
}
}
static const float nbSteps = 20.0;
static const float r = 0.7;
void Viewer::init()
{
setSceneRadius(3.0);
camera()->setFlySpeed(0.001);
camera()->setMode(ManipulatedCameraFrame::FLY);
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
TriangleSetConstraint* tsc = new TriangleSetConstraint();
camera()->frame()->setConstraint(tsc);
tsc->addPoint(Vec(1.0,0.0,0.0));
tsc->addPoint(Vec(r ,0.0,0.0));
for (int i=1; i<nbSteps; ++i)
{
float angle = 2.0 * M_PI * i / nbSteps;
tsc->addPoint(Vec(cos(angle) , sin(angle) , 0.0)); // index 2i
tsc->addPoint(Vec(r*cos(angle), r*sin(angle), 0.0)); // index 2i+1
tsc->addTriangle(2*i-1, 2*i, 2*i+1);
tsc->addTriangle(2*i-1, 2*i-2, 2*i);
}
tsc->addTriangle(0, 2*(int)nbSteps-2, 2*(int)nbSteps-1);
tsc->addTriangle(0, 1, 2*(int)nbSteps-1);
tsc->setCurrentTriangle(1);
camera()->setOrientation(Quaternion(Vec(1,0,0), M_PI/2.0));
camera()->setPosition(0.85, 0.05, 0.0);
}
void Viewer::draw()
{
// The camera is made visible by reseting the modelview matrix
glLoadIdentity();
glTranslatef(0.0,0.0,-2.5);
// Draw Road
glNormal3f(0.0, 0.0, 1.0);
glColor3f(.2,.6,.8);
glBegin(GL_QUAD_STRIP);
for (float i=0; i<=nbSteps; ++i)
{
float angle = 2.0 * M_PI * i / nbSteps;
glVertex3f(cos(angle), sin(angle), 0.0);
glVertex3f(r*cos(angle), r*sin(angle), 0.0);
}
glEnd();
// Draw camera position
Vec pos = camera()->position();
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex3fv(pos.address());
glEnd();
displayConstraint(Vec(0,0,-1));
}
#include "triSetConstraint.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