Help needed getting picking to work

I am trying to get picking to work, but despite reading about it in the OpenGL Super Bible and studying the NeHe examples for C++Builder 6, I can’t get it to work properly.

I am able to pick some objects but not all, and only in certain views (typically perspective and isometric, not cross-section, elevation, or plan). Some objects are picked when I click near them (noy on them)!

Can anyone see what is wong wih my code please? I would be happy to supply ALL the code (written for C++Builder 6) if that helps.

Many thanks in anticipation

Andrew


Here are (what I think are) the most significant functions:

void OnResize(int width, int height)
{
glViewport(0, 0, width, height);
}

void OnPaint()
{
glLoadIdentity();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(projection == Perspective) {
double aspect(double(width) / height);
double near_plane(size * width / 10);
double far_plane(near_plane * 1000);
gluPerspective(45, aspect, near_plane, far_plane);
}
else {
double h(size * height); // in cm
double w(size * width); // in cm
glOrtho(-w, w, -h, h, -w, w);
}
glMatrixMode(GL_MODELVIEW);

LocateCamera(); // see below
RenderScene(); // see below
SwapBuffers();
::ValidateRect(hwnd, NULL);
}

void LocateCamera()
{
switch(projection) {
case CrossSection:
gluLookAt(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
break;
case Plan:
gluLookAt(0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
break;
case Elevation:
gluLookAt(0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
break;
case Isometric:
gluLookAt(-1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
break;
case Perspective:
gluLookAt(-20.0, -20.0, -20.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
break;
default:
throw std::invalid_argument(FUNC);
}
}

void RenderScene()
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();

glInitNames();
glPushName(0);

glScaled(scale, scale, scale);
glScaled(100, 100, 100); // we are working in cm per pixel

assert(Draw);
Draw(); // draws the obejcts and pushes names onto the name stack

glPopMatrix();
}

bool HitTest(int x, int y)
{
glSelectBuffer(name_stack.size(), &name_stack[0]);

int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

glRenderMode(GL_SELECT);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

gluPickMatrix((double)x, viewport[3] - (double)y, 20, 20, viewport);

double aspect(double(width) / height);
double near_plane(size * width / 10.0);
double far_plane(near_plane * 100);
gluPerspective(45, aspect, near_plane, far_plane);

glMatrixMode(GL_MODELVIEW);
RenderScene();
glMatrixMode(GL_PROJECTION);

unsigned int hits = glRenderMode(GL_RENDER);

// pop the projection matrix
glPopMatrix();

return hits;
}
// end of code

You should keep the code p[aths together for all rendering and ONLY branch the pick mode and gluPuickMatrix call, that way you’ll know the pick code is drawing the same stuff as the normal render code. NOTHING else involved in projection should change.

I don’t even use gluPickMatrix, you can define your own projection matrix premultiplication or pick region viewport to scope the pick region. To debug you can also render with the pick matrix (or viewport or however you choose to do it) active and see what the pick region looks like.

Thanks for your help on this - I have now solved the problem and it was a fairly basic error (mea culpa)…

I was passing screen x, y coordinates to the hit testing function instead of window coordinates. My hit testing therefore almost worked when I had my window full size and never worked when normalized.

Anyway, thanks for the helpful feedback.

Andrew