Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

450 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Common collision utility methods
  4. //
  5. // $Header: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef COLLISIONUTILS_H
  9. #define COLLISIONUTILS_H
  10. #include "tier0/platform.h"
  11. #ifdef _WIN32
  12. #pragma once
  13. #endif
  14. #include "mathlib/ssemath.h"
  15. //-----------------------------------------------------------------------------
  16. // forward declarations
  17. //-----------------------------------------------------------------------------
  18. struct Ray_t;
  19. class Vector;
  20. class Vector2D;
  21. class Vector4D;
  22. struct cplane_t;
  23. class QAngle;
  24. class CBaseTrace;
  25. struct matrix3x4_t;
  26. //-----------------------------------------------------------------------------
  27. //
  28. // IntersectRayWithTriangle
  29. //
  30. // Intersects a ray with a triangle, returns distance t along ray.
  31. // t will be less than zero if no intersection occurred
  32. // oneSided will cull collisions which approach the triangle from the back
  33. // side, assuming the vertices are specified in counter-clockwise order
  34. // The vertices need not be specified in that order if oneSided is not used
  35. //
  36. //-----------------------------------------------------------------------------
  37. float IntersectRayWithTriangle( const Ray_t& ray,
  38. const Vector& v1, const Vector& v2, const Vector& v3,
  39. bool oneSided );
  40. //-----------------------------------------------------------------------------
  41. //
  42. // ComputeIntersectionBarycentricCoordinates
  43. //
  44. // Figures out the barycentric coordinates (u,v) where a ray hits a
  45. // triangle. Note that this will ignore the ray extents, and it also ignores
  46. // the ray length. Note that the edge from v1->v2 represents u (v2: u = 1),
  47. // and the edge from v1->v3 represents v (v3: v = 1). It returns false
  48. // if the ray is parallel to the triangle (or when t is specified if t is less
  49. // than zero).
  50. //
  51. //-----------------------------------------------------------------------------
  52. bool ComputeIntersectionBarycentricCoordinates( const Ray_t& ray,
  53. const Vector& v1, const Vector& v2, const Vector& v3, float& u, float& v,
  54. float *t = 0 );
  55. //-----------------------------------------------------------------------------
  56. //
  57. // IntersectRayWithRay
  58. //
  59. // Returns whether or not there was an intersection. The "t" paramter is the
  60. // distance along ray0 and the "s" parameter is the distance along ray1. If
  61. // the two lines to not intersect the "t" and "s" represent the closest approach.
  62. // "t" and "s" will not change if the rays are parallel.
  63. //
  64. //-----------------------------------------------------------------------------
  65. bool IntersectRayWithRay( const Ray_t &ray0, const Ray_t &ray1, float &t, float &s );
  66. //-----------------------------------------------------------------------------
  67. //
  68. // IntersectRayWithSphere
  69. //
  70. // Returns whether or not there was an intersection. Returns the two intersection points.
  71. // NOTE: The point of closest approach can be found at the average t value.
  72. //
  73. //-----------------------------------------------------------------------------
  74. bool IntersectRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta, const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 );
  75. //-----------------------------------------------------------------------------
  76. //
  77. // IntersectInfiniteRayWithSphere
  78. //
  79. // Returns whether or not there was an intersection of a sphere against an infinitely
  80. // extending ray.
  81. // Returns the two intersection points
  82. //
  83. //-----------------------------------------------------------------------------
  84. bool IntersectInfiniteRayWithSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  85. const Vector &vecSphereCenter, float flRadius, float *pT1, float *pT2 );
  86. // returns true if the sphere and cone intersect
  87. // NOTE: cone sine/cosine are the half angle of the cone
  88. bool IsSphereIntersectingCone( const Vector &sphereCenter, float sphereRadius, const Vector &coneOrigin, const Vector &coneNormal, float coneSine, float coneCosine );
  89. //-----------------------------------------------------------------------------
  90. //
  91. // IntersectRayWithPlane
  92. //
  93. // Intersects a ray with a plane, returns distance t along ray.
  94. // t will be less than zero the intersection occurs in the opposite direction of the ray.
  95. //
  96. //-----------------------------------------------------------------------------
  97. float IntersectRayWithPlane( const Ray_t& ray, const cplane_t& plane );
  98. float IntersectRayWithPlane( const Vector& org, const Vector& dir, const cplane_t& plane );
  99. float IntersectRayWithPlane( const Vector& org, const Vector& dir, const Vector& normal, float dist );
  100. // This version intersects a ray with an axis-aligned plane
  101. float IntersectRayWithAAPlane( const Vector& vecStart, const Vector& vecEnd, int nAxis, float flSign, float flDist );
  102. //-----------------------------------------------------------------------------
  103. // IntersectRayWithBox
  104. //
  105. // Purpose: Computes the intersection of a ray with a box (AABB)
  106. // Output : Returns true if there is an intersection + trace information
  107. //-----------------------------------------------------------------------------
  108. bool IntersectRayWithBox( const Vector &rayStart, const Vector &rayDelta, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL );
  109. bool IntersectRayWithBox( const Ray_t &ray, const Vector &boxMins, const Vector &boxMaxs, float epsilon, CBaseTrace *pTrace, float *pFractionLeftSolid = NULL );
  110. //-----------------------------------------------------------------------------
  111. // Intersects a ray against a box
  112. //-----------------------------------------------------------------------------
  113. struct BoxTraceInfo_t
  114. {
  115. float t1;
  116. float t2;
  117. int hitside;
  118. bool startsolid;
  119. };
  120. bool IntersectRayWithBox( const Vector &vecRayStart, const Vector &vecRayDelta,
  121. const Vector &boxMins, const Vector &boxMaxs, float flTolerance, BoxTraceInfo_t *pTrace );
  122. //-----------------------------------------------------------------------------
  123. // IntersectRayWithOBB
  124. //
  125. // Purpose: Computes the intersection of a ray with a oriented box (OBB)
  126. // Output : Returns true if there is an intersection + trace information
  127. //-----------------------------------------------------------------------------
  128. bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta,
  129. const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs,
  130. float flTolerance, CBaseTrace *pTrace );
  131. bool IntersectRayWithOBB( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  132. const Vector &vecBoxOrigin, const QAngle &angBoxRotation,
  133. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  134. bool IntersectRayWithOBB( const Ray_t &ray, const Vector &vecBoxOrigin, const QAngle &angBoxRotation,
  135. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  136. bool IntersectRayWithOBB( const Ray_t &ray, const matrix3x4_t &matOBBToWorld,
  137. const Vector &vecOBBMins, const Vector &vecOBBMaxs, float flTolerance, CBaseTrace *pTrace );
  138. bool IntersectRayWithOBB( const Vector &vecRayStart, const Vector &vecRayDelta,
  139. const matrix3x4_t &matOBBToWorld, const Vector &vecOBBMins, const Vector &vecOBBMaxs,
  140. float flTolerance, BoxTraceInfo_t *pTrace );
  141. //-----------------------------------------------------------------------------
  142. //
  143. // IsSphereIntersectingSphere
  144. //
  145. // returns true if there's an intersection between sphere and sphere
  146. //
  147. //-----------------------------------------------------------------------------
  148. bool IsSphereIntersectingSphere( const Vector& center1, float radius1,
  149. const Vector& center2, float radius2 );
  150. //-----------------------------------------------------------------------------
  151. //
  152. // IsBoxIntersectingSphere
  153. //
  154. // returns true if there's an intersection between box and sphere
  155. //
  156. //-----------------------------------------------------------------------------
  157. bool IsBoxIntersectingSphere( const Vector& boxMin, const Vector& boxMax,
  158. const Vector& center, float radius );
  159. bool IsBoxIntersectingSphereExtents( const Vector& boxCenter, const Vector& boxHalfDiag,
  160. const Vector& center, float radius );
  161. //-----------------------------------------------------------------------------
  162. // returns true if there's an intersection between ray and sphere
  163. //-----------------------------------------------------------------------------
  164. bool IsRayIntersectingSphere( const Vector &vecRayOrigin, const Vector &vecRayDelta,
  165. const Vector &vecSphereCenter, float flRadius, float flTolerance = 0.0f );
  166. //-----------------------------------------------------------------------------
  167. //
  168. // IsCircleIntersectingRectangle
  169. //
  170. // returns true if there's an intersection between rectangle and circle
  171. //
  172. //-----------------------------------------------------------------------------
  173. bool IsCircleIntersectingRectangle( const Vector2D& boxMin, const Vector2D& boxMax,
  174. const Vector2D& center, float radius );
  175. //-----------------------------------------------------------------------------
  176. //
  177. // IsBoxIntersectingBox
  178. //
  179. // returns true if there's an intersection between two boxes
  180. //
  181. //-----------------------------------------------------------------------------
  182. bool IsBoxIntersectingBox( const Vector& boxMin1, const Vector& boxMax1,
  183. const Vector& boxMin2, const Vector& boxMax2 );
  184. bool IsBoxIntersectingBoxExtents( const Vector& boxCenter1, const Vector& boxHalfDiagonal1,
  185. const Vector& boxCenter2, const Vector& boxHalfDiagonal2 );
  186. #ifdef _X360
  187. // inline version:
  188. #include "mathlib/ssemath.h"
  189. inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1,
  190. const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 );
  191. #endif
  192. //-----------------------------------------------------------------------------
  193. //
  194. // IsOBBIntersectingOBB
  195. //
  196. // returns true if there's an intersection between two OBBs
  197. //
  198. //-----------------------------------------------------------------------------
  199. bool IsOBBIntersectingOBB( const Vector &vecOrigin1, const QAngle &vecAngles1, const Vector& boxMin1, const Vector& boxMax1,
  200. const Vector &vecOrigin2, const QAngle &vecAngles2, const Vector& boxMin2, const Vector& boxMax2, float flTolerance = 0.0f );
  201. //-----------------------------------------------------------------------------
  202. //
  203. // IsBoxIntersectingRay
  204. //
  205. // returns true if there's an intersection between box and ray
  206. //
  207. //-----------------------------------------------------------------------------
  208. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  209. const Vector& origin, const Vector& delta, float flTolerance = 0.0f );
  210. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  211. const Ray_t& ray, float flTolerance = 0.0f );
  212. bool FASTCALL IsBoxIntersectingRay( const Vector& boxMin, const Vector& boxMax,
  213. const Vector& origin, const Vector& delta,
  214. const Vector& invDelta, float flTolerance = 0.0f );
  215. // On the PC, we can't pass fltx4's in registers like this. On the x360, it is
  216. // much better if we do.
  217. #ifdef _X360
  218. bool FASTCALL IsBoxIntersectingRay( fltx4 boxMin, fltx4 boxMax,
  219. fltx4 origin, fltx4 delta, fltx4 invDelta, // ray parameters
  220. fltx4 vTolerance = LoadZeroSIMD() ///< eg from ReplicateX4(flTolerance)
  221. );
  222. #else
  223. bool FASTCALL IsBoxIntersectingRay( const fltx4 &boxMin, const fltx4 &boxMax,
  224. const fltx4 & origin, const fltx4 & delta, const fltx4 & invDelta, // ray parameters
  225. const fltx4 & vTolerance = Four_Zeros ///< eg from ReplicateX4(flTolerance)
  226. );
  227. #endif
  228. bool inline FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax,
  229. const fltx4& origin, const fltx4& delta, float flTolerance = 0.0f )
  230. {
  231. return IsBoxIntersectingRay( boxMin, boxMax, origin, delta, ReciprocalSIMD(delta), ReplicateX4(flTolerance) );
  232. }
  233. bool FASTCALL IsBoxIntersectingRay( const fltx4& boxMin, const fltx4& boxMax,
  234. const Ray_t& ray, float flTolerance = 0.0f );
  235. //-----------------------------------------------------------------------------
  236. //
  237. // IsPointInBox
  238. //
  239. // returns true if the point is in the box
  240. //
  241. //-----------------------------------------------------------------------------
  242. bool IsPointInBox( const Vector& pt, const Vector& boxMin, const Vector& boxMax );
  243. // SIMD version
  244. FORCEINLINE bool IsPointInBox( const fltx4& pt, const fltx4& boxMin, const fltx4& boxMax )
  245. {
  246. fltx4 greater = CmpGtSIMD( pt,boxMax );
  247. fltx4 less = CmpLtSIMD( pt, boxMin );
  248. return (IsAllZeros(SetWToZeroSIMD(OrSIMD(greater,less))));
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: returns true if pt intersects the truncated cone
  252. // origin - cone tip, axis unit cone axis, cosAngle - cosine of cone axis to surface angle
  253. //-----------------------------------------------------------------------------
  254. bool IsPointInCone( const Vector &pt, const Vector &origin, const Vector &axis, float cosAngle, float length );
  255. //-----------------------------------------------------------------------------
  256. // Intersects a plane with a triangle (using barycentric definition)
  257. // The return value, in pIntersection, is an array of barycentric coordinates
  258. // describing at most 2 intersection points.
  259. // The return value is the number of intersection points
  260. //-----------------------------------------------------------------------------
  261. int IntersectTriangleWithPlaneBarycentric( const Vector& org, const Vector& edgeU, const Vector& edgeV,
  262. const Vector4D& plane, Vector2D* pIntersection );
  263. //-----------------------------------------------------------------------------
  264. //
  265. // PointInQuadBarycentric
  266. //
  267. // Given a point and a quad in a plane return the u and v (barycentric) positions
  268. // of the point relative to the quad. The points (v1,v2,v3,v4) should be given
  269. // in a counter-clockwise order with v1 acting as the primary corner (u=0, v=0).
  270. // Thus, u0 = v2 - v1, and v0 = v4 - v1.
  271. //
  272. //-----------------------------------------------------------------------------
  273. enum QuadBarycentricRetval_t
  274. {
  275. BARY_QUADRATIC_FALSE = 0,
  276. BARY_QUADRATIC_TRUE = 1,
  277. BARY_QUADRATIC_NEGATIVE_DISCRIMINANT = 2
  278. };
  279. QuadBarycentricRetval_t PointInQuadToBarycentric( const Vector &v1, const Vector &v2,
  280. const Vector &v3, const Vector &v4, const Vector &point, Vector2D &uv );
  281. void PointInQuadFromBarycentric( const Vector &v1, const Vector &v2, const Vector &v3, const Vector &v4,
  282. const Vector2D &uv, Vector &point );
  283. void TexCoordInQuadFromBarycentric( const Vector2D &v1, const Vector2D &v2, const Vector2D &v3, const Vector2D &v4,
  284. const Vector2D &uv, Vector2D &texCoord );
  285. //-----------------------------------------------------------------------------
  286. // Compute point from barycentric specification
  287. // Edge u goes from v0 to v1, edge v goes from v0 to v2
  288. //-----------------------------------------------------------------------------
  289. void ComputePointFromBarycentric( const Vector& v0, const Vector& v1, const Vector& v2,
  290. float u, float v, Vector& pt );
  291. void ComputePointFromBarycentric( const Vector2D& v0, const Vector2D& v1, const Vector2D& v2,
  292. float u, float v, Vector2D& pt );
  293. //-----------------------------------------------------------------------------
  294. // Swept OBB test
  295. //-----------------------------------------------------------------------------
  296. bool IsRayIntersectingOBB( const Ray_t &ray, const Vector& org, const QAngle& angles,
  297. const Vector& mins, const Vector& maxs );
  298. //-----------------------------------------------------------------------------
  299. // Compute a separating plane between two boxes (expensive!)
  300. // Returns false if no separating plane exists
  301. //-----------------------------------------------------------------------------
  302. bool ComputeSeparatingPlane( const Vector& org1, const QAngle& angles1, const Vector& min1, const Vector& max1,
  303. const Vector& org2, const QAngle& angles2, const Vector& min2, const Vector& max2,
  304. float tolerance, cplane_t* pPlane );
  305. //-----------------------------------------------------------------------------
  306. // IsBoxIntersectingTriangle
  307. //
  308. // Test for an intersection (overlap) between an axial-aligned bounding
  309. // box (AABB) and a triangle.
  310. //
  311. // Triangle points are in counter-clockwise order with the normal facing "out."
  312. //
  313. // Using the "Separating-Axis Theorem" to test for intersections between
  314. // a triangle and an axial-aligned bounding box (AABB).
  315. // 1. 3 Axis Plane Tests - x, y, z
  316. // 2. 9 Edge Planes Tests - the 3 edges of the triangle crossed with all 3 axial
  317. // planes (x, y, z)
  318. // 3. 1 Face Plane Test - the plane the triangle resides in (cplane_t plane)
  319. //-----------------------------------------------------------------------------
  320. bool IsBoxIntersectingTriangle( const Vector &vecBoxCenter, const Vector &vecBoxExtents,
  321. const Vector &v1, const Vector &v2, const Vector &v3,
  322. const cplane_t &plane, float flTolerance );
  323. Vector CalcClosestPointOnTriangle( const Vector &P, const Vector &v0, const Vector &v1, const Vector &v2 );
  324. //-----------------------------------------------------------------------------
  325. // Compute if the OBB intersects the quad plane, and whether the entire
  326. // OBB/Quad intersection is contained within the quad itself
  327. //
  328. // False if no intersection exists, or if part of the intersection is
  329. // outside the quad's extents
  330. //-----------------------------------------------------------------------------
  331. bool OBBHasFullyContainedIntersectionWithQuad( const Vector &vOBBExtent1_Scaled, const Vector &vOBBExtent2_Scaled, const Vector &vOBBExtent3_Scaled, const Vector &ptOBBCenter,
  332. const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter,
  333. const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length,
  334. const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length );
  335. //-----------------------------------------------------------------------------
  336. // Compute if the Ray intersects the quad plane, and whether the entire
  337. // Ray/Quad intersection is contained within the quad itself
  338. //
  339. // False if no intersection exists, or if part of the intersection is
  340. // outside the quad's extents
  341. //-----------------------------------------------------------------------------
  342. bool RayHasFullyContainedIntersectionWithQuad( const Ray_t &ray,
  343. const Vector &vQuadNormal, float fQuadPlaneDist, const Vector &ptQuadCenter,
  344. const Vector &vQuadExtent1_Normalized, float fQuadExtent1Length,
  345. const Vector &vQuadExtent2_Normalized, float fQuadExtent2Length );
  346. //-----------------------------------------------------------------------------
  347. // INLINES
  348. //-----------------------------------------------------------------------------
  349. #ifdef _X360
  350. inline bool IsBoxIntersectingBoxExtents( const fltx4 boxCenter1, const fltx4 boxHalfDiagonal1,
  351. const fltx4 boxCenter2, const fltx4 boxHalfDiagonal2 )
  352. {
  353. fltx4 vecDelta, vecSize;
  354. vecDelta = SubSIMD(boxCenter1, boxCenter2);
  355. vecSize = AddSIMD(boxHalfDiagonal1, boxHalfDiagonal2);
  356. uint condition;
  357. XMVectorInBoundsR(&condition, vecDelta, vecSize);
  358. // we want the top three words to be all 1's ; that means in bounds
  359. return XMComparisonAllInBounds( condition );
  360. }
  361. #endif
  362. #endif // COLLISIONUTILS_H