Search code examples
delphidelphi-xe3glscene

GLScene picking


I have been using GLSceneViewer1.Buffer.GetPickedObject( x, y ) to pick GLscene objects in a GLViewerMouseDown event per the pick demo. I need to select an object, change the color, with a left mouse click and deselect with another left mouse click, and if another object is selected it is deselected. It seems that TGLSceneObject needs a property IsPicked : boolean for me to be able to achieve this. If someone knows away of doing this with out modifying GLScene would be cool. Here is the code I wrote it sort of works but sort of doesn't. SetSelected( Selected, SelectedColor ) just changes the color of the selected object.

procedure TForm32.GLSceneViewer1MouseDown( Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer );
  var
    Selected : TGLSceneObject;
    AButton : TGLMouseButton;
  begin
    AButton := TGLMouseButton( Button );

    // if an object is picked...
    Selected := ( GLSceneViewer1.Buffer.GetPickedObject( x, y ) as TGLSceneObject );

      case AButton of
        mbLeft:
          begin
              if( Selected <> UnSelected ) then
                begin
                   if( Assigned( Selected ) ) then
                      begin
                        SetSelected( Selected, SelectedColor );
                        StatusBar1.Panels[0].Text := 'Selected';
                        UnSelected := Selected;
                      end
                   else
                    if( not Assigned( Selected ) ) then
                      begin
                        UnSelected.Material.FrontProperties.Emission.Color:= clrBlack;
                        UnSelected.Material.FrontProperties.Ambient.Color := clrGray20;
                        UnSelected.Material.FrontProperties.Diffuse.Color := clrGray80;
                        StatusBar1.Panels[0].Text := 'Unselected';
                        UnSelected := Selected;
                      end;
                end;
          end;
      end;
  end;

To me this would be easier:

procedure TForm32.GLSceneViewer1MouseDown( Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer );
  var
    Selected : TGLSceneObject;
  begin
    Selected := ( GLSceneViewer1.Buffer.GetPickedObject( x, y ) as TGLSceneObject );
      if( not Selected.IsPicked ) then
        SetSelected( Selected, SelectedColor )
      else
        SetSelected( Selected, UnSelectedColor );
   end;

Solution

  • After some debating on whether I should break my GLScene library by modifying the source code which would necessitate having to distribute the source code, which didn't seem ideal to me, I have come up with the following code as an answer to my problem. The answer it seemed was to maintain a TGLSceneObject buffer object which I named CurrentSelection.

    procedure TForm32.GLSceneViewer1MouseDown( Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer );
      //CurrentSelection : TGLSceneObject; //TForm private declaration
      //Selected : TGLSceneObject; //TForm private declaration
      begin
        Selected := ( GLSceneViewer1.Buffer.GetPickedObject( x, y ) as TGLSceneObject );
          if( Selected <> nil ) then  //Avoid access violation error
            begin
              if( Assigned( CurrentSelection ) ) then //If CurrentSelection is not nil deselect it
                SetSelectedColor( CurrentSelection, UnSelectedColor );
    
              if( Selected = CurrentSelection ) then 
                begin 
                  //has the same object been clicked then deselect it and clear the buffer object
                  SetSelectedColor( Selected, UnSelectedColor );
                  CurrentSelection := nil;
                end
              else
                begin 
                  //if no object is selected select an object, set the color and assign the object to the buffer
                  SetSelectedColor( Selected, SelectedColor );
                  CurrentSelection := Selected;
                end;
            end;
      end;
    

    Set the color of the TGLSceneObject

    procedure TForm32.SetSelectedColor( Selected : TGLSceneObject; Color : TColorVector );
      begin
        Selected.Material.FrontProperties.Ambient.Color := Color;
        Selected.Material.FrontProperties.Diffuse.Color := Color;
        Selected.Material.FrontProperties.Emission.Color:= clrBlack;
      end;
    

    The above code doesn't check which mouse button has been used, but I can select an object, deselect the object and when another object is selected it deselects the current object.

    I will need to modify it to set the deselected object to its original colour/material but that should be relatively simple.

    Cheers :)