Collisions.pas
资源名称:CAST2SDK.rar [点击查看]
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:17k
源码类别:
游戏引擎
开发平台:
Delphi
- (*
- @Abstract(Collisions unit)
- (C) 2006-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
- The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
- Unit contains collision detection routines
- *)
- {$Include GDefines.inc}
- unit Collisions;
- interface
- uses BaseTypes, Base3D;
- type
- // Bounding volume kind
- TBoundingVolumeKind = (// Object-oriented bounding box
- bvkOOBB,
- // Bounding sphere
- bvkSphere);
- { Bounding volume data structure
- <b>VolumeKind</b> - bvkOOBB - object-oriented bounding box, bvkSphere - sphere
- <b>Offset</b> - offset of the volume's center
- <b>Dimensions</b> - half-size of a box or radius of a sphere (in x component) }
- TBoundingVolume = record
- VolumeKind: TBoundingVolumeKind;
- Offset, Dimensions: BaseTypes.TVector3s;
- end;
- // Array of bounding volumes
- TBoundingVolumes = array of TBoundingVolume;
- // Data structure of a collision-test result. Contains the two collided volumes or <b>nils</b> if no collision detected
- TCollisionResult = record
- Vol1, Vol2: ^TBoundingVolume;
- end;
- { Returns <b>True</b> if a ray with the specified origin and direction intersects with a sphere with the specified origin and radius.
- Point is filled with the nearest to ray origin intersection point if any }
- function RaySphereColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
- { Returns <b>True</b> if a ray with the specified origin and direction intersects with a sphere with the specified origin and radius.
- Point is filled with the nearest to ray origin intersection point if any }
- function RayCircleColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
- { Returns <b>True</b> if the given sphere intersects with the given OOBB.
- <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
- function SphereOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const Sphere, OOBB: TBoundingVolume): Boolean;
- { Returns <b>True</b> if the two given OOBBs intersects.
- <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
- function OOBBOOBBColDet (const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean;
- { Returns <b>True</b> if the two given OOBBs intersects in XZ plane. It's faster then @Link(OOBBOOBBColDet) a little.
- <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volumes within the world space and should not contain scale. }
- function OOBBOOBBColDet2D(const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean;
- { Checks two arrays of bounding volumes for collision and returns result in @Link(TCollisionResult) structure.
- <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volume arrays within the world space and should not contain scale. }
- function VolumeColDet(Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): TCollisionResult;
- { Returns <b>True</b> if there is an intersection between bounding volumes from the given arrays.
- <b>Transform1</b> and <b>Transform2</b> specifies location and orientation of the volume arrays within the world space and should not contain scale. }
- function VolumeColTest(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): Boolean; //
- // function VolumeColDet2D(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): TCollisionResult; // ToFix: Take location in account
- // function VolumeColTest2D(const Volume1, Volume2: TBoundingVolumes; const Transform1, Transform2: Base3D.TMatrix4s): Boolean; //
- implementation
- function RaySphereColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
- var B, C, D, t1, t2: Single;
- begin
- Result := False;
- Point := SubVector3s(RayOrigin, SphereOrigin);
- B := 2 * DotProductVector3s(Point, RayDir);
- C := SqrMagnitude(Point) - Sqr(SphereRadius);
- D := B*B - 4 * C;
- if D < 0 then Exit;
- if D > 0 then begin
- t1 := -B - Sqrt(D);
- t2 := -B + Sqrt(D);
- if (t1 < 0) and (t2 < 0) then Exit;
- if (t1 < t2) and (t1 >= 0) then B := -t1 else if t2 >= 0 then B := -t2 else B := -t1;
- end;
- Point := AddVector3s(RayOrigin, ScaleVector3s(RayDir, -B * 0.5));
- Result := True;
- end;
- function RayCircleColDet(const RayOrigin, RayDir, SphereOrigin: BaseTypes.TVector3s; SphereRadius: Single; var Point: BaseTypes.TVector3s): Boolean;
- var B, C, D, t1, t2: Single;
- begin
- Result := False;
- Point := SubVector3s(RayOrigin, SphereOrigin);
- Point.Y := 0;
- B := 2 * DotProductVector3s(Point, RayDir);
- C := SqrMagnitude(Point) - Sqr(SphereRadius);
- D := B*B - 4 * C;
- if D < 0 then Exit;
- if D > 0 then begin
- t1 := -B - Sqrt(D);
- t2 := -B + Sqrt(D);
- if (t1 < 0) and (t2 < 0) then Exit;
- if (t1 < t2) and (t1 >= 0) then B := -t1 else if t2 >= 0 then B := -t2 else B := -t1;
- end;
- Point := AddVector3s(RayOrigin, ScaleVector3s(RayDir, -B * 0.5));
- Point.Y := 0;
- Result := True;
- end;
- function SphereOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const Sphere, OOBB: TBoundingVolume): Boolean;
- var d, a: Single; i: Integer; SPos: BaseTypes.TVector3s; InverseT2: Base3D.TMatrix3s;
- begin
- InverseT2 := CutMatrix3s(Transform2);
- TransposeMatrix3s(InverseT2);
- SPos := SubVector4s(Transform4Vector3s(Transform2, OOBB.Offset), Transform4Vector3s(Transform1, Sphere.Offset)).xyz;
- SPos := Transform3Vector3s(InverseT2, SPos);
- d := 0; i := 0;
- while i <= 2 do begin
- if (SPos.v[i] < -OOBB.Dimensions.v[i]{*M2.M[i, i]}) then begin
- a := SPos.v[i] + OOBB.Dimensions.v[i]{*M2.M[i, i]};
- d := d + a * a;
- end else if (SPos.v[i] > OOBB.Dimensions.v[i]{*M2.M[i, i]}) then begin
- a := SPos.v[i] - OOBB.Dimensions.v[i]{*M2.M[i, i]};
- d := d + a * a;
- end;
- Inc(i);
- end;
- Result := d <= Sphere.Dimensions.X * Sphere.Dimensions.X;
- end;
- function OOBBOOBBColDet(const Transform1, Transform2: Base3D.TMatrix4s; const OOBB1, OOBB2: TBoundingVolume): Boolean; // 襄疱皴麇龛