Picking / Selecting

Selecting a mesh or picking a specific triangle of a mesh are well known everyday challenges. Since v1.1.0.2927 we've fixed and optimized our set of methods.

You can now perform a raycast intersect test or a pick triangle call on a model or mesh and it will also test containing sub-meshes.

MethodDescription
function RayCastIntersect(const ARayPos, ARayDir: TPoint3D; var AIntersection, ANormal: TPoint3D) : Boolean;Perform a ray cast on this mesh. CAUTION: absolute ray position and ray direction expected!
function PickTriangle(const X, Y : Single; var AIntersection, ANormal: TPoint3D; out A, B, C : TPoint3D) : Boolean;Detects an intersected triangle by a screen point. The method converts screen coordinates to 3d coordinates and calls PickTriangle() routine with the corresponding raypos and raydir. If intersection was successful, the method returns the intersection 3D coordinate and the normal vector at this position. Otherwise those values are undefined. If intersection was successful, the method returns the absolute triangle corner coordinates. Otherwise A, B and C are zero.
function PickTriangle(const X, Y : Single; var AResult : TTriangleRayCastResult) : Boolean;Detects an intersected triangle by a screen point. The method converts screen coordinates to 3d coordinates and calls PickTriangle() routine with the corresponding raypos and raydir. If intersection was successful, the method returns the TTriangleRayCastResult structure containing the intersection point, the normal at this position, the 3 corner vertex positions and if a object could be detected the instance those data belongs to. Otherwise this structure is undefined.
function PickTriangle(const ARayPos, ARayDir: TVector3D; var AIntersection, ANormal: TPoint3D; out A, B, C : TPoint3D) : Boolean;Detects an intersected triangle by an absolute raypos and raydir! If intersection was successful, the method returns the intersection 3D coordinate and the normal vector at this position. Otherwise those values are undefined. If intersection was successful, the method returns the absolute triangle corner coordinates. Otherwise A, B and C are zero.
function PickTriangle(const ARayPos, ARayDir: TVector3D; var AResult : TTriangleRayCastResult) : Boolean;Detects an intersected triangle by an absolute raypos and raydir! If intersection was successful, the method returns the TTriangleRayCastResult structure containing the intersection point, the normal at this position, the 3 corner vertex positions and if a object could be detected the instance those data belongs to. Otherwise this structure is undefined.

Use the extended calls with the TTriangleRayCastResult result for detailed information about the picked data.

The TTriangleRayCastResult record has the following structure:

  TTriangleRayCastResult = record
    T            : Single;
    Normal       : TPoint3D;
    Hit          : Boolean;
    Intersection : TPoint3D;
    Instance     : TObject; // TCustomMeshDef/TMeshDef/TGorillaMesh
    Triangle     : Array[0..2] of TPoint3D;
  end;

As example, you can register an OnMouseUp event on your specific mesh/model or sub-mesh. Within your OnMouseUp event you can then perform the raycasting or triangle picking:

procedure TForm1.MyMeshMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
var LAbsRayPos, LAbsRayDir : TVector3D;
    LIntersect, LNormal : TPoint3D;
    LMesh : TGorillaMesh;
    LTriResult  : TTriangleRayCastResult;
begin
  LMesh := Sender as TGorillaMesh;
 
  if not Assigned(LMesh) then
    Exit;
 
  // Convert from local vector to absolute, because we're currently in object space
  LAbsRayPos := LMesh.LocalToAbsoluteVector(ARayPos);
  LAbsRayDir := LMesh.LocalToAbsoluteDirection(ARayDir);
 
  // Perform a raycast intersection test and if it hits the mesh, show a message 
  if LMesh.RayCastIntersect(LAbsRayPos, LAbsRayDir, LIntersect, LNormal) then
    ShowMessage(Format('Intersection-Point = (%n, %n, %n)', [LIntersect.X, LIntersect.Y, LIntersect.Z]));
 
  // Or perform a triangle pick and output the triangle points and the instance pointer too
  if LMesh.PickTriangle(LAbsRayPos, LAbsRayDir, LTriResult) then
    ShowMessage(Format('instance=%d, Intersection-Point = (%n, %n, %n), triangle-P1=(%n,%n,%n), triangle-P2=(%n,%n,%n), triangle-P3=(%n,%n,%n)', 
      [
      NativeUInt(LTriResult.Instance),
      LTriResult.Intersection.X, LTriResult.Intersection.Y, LTriResult.Intersection.Z,
 
      LTriResult.Triangle[0].X, LTriResult.Triangle[0].Y, LTriResult.Triangle[0].Z,
      LTriResult.Triangle[1].X, LTriResult.Triangle[1].Y, LTriResult.Triangle[1].Z,
      LTriResult.Triangle[2].X, LTriResult.Triangle[2].Y, LTriResult.Triangle[2].Z
      ]));
end;

Next step: CharacterControlling