Collisions.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:17k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Collisions unit)
  3.  (C) 2006-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains collision detection routines
  6. *)
  7. {$Include GDefines.inc}
  8. unit Collisions;
  9. interface
  10. uses BaseTypes, Base3D;
  11. type
  12.   // Bounding volume kind
  13.   TBoundingVolumeKind = (// Object-oriented bounding box
  14.                          bvkOOBB,
  15.                          // Bounding sphere
  16.                          bvkSphere);
  17.   { Bounding volume data structure
  18.     <b>VolumeKind</b>    - bvkOOBB - object-oriented bounding box, bvkSphere - sphere
  19.     <b>Offset</b>        - offset of the volume's center
  20.     <b>Dimensions</b>    - half-size of a box or radius of a sphere (in x component) }
  21.   TBoundingVolume = record
  22.     VolumeKind: TBoundingVolumeKind;
  23.     Offset, Dimensions: BaseTypes.TVector3s;
  24.   end;
  25.   // Array of bounding volumes
  26.   TBoundingVolumes = array of TBoundingVolume;
  27.   // Data structure of a collision-test result. Contains the two collided volumes or <b>nils</b> if no collision detected
  28.   TCollisionResult = record
  29.     Vol1, Vol2: ^TBoundingVolume;
  30.   end;
  31.   { Returns <b>True</b> if a ray with the specified origin and direction intersects with a sphere with the specified origin and radius.
  32.     Point is filled with the nearest to ray origin intersection point if any }
  33.   function RaySphereColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
  34.   { Returns <b>True</b> if a ray with the specified origin and direction intersects with a sphere with the specified origin and radius.
  35.     Point is filled with the nearest to ray origin intersection point if any }
  36.   function RayCircleColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
  37.   { Returns <b>True</b> if the given sphere intersects with the given OOBB.
  38.     <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
  39.   function SphereOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const Sphere, OOBB: TBoundingVolume): Boolean;
  40.   { Returns <b>True</b> if the two given OOBBs intersects.
  41.     <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
  42.   function OOBBOOBBColDet  (const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean;
  43.   { Returns <b>True</b> if the two given OOBBs intersects in XZ plane. It's faster then @Link(OOBBOOBBColDet) a little.
  44.     <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
  45.   function OOBBOOBBColDet2D(const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean;
  46.   { Checks two arrays of bounding volumes for collision and returns result in @Link(TCollisionResult) structure.
  47.     <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volume arrays within the world space and should not contain scale. }
  48.   function VolumeColDet(Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): TCollisionResult;
  49.   { Returns <b>True</b> if there is an intersection between bounding volumes from the given arrays.
  50.     <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volume arrays within the world space and should not contain scale. }
  51.   function VolumeColTest(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): Boolean;                                       //
  52. //  function VolumeColDet2D(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): TCollisionResult;     // ToFix: Take location in account
  53. //  function VolumeColTest2D(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): Boolean;                                       //
  54. implementation
  55. function RaySphereColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
  56. var B, C, D, t1, t2: Single;
  57. begin
  58.   Result := False;
  59.   Point := SubVector3s(RayOrigin, SphereOrigin);
  60.   B := 2 * DotProductVector3s(Point, RayDir);
  61.   C := SqrMagnitude(Point) - Sqr(SphereRadius);
  62.   D := B*B - 4 * C;
  63.   if D < 0 then Exit;
  64.   if D > 0 then begin
  65.     t1 := -B - Sqrt(D);
  66.     t2 := -B + Sqrt(D);
  67.     if (t1 < 0) and (t2 < 0) then Exit;
  68.     if (t1 < t2) and (t1 >= 0) then B := -t1 else if t2 >= 0 then B := -t2 else B := -t1;
  69.   end;
  70.   Point := AddVector3s(RayOrigin, ScaleVector3s(RayDir, -B * 0.5));
  71.   Result := True;
  72. end;
  73. function RayCircleColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
  74. var B, C, D, t1, t2: Single;
  75. begin
  76.   Result := False;
  77.   Point := SubVector3s(RayOrigin, SphereOrigin);
  78.   Point.Y := 0;
  79.   B := 2 * DotProductVector3s(Point, RayDir);
  80.   C := SqrMagnitude(Point) - Sqr(SphereRadius);
  81.   D := B*B - 4 * C;
  82.   if D < 0 then Exit;
  83.   if D > 0 then begin
  84.     t1 := -B - Sqrt(D);
  85.     t2 := -B + Sqrt(D);
  86.     if (t1 < 0) and (t2 < 0) then Exit;
  87.     if (t1 < t2) and (t1 >= 0) then B := -t1 else if t2 >= 0 then B := -t2 else B := -t1;
  88.   end;              
  89.   Point := AddVector3s(RayOrigin, ScaleVector3s(RayDir, -B * 0.5));
  90.   Point.Y := 0;
  91.   Result := True;
  92. end;
  93. function SphereOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const Sphere, OOBB: TBoundingVolume): Boolean;
  94. var d, a: Single; i: Integer; SPos: BaseTypes.TVector3s; InverseT2: Base3D.TMatrix3s;
  95. begin
  96.   InverseT2 := CutMatrix3s(Transform2);
  97.   TransposeMatrix3s(InverseT2);
  98.   SPos := SubVector4s(Transform4Vector3s(Transform2, OOBB.Offset), Transform4Vector3s(Transform1, Sphere.Offset)).xyz;
  99.   SPos := Transform3Vector3s(InverseT2, SPos);
  100.   d := 0; i := 0;
  101.   while i <= 2 do begin
  102.     if (SPos.v[i] < -OOBB.Dimensions.v[i]{*M2.M[i, i]}) then begin
  103.       a := SPos.v[i] + OOBB.Dimensions.v[i]{*M2.M[i, i]};
  104.       d := d + a * a;
  105.     end else if (SPos.v[i] > OOBB.Dimensions.v[i]{*M2.M[i, i]}) then begin
  106.       a := SPos.v[i] - OOBB.Dimensions.v[i]{*M2.M[i, i]};
  107.       d := d + a * a;
  108.     end;
  109.     Inc(i);
  110.   end;
  111.   Result := d <= Sphere.Dimensions.X * Sphere.Dimensions.X;
  112. end;
  113. function OOBBOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean;     // 襄疱皴麇龛