PDA

View Full Version : Picking an Object not working



Zubaja
04-01-2014, 07:36 AM
Hello everyone,

I'm in a bit of a bind for a while now concerning object picking. Here's the situation:
Our company has recently been implementing OpenGL into our Delphi 2010 programs and our current assignment is to display voyages of several trains in a 3D-esque environment.
Everything works and is data-aware (connected to a database); our client/customer now wants the ability to open the voyage-information when you click on a train.

I went looking for a tutorial and came across this: http://www.sulaco.co.za/opengl_project_GL_picking.htm
Studied the code, dissected the code, applied the code to our own project but it doesn't function.
One thing I've noticed is this:
The 'tutorial' uses a Viewport whereas I use a Context; the latter is because we have to use several Delphi Tools like a date-time selection bar on our Form.

Here is an image of the ContextView:
http://i1273.photobucket.com/albums/y413/Steven_Nolles/GleisGleisGleis_zpsf385d686.png

And here is the code I'm using for the Object Picking:

function TGL_Form.RetrieveObjectID(x, y: integer): integer;
var
objectsFound: integer;
viewportCoords: array [0..3] of integer;
selectBuffer: array[0..31] of cardinal;
lowestDepth: cardinal;
selectedObject: cardinal;
i: integer;
begin
objectsFound := 0;
ZeroMemory(@viewportCoords, sizeof(viewportCoords));
ZeroMemory(@selectBuffer, sizeof(selectBuffer));

glSelectBuffer(32, @selectBuffer);

viewportCoords[0] := 0;
viewportCoords[1] := 0;
viewportCoords[2] := GL_Form.ClientWidth;
viewportCoords[3] := GL_Form.ClientHeight;

glMatrixMode(GL_PROJECTION);
glPushMatrix();

glRenderMode(GL_SELECT);
glLoadIdentity();

gluPickMatrix(x, viewportCoords[3]-y-Integer(not g_Fullscreen)*(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1), 15, 15, @viewportCoords);

gluPerspective(45.0, viewportCoords[2]/viewportCoords[3], 0.5, 150.0);
glMatrixMode(GL_MODELVIEW);

objectsFound := glRenderMode(GL_RENDER);

glMatrixMode(GL_PROJECTION);
glPopMatrix();

glMatrixMode(GL_MODELVIEW);

if (objectsFound > 0) then
begin
lowestDepth := selectBuffer[1];
selectedObject := selectBuffer[3];

for i := 1 to objectsFound - 1 do
begin
if (selectBuffer[(i * 4) + 1] < lowestDepth) then
begin
lowestDepth := selectBuffer[(i * 4) + 1];
selectedObject := selectBuffer[(i * 4) + 3];
end;
end;

result := selectedObject;
exit;
end;

result := 0;
end;
Pushing names into the list:

//Draw the trains
glInitNames();
glPushName(0);

for T1 := 0 to Length(trackNames)-1 do
for T2 := 0 to Length(trackTrack)-1 do
if(trackNames[T1] = trackTrack[T2]) then
begin
glLoadName(T2);

Y := -((T1 * trackWidth) + (T1 * trackSpace))+0.5;
glCube(trackFrom[T2]*(trackLength/58),
Y,
0,
((trackTo[T2]-trackFrom[T2])*(trackLength/58)), //Length
trackWidth, //Height
0.09, //Depth
trackColorR[T2],
trackColorG[T2],
trackColorB[T2]
);

glPrint(trackVoyage[T2],
trackFrom[T2]*(trackLength/58)+1,
Y+2,
0.1,
textColorR[T2],
textColorG[T2],
textColorB[T2],
false
);
glEnd();

end;

Using breakpoints I've adjusted the code accordingly and tested to see where it goes awry:

glRenderMode(GL_SELECT);
glLoadIdentity();

gluPickMatrix(x, viewportCoords[3]-y-Integer(not g_Fullscreen)*(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1), 15, 15, @viewportCoords);

gluPerspective(45.0, viewportCoords[2]/viewportCoords[3], 0.5, 150.0);
glMatrixMode(GL_MODELVIEW);

objectsFound := glRenderMode(GL_RENDER);
This part ALWAYS returns 0
The 'x' and 'y' have the correct mouse positions stored,
data in 'viewportCoords' is correct; [0, 0, 1024, 768],
'g_FullScreen' is always 'false',

I have no idea what 'GetSystemMetrics(SM_CYCAPTION)', 'GetSystemMetrics(SM_CYSIZEFRAME)' or '(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1)' have for values because they're untracable for some reason; neither a breakpoint nor storing the data (Integers) shows any result, though I have a few more methods that might work, will update on this..
##UPDATE##
'GetSystemMetrics(SM_CYCAPTION)' = 23
'GetSystemMetrics(SM_CYSIZEFRAME)' = 8
'(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1)' = 39
'viewportCoords[3]-y-Integer(not g_Fullscreen)*(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1)' = returns a value based on the mouseposition (changes)

I hope someone can help me with fixing this, because I'm at a loss at the moment.

Thanks in advance and kind regards.

Steven Katic
04-01-2014, 03:03 PM
Hi,
Nothing unusual is apparent yet except:
It seems immeadiately obvious that there is the lack of evidence that you are actually rendering anything to the "offscreen selection buffer".
i.e. the // Draw the trains// code you show needs to be executed for the second separate time offscreen (in between the lines glMatrixMode(GL_MODELVIEW);
and objectsFound := glRenderMode(GL_RENDER);.
I was expecting to see in between these lines something like this:
glLoadIdentity();
ApplyCameraTransformations(): //if you have and use the concept
DrawTrainsHitTestMode (); //or something like it to render with the names/ids

try it and then see what happens.

Then an easier way of initially testing this is visually is to comment out the Selection mode line:
glRenderMode(GL_SELECT);
Then the zoomed up 15X15 viewport of the glPickmatrix will be magnifyed up and fill up on top of your current viewport (bit like the effect of telescopic
sights on a rifle, and that zoomed up view will move as you move the "camera with the mouse" (Note: this is possible because of the way i have it set up, thus I am aware it may just not be possible with your set up). It is very conveniently visual. You can also widen the 15X15 view with much higher values if all you see is flashes of color (produced by being zoomed up very close).

reto.koradi
04-01-2014, 10:47 PM
Since the layout of your rendered geometry looks fairly straightforward, could you just figure out in your own code what was drawn at the position the user clicked? That might be simpler in this case, and most likely less error prone.

Selection mode is also a deprecated feature.

Zubaja
04-02-2014, 01:24 AM
@Steven Katic
I've placed the '//draw trains' code in-between the lines you suggested, but nothing comes out of it; I'm not even 100% sure I've done it completely right.

//glRenderMode(GL_SELECT);

gluPickMatrix(x, viewportCoords[3]-y-Integer(not g_Fullscreen)*(GetSystemMetrics(SM_CYCAPTION)+ GetSystemMetrics(SM_CYSIZEFRAME) shl 1), 55, 55, @viewportCoords);

gluPerspective(45.0, viewportCoords[2]/viewportCoords[3], 0.5, 150.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Draw trains here too
for T1 := 0 to Length(trackNames)-1 do
for T2 := 0 to Length(trackTrack)-1 do
if(trackNames[T1] = trackTrack[T2]) then
begin

_Y := -((T1 * trackWidth) + (T1 * trackSpace))+0.5;
glCube(trackFrom[T2]*(trackLength/58),
_Y,
0,
((trackTo[T2]-trackFrom[T2])*(trackLength/58)), //Length
trackWidth, //Height
0.09, //Depth
trackColorR[T2],
trackColorG[T2],
trackColorB[T2]
);

glPrint(trackVoyage[T2],
trackFrom[T2]*(trackLength/58)+1,
_Y+2,
0.1,
textColorR[T2],
textColorG[T2],
textColorB[T2],
false
);
end;

objectsFound := glRenderMode(GL_RENDER);

As you can also see, I turned off 'GL_SELECT' but that doesn't amount to any change either.
I've also looked at 'ApplyCameraTransformations();' but Delphi 2010 doesn't have that function.

@reto.koradi
If you happen to have a function that (magically) translates pixels into units (2D-3D), that'd be grand and a lot of help (No sarcasm intended). Otherwise I'm still stuck.

One thing I forgot to mention was that I also looked into RayCasting, a thing I picked up at college when I was studying Game Development, but I had to give up on that because the tutorials I found were not Delphi 2010 compatible.
And Delphi has some 'glu' functions too, for some reason.

In any case:
I'm still stuck (sadly) with narry a solution in sight. If anyone has a different tutorial for me to follow or possibly a completely different solution, that'd be grand.

##UPDATE##
I've looked up a different method, namely this one (http://nehe.gamedev.net/article/using_gluunproject/16013/).
This time, when I try to get a Vector3 (The result from the function), I get 3x -NAN, which is more (or less, depends on how you look at it since NAN = Not A Number) than the other function I had.

##UPDATE_02##
After editing the code from here (http://nehe.gamedev.net/article/using_gluunproject/16013/), I am finally getting sound digits thrown back at me. They all range from -1 to 1, so I'm guessing that good? Now all I need is to make sure I receive a hit. Any takers on how to do this?