How to select vertex3f on mouse click

Hello there

I have array of points that I draw in OpenGL (code below):

procedure Draw();
begin
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glClearColor(255,255,255,0);
    glLoadIdentity; //biezaca macierz = I
    gluLookAt(0,0,KameraZ, 0,0,0,0,1,0);
    glRotatef(Theta, 1.0, 0.0, 0.0); 
    glRotatef(Phi, 0.0, 1.0, 0.0); 
    glTranslated(MoveX,MoveY,0);  

    glPointSize(2);
    glBegin(GL_POINTS); 
    for I := 0 to High(Stars) - 1 do //stars is my array of array of points
      for j := 0 to High(stars[i]) - 1 do
      begin
        glColor3ub(stars[i,j].R,stars[i,j].g, stars[i,j].b);
        glVertex3i(stars[i,j].x,stars[i,j].y, stars[i,j].distance);
     end;
    glEnd;

    SwapBuffers(wglGetCurrentDC);
end;

In my application onMouseMove event set KameraZ (zoom), Theta & Phi (rotate angle) and MoveX, MoveY (move left/right & up/down).

Now … when user hold shift and click on scene I like to find point under clicked coords (mouse coords converted to opengl coords). After find first one (in this coords can be lot of points but I need only one neares camera look) i like to compare and find this point in my array by X, Y and Distans. I have to do that because point in array (stars) has more informations (OpenGL only show location of this point). I try to do that with such code:


procedure MouseClick(const X, Y: Integer);
type
  T3D_Point = array [1..3] of Double;
var
  i, j: Integer;
  pt: T3D_Point;
  function GetOGLPos(X, Y: Integer): T3D_Point;
  var
      viewport:   array [1..4]  of Integer;
      modelview:  array [1..16] of Double;
      projection: array [1..16] of Double;
      winZ: Single;
  begin
      glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
      glGetDoublev( GL_PROJECTION_MATRIX, projection );
      glGetIntegerv( GL_VIEWPORT, viewport );
      if( Y = 0 )then Y := 1;
      glReadPixels(X, -Y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, winZ );
      gluUnProject(X, viewport[4]-Y, winZ,
              modelview, projection, viewport,
              Result[1], Result[2], Result[3]);
  end;
begin
  pt := GetOGLPos(X,Y);
  for I := 0 to High(stars) do
    for j := 0 to High(stars[i]) do
      if (CompareValue(stars[i,j].x, pt[1], 2) = EqualsValue)  and
         (CompareValue(stars[i,j].y, pt[2], 2) = EqualsValue) then
      begin
        sbar.Panels[0].Text := 'Line:'+IntToStr(i)+',Point:'+IntToStr(j)+
                               ',R:'+FloatToStr(Round(stars[i,j].R))+
                               ',G:'+FloatToStr(Round(stars[i,j].G))+
                               ',B:'+FloatToStr(Round(stars[i,j].B));
        Break;
      end;
end;

procedure pPaintMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
    if (ssShift in Shift) and (Button = mbLeft) then
        MouseClick(x,y);
end;

but even if KameraZ = 100 and Theta, Phi, MoveX and MoveY is set to 0 sbar.Panels[0].Text is empty. Why?

The above should probably be


      glReadPixels(X, viewport[4]-1-Y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, winZ );

Except, viewport[4] is only correct if the viewport covers the entire window. Ideally you should use the actual height of the window.

Here, I’d suggest


      gluUnProject(X+0.5, viewport[2]+viewport[4]-0.5-Y, winZ,

so that you’re projecting the centre of the pixel rather than one corner.

Other than that, I suggest printing out the value of “pt” in case that provides any clues.

I have change my code as you show me but it still not work eg.

X = 503, Y = 339
After run GetOGLPos
pt = (-498,63926995, 29,131270601, -9906,5914513)

and points in stars array is between:
X: -262,26186891 and 289,87443628
Y: -0,90275827758 and 0,53627689465
Z: -15,801837661 and 25,229662989

Well, the Z coordinate appears to be quite a way off, so I suggest checking the value of winZ. If you’re reading the depth for a pixel which wasn’t rendered, everything will be way off.

Another possibility: if you’re using a perspective projection and the near distance is far too small, most of your scene will have very coarse depth resolution, which could be an issue.

I’m not sure if I understund You correctly so here is my all code for OpenGL:


function GL_UstalFormatPikseli(uchwytDC: HDC): Boolean;
var
    opisFormatuPikseli :PIXELFORMATDESCRIPTOR;
    formatPikseli :Integer;
begin
    Result:=False;
    with opisFormatuPikseli do
    begin
        dwFlags:=PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; 
        iPixelType:=PFD_TYPE_RGBA; 
        cColorBits:=32; 
        cDepthBits:=16; 
        iLayerType:=PFD_MAIN_PLANE;
    end;
    formatPikseli:=ChoosePixelFormat(uchwytDC, @opisFormatuPikseli);
    if (formatPikseli=0) then
        Exit;
    if (SetPixelFormat(uchwytDC, formatPikseli, @opisFormatuPikseli) <> True) then
        Exit;
    Result:=True;
end;

procedure InitOpenGL;
begin
    uchwytDC:=GetDC(pPaint.Handle);
    GL_UstalFormatPikseli(uchwytDC);
    uchwytRC:=wglCreateContext(uchwytDC);
    wglMakeCurrent(uchwytDC,uchwytRC);
    glMatrixMode(GL_PROJECTION); 
    glFrustum(-0.1, 0.1, -0.075, 0.075, 0.3, 10000.0); 
    glMatrixMode(GL_MODELVIEW); 
    glEnable(GL_DEPTH_TEST); 
    glClearColor(255,255,255,0);
    KameraZ := 100;
end;

procedure Draw();
var
  i,j: Integer;
begin
    glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    glClearColor(255,255,255,0);
    glLoadIdentity; 
    glTranslated(MoveX,-MoveY,0);
    gluLookAt(0,0,KameraZ, 0,0,0, 0,1,0); 
    glRotatef(Theta, 1.0, 0.0, 0.0); 
    glRotatef(Phi, 0.0, 1.0, 0.0); 
    glPointSize(2);
    glBegin(GL_POINTS); 
    for I := 0 to High(Stars)  do //stars is my array of array of points
      for j := 0 to High(stars[i])  do
      begin
        glColor3ub(stars[i,j].R,stars[i,j].g, stars[i,j].b);
        glVertex3i(stars[i,j].x,stars[i,j].y, stars[i,j].distance);
     end;
    glEnd;
    SwapBuffers(wglGetCurrentDC);
end;

And on resize of TFrame is:

procedure FrameResize(Sender: TObject);
begin
    glViewport(0,0,pPaint.Width,pPaint.Height);
end;

Between these two, you’re only using around 185 distinct depth values with the default viewpoint. The nearest star will be 75 units from the viewpoint, which is 250 times the near distance, meaning that the region between the nearest star and the far plane only uses around 1/250th of the depth range; with a 16-bit depth buffer, that’s around 262 distinct values.

But that’s not the issue here. The Z value of -9906.6 from your previous message corresponds to a point that’s exactly on the far plane (to within the accuracy of single-precision floating point), i.e. you’re reading the depth value for a pixel that wasn’t rendered to.

Check that the mouse coordinates are what you expect, i.e. (0,0) is the top-left corner of the OpenGL viewport. If it’s reporting screen coordinates or coordinates relative to the window frame, you’ll be reading the wrong pixel.

[QUOTE=woolfik;1279256]
Now … when user hold shift and click on scene I like to find point under clicked coords (mouse coords converted to opengl coords). After find first one (in this coords can be lot of points but I need only one neares camera look) i like to compare and find this point in my array by X, Y and Distans. I have to do that because point in array (stars) has more informations (OpenGL only show location of this point).[/QUOTE]
I’m sorry for interfering, but why don’t you use a selection mechanism available in the legacy OpenGL?
It would save you from all the trouble, like converting the screen coordinates to the normalized device coordinates (results are already in NDC), from searching other structures to find the star data (selection retrieves its ID or a pointer to the particular data), from picking the exact point (a buffer around the cursor can be defined), it retrieves all objects intersecting defined picking frustum, and does whatever you need about selection. So the question is really obvious: Why don’t you use it?

Aleksandar because I don’t know this selection mechanizm and I’m new in OpenGL. Can You show me some example based on my code? (it can be in C++ it does not mather wich language). I need to understund how this vertexf can be selection and how to operate on this selection in my OnMouse event.

I believe that he’s referring to glRenderMode(GL_SELECT).

This is covered in some detail in the red book.