2
0

BoundingOrientedBox.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. //-----------------------------------------------------------------------------
  2. // BoundingOrientedBox.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. namespace CollisionSample
  11. {
  12. /// <summary>
  13. /// Bounding volume using an oriented bounding box.
  14. /// </summary>
  15. public struct BoundingOrientedBox : IEquatable<BoundingOrientedBox>
  16. {
  17. #region Constants
  18. public const int CornerCount = 8;
  19. // Epsilon value used in ray tests, where a ray might hit the box almost edge-on.
  20. const float RAY_EPSILON = 1e-20F;
  21. #endregion
  22. #region Fields
  23. public Vector3 Center;
  24. public Vector3 HalfExtent;
  25. public Quaternion Orientation;
  26. #endregion
  27. #region Constructors
  28. /// <summary>
  29. /// Create an oriented box with the given center, half-extents, and orientation.
  30. /// </summary>
  31. public BoundingOrientedBox(Vector3 center, Vector3 halfExtents, Quaternion orientation)
  32. {
  33. Center = center;
  34. HalfExtent = halfExtents;
  35. Orientation = orientation;
  36. }
  37. /// <summary>
  38. /// Create an oriented box from an axis-aligned box.
  39. /// </summary>
  40. public static BoundingOrientedBox CreateFromBoundingBox(BoundingBox box)
  41. {
  42. Vector3 mid = (box.Min + box.Max) * 0.5f;
  43. Vector3 halfExtent = (box.Max - box.Min) * 0.5f;
  44. return new BoundingOrientedBox(mid, halfExtent, Quaternion.Identity);
  45. }
  46. /// <summary>
  47. /// Transform the given bounding box by a rotation around the origin followed by a translation
  48. /// </summary>
  49. /// <param name="rotation"></param>
  50. /// <param name="translation"></param>
  51. /// <returns>A new bounding box, transformed relative to this one</returns>
  52. public BoundingOrientedBox Transform(Quaternion rotation, Vector3 translation)
  53. {
  54. return new BoundingOrientedBox(Vector3.Transform(Center, rotation) + translation,
  55. HalfExtent,
  56. Orientation * rotation);
  57. }
  58. /// <summary>
  59. /// Transform the given bounding box by a uniform scale and rotation around the origin followed
  60. /// by a translation
  61. /// </summary>
  62. /// <returns>A new bounding box, transformed relative to this one</returns>
  63. public BoundingOrientedBox Transform(float scale, Quaternion rotation, Vector3 translation)
  64. {
  65. return new BoundingOrientedBox(Vector3.Transform(Center * scale, rotation) + translation,
  66. HalfExtent * scale,
  67. Orientation * rotation);
  68. }
  69. #endregion
  70. #region IEquatable implementation
  71. public bool Equals(BoundingOrientedBox other)
  72. {
  73. return (Center == other.Center && HalfExtent == other.HalfExtent && Orientation == other.Orientation);
  74. }
  75. public override bool Equals(Object obj)
  76. {
  77. if (obj != null && obj is BoundingOrientedBox)
  78. {
  79. BoundingOrientedBox other = (BoundingOrientedBox)obj;
  80. return (Center == other.Center && HalfExtent == other.HalfExtent && Orientation == other.Orientation);
  81. }
  82. else
  83. {
  84. return false;
  85. }
  86. }
  87. public override int GetHashCode()
  88. {
  89. return Center.GetHashCode() ^ HalfExtent.GetHashCode() ^ Orientation.GetHashCode();
  90. }
  91. public static bool operator==(BoundingOrientedBox a, BoundingOrientedBox b)
  92. {
  93. return Equals(a, b);
  94. }
  95. public static bool operator!=(BoundingOrientedBox a, BoundingOrientedBox b)
  96. {
  97. return !Equals(a, b);
  98. }
  99. public override string ToString()
  100. {
  101. return "{Center:" + Center.ToString() +
  102. " Extents:" + HalfExtent.ToString() +
  103. " Orientation:" + Orientation.ToString() + "}";
  104. }
  105. #endregion
  106. #region Test vs. BoundingBox
  107. /// <summary>
  108. /// Determine if box A intersects box B.
  109. /// </summary>
  110. public bool Intersects(ref BoundingBox box)
  111. {
  112. Vector3 boxCenter = (box.Max + box.Min) * 0.5f;
  113. Vector3 boxHalfExtent = (box.Max - box.Min) * 0.5f;
  114. Matrix mb = Matrix.CreateFromQuaternion(Orientation);
  115. mb.Translation = Center - boxCenter;
  116. return ContainsRelativeBox(ref boxHalfExtent, ref HalfExtent, ref mb) != ContainmentType.Disjoint;
  117. }
  118. /// <summary>
  119. /// Determine if this box contains, intersects, or is disjoint from the given BoundingBox.
  120. /// </summary>
  121. public ContainmentType Contains(ref BoundingBox box)
  122. {
  123. Vector3 boxCenter = (box.Max + box.Min) * 0.5f;
  124. Vector3 boxHalfExtent = (box.Max - box.Min) * 0.5f;
  125. // Build the 3x3 rotation matrix that defines the orientation of 'other' relative to this box
  126. Quaternion relOrient;
  127. Quaternion.Conjugate(ref Orientation, out relOrient);
  128. Matrix relTransform = Matrix.CreateFromQuaternion(relOrient);
  129. relTransform.Translation = Vector3.TransformNormal(boxCenter - Center, relTransform);
  130. return ContainsRelativeBox(ref HalfExtent, ref boxHalfExtent, ref relTransform);
  131. }
  132. /// <summary>
  133. /// Determine if box A contains, intersects, or is disjoint from box B.
  134. /// </summary>
  135. public static ContainmentType Contains(ref BoundingBox boxA, ref BoundingOrientedBox oboxB)
  136. {
  137. Vector3 boxA_halfExtent = (boxA.Max - boxA.Min) * 0.5f;
  138. Vector3 boxA_center = (boxA.Max + boxA.Min) * 0.5f;
  139. Matrix mb = Matrix.CreateFromQuaternion(oboxB.Orientation);
  140. mb.Translation = oboxB.Center - boxA_center;
  141. return BoundingOrientedBox.ContainsRelativeBox(ref boxA_halfExtent, ref oboxB.HalfExtent, ref mb);
  142. }
  143. #endregion
  144. #region Test vs. BoundingOrientedBox
  145. /// <summary>
  146. /// Returns true if this box intersects the given other box.
  147. /// </summary>
  148. public bool Intersects(ref BoundingOrientedBox other)
  149. {
  150. return Contains(ref other) != ContainmentType.Disjoint;
  151. }
  152. /// <summary>
  153. /// Determine whether this box contains, intersects, or is disjoint from
  154. /// the given other box.
  155. /// </summary>
  156. public ContainmentType Contains(ref BoundingOrientedBox other)
  157. {
  158. // Build the 3x3 rotation matrix that defines the orientation of 'other' relative to this box
  159. Quaternion invOrient;
  160. Quaternion.Conjugate(ref Orientation, out invOrient);
  161. Quaternion relOrient;
  162. Quaternion.Multiply(ref invOrient, ref other.Orientation, out relOrient);
  163. Matrix relTransform = Matrix.CreateFromQuaternion(relOrient);
  164. relTransform.Translation = Vector3.Transform(other.Center - Center, invOrient);
  165. return ContainsRelativeBox(ref HalfExtent, ref other.HalfExtent, ref relTransform);
  166. }
  167. #endregion
  168. #region Test vs. BoundingFrustum
  169. /// <summary>
  170. /// Determine whether this box contains, intersects, or is disjoint from
  171. /// the given frustum.
  172. /// </summary>
  173. public ContainmentType Contains(BoundingFrustum frustum)
  174. {
  175. // Convert this bounding box to an equivalent BoundingFrustum, so we can rely on BoundingFrustum's
  176. // implementation. Note that this is very slow, since BoundingFrustum builds various data structures
  177. // for this test that it caches internally. To speed it up, you could convert the box to a frustum
  178. // just once and re-use that frustum for repeated tests.
  179. BoundingFrustum temp = ConvertToFrustum();
  180. return temp.Contains(frustum);
  181. }
  182. /// <summary>
  183. /// Returns true if this box intersects the given frustum.
  184. /// </summary>
  185. public bool Intersects(BoundingFrustum frustum)
  186. {
  187. return (Contains(frustum) != ContainmentType.Disjoint);
  188. }
  189. /// <summary>
  190. /// Determine whether the given frustum contains, intersects, or is disjoint from
  191. /// the given oriented box.
  192. /// </summary>
  193. public static ContainmentType Contains(BoundingFrustum frustum, ref BoundingOrientedBox obox)
  194. {
  195. return frustum.Contains(obox.ConvertToFrustum());
  196. }
  197. #endregion
  198. #region Test vs. BoundingSphere
  199. /// <summary>
  200. /// Test whether this box contains, intersects, or is disjoint from the given sphere
  201. /// </summary>
  202. public ContainmentType Contains(ref BoundingSphere sphere)
  203. {
  204. // Transform the sphere into local box space
  205. Quaternion iq = Quaternion.Conjugate(Orientation);
  206. Vector3 localCenter = Vector3.Transform(sphere.Center - Center, iq);
  207. // (dx,dy,dz) = signed distance of center of sphere from edge of box
  208. float dx = Math.Abs(localCenter.X) - HalfExtent.X;
  209. float dy = Math.Abs(localCenter.Y) - HalfExtent.Y;
  210. float dz = Math.Abs(localCenter.Z) - HalfExtent.Z;
  211. // Check for sphere completely inside box
  212. float r = sphere.Radius;
  213. if (dx <= -r && dy <= -r && dz <= -r)
  214. return ContainmentType.Contains;
  215. // Compute how far away the sphere is in each dimension
  216. dx = Math.Max(dx, 0.0f);
  217. dy = Math.Max(dy, 0.0f);
  218. dz = Math.Max(dz, 0.0f);
  219. if(dx*dx + dy*dy + dz*dz >= r*r)
  220. return ContainmentType.Disjoint;
  221. return ContainmentType.Intersects;
  222. }
  223. /// <summary>
  224. /// Test whether this box intersects the given sphere
  225. /// </summary>
  226. public bool Intersects(ref BoundingSphere sphere)
  227. {
  228. // Transform the sphere into local box space
  229. Quaternion iq = Quaternion.Conjugate(Orientation);
  230. Vector3 localCenter = Vector3.Transform(sphere.Center - Center, iq);
  231. // (dx,dy,dz) = signed distance of center of sphere from edge of box
  232. float dx = Math.Abs(localCenter.X) - HalfExtent.X;
  233. float dy = Math.Abs(localCenter.Y) - HalfExtent.Y;
  234. float dz = Math.Abs(localCenter.Z) - HalfExtent.Z;
  235. // Compute how far away the sphere is in each dimension
  236. dx = Math.Max(dx, 0.0f);
  237. dy = Math.Max(dy, 0.0f);
  238. dz = Math.Max(dz, 0.0f);
  239. float r = sphere.Radius;
  240. return dx * dx + dy * dy + dz * dz < r * r;
  241. }
  242. /// <summary>
  243. /// Test whether a BoundingSphere contains, intersects, or is disjoint from a BoundingOrientedBox
  244. /// </summary>
  245. public static ContainmentType Contains(ref BoundingSphere sphere, ref BoundingOrientedBox box)
  246. {
  247. // Transform the sphere into local box space
  248. Quaternion iq = Quaternion.Conjugate(box.Orientation);
  249. Vector3 localCenter = Vector3.Transform(sphere.Center - box.Center, iq);
  250. localCenter.X = Math.Abs(localCenter.X);
  251. localCenter.Y = Math.Abs(localCenter.Y);
  252. localCenter.Z = Math.Abs(localCenter.Z);
  253. // Check for box completely inside sphere
  254. float rSquared = sphere.Radius * sphere.Radius;
  255. if ((localCenter + box.HalfExtent).LengthSquared() <= rSquared)
  256. return ContainmentType.Contains;
  257. // (dx,dy,dz) = signed distance of center of sphere from edge of box
  258. Vector3 d = localCenter - box.HalfExtent;
  259. // Compute how far away the sphere is in each dimension
  260. d.X = Math.Max(d.X, 0.0f);
  261. d.Y = Math.Max(d.Y, 0.0f);
  262. d.Z = Math.Max(d.Z, 0.0f);
  263. if (d.LengthSquared() >= rSquared)
  264. return ContainmentType.Disjoint;
  265. return ContainmentType.Intersects;
  266. }
  267. #endregion
  268. #region Test vs. 0/1/2d primitives
  269. /// <summary>
  270. /// Returns true if this box contains the given point.
  271. /// </summary>
  272. public bool Contains(ref Vector3 point)
  273. {
  274. // Transform the point into box-local space and check against
  275. // our extents.
  276. Quaternion qinv = Quaternion.Conjugate(Orientation);
  277. Vector3 plocal = Vector3.Transform(point - Center, qinv);
  278. return Math.Abs(plocal.X) <= HalfExtent.X &&
  279. Math.Abs(plocal.Y) <= HalfExtent.Y &&
  280. Math.Abs(plocal.Z) <= HalfExtent.Z;
  281. }
  282. /// <summary>
  283. /// Determine whether the given ray intersects this box. If so, returns
  284. /// the parametric value of the point of first intersection; otherwise
  285. /// returns null.
  286. /// </summary>
  287. public float? Intersects(ref Ray ray)
  288. {
  289. Matrix R = Matrix.CreateFromQuaternion(Orientation);
  290. Vector3 TOrigin = Center - ray.Position;
  291. float t_min = -float.MaxValue;
  292. float t_max = float.MaxValue;
  293. // X-case
  294. float axisDotOrigin = Vector3.Dot(R.Right, TOrigin);
  295. float axisDotDir = Vector3.Dot(R.Right, ray.Direction);
  296. if (axisDotDir >= -RAY_EPSILON && axisDotDir <= RAY_EPSILON)
  297. {
  298. if ((-axisDotOrigin - HalfExtent.X) > 0.0 || (-axisDotOrigin + HalfExtent.X) > 0.0f)
  299. return null;
  300. }
  301. else
  302. {
  303. float t1 = (axisDotOrigin - HalfExtent.X) / axisDotDir;
  304. float t2 = (axisDotOrigin + HalfExtent.X) / axisDotDir;
  305. if (t1 > t2)
  306. {
  307. float temp = t1;
  308. t1 = t2;
  309. t2 = temp;
  310. }
  311. if (t1 > t_min)
  312. t_min = t1;
  313. if (t2 < t_max)
  314. t_max = t2;
  315. if (t_max < 0.0f || t_min > t_max)
  316. return null;
  317. }
  318. // Y-case
  319. axisDotOrigin = Vector3.Dot(R.Up, TOrigin);
  320. axisDotDir = Vector3.Dot(R.Up, ray.Direction);
  321. if (axisDotDir >= -RAY_EPSILON && axisDotDir <= RAY_EPSILON)
  322. {
  323. if ((-axisDotOrigin - HalfExtent.Y) > 0.0 || (-axisDotOrigin + HalfExtent.Y) > 0.0f)
  324. return null;
  325. }
  326. else
  327. {
  328. float t1 = (axisDotOrigin - HalfExtent.Y) / axisDotDir;
  329. float t2 = (axisDotOrigin + HalfExtent.Y) / axisDotDir;
  330. if (t1 > t2)
  331. {
  332. float temp = t1;
  333. t1 = t2;
  334. t2 = temp;
  335. }
  336. if (t1 > t_min)
  337. t_min = t1;
  338. if (t2 < t_max)
  339. t_max = t2;
  340. if (t_max < 0.0f || t_min > t_max)
  341. return null;
  342. }
  343. // Z-case
  344. axisDotOrigin = Vector3.Dot(R.Forward, TOrigin);
  345. axisDotDir = Vector3.Dot(R.Forward, ray.Direction);
  346. if (axisDotDir >= -RAY_EPSILON && axisDotDir <= RAY_EPSILON)
  347. {
  348. if ((-axisDotOrigin - HalfExtent.Z) > 0.0 || (-axisDotOrigin + HalfExtent.Z) > 0.0f)
  349. return null;
  350. }
  351. else
  352. {
  353. float t1 = (axisDotOrigin - HalfExtent.Z) / axisDotDir;
  354. float t2 = (axisDotOrigin + HalfExtent.Z) / axisDotDir;
  355. if (t1 > t2)
  356. {
  357. float temp = t1;
  358. t1 = t2;
  359. t2 = temp;
  360. }
  361. if (t1 > t_min)
  362. t_min = t1;
  363. if (t2 < t_max)
  364. t_max = t2;
  365. if (t_max < 0.0f || t_min > t_max)
  366. return null;
  367. }
  368. return t_min;
  369. }
  370. /// <summary>
  371. /// Classify this bounding box as entirely in front of, in back of, or
  372. /// intersecting the given plane.
  373. /// </summary>
  374. public PlaneIntersectionType Intersects(ref Plane plane)
  375. {
  376. float dist = plane.DotCoordinate(Center);
  377. // Transform the plane's normal into this box's space
  378. Vector3 localNormal = Vector3.Transform(plane.Normal, Quaternion.Conjugate(Orientation));
  379. // Project the axes of the box onto the normal of the plane. Half the
  380. // length of the projection (sometime called the "radius") is equal to
  381. // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w))
  382. // where h(i) are extents of the box, n is the plane normal, and b(i) are the
  383. // axes of the box.
  384. float r = Math.Abs(HalfExtent.X*localNormal.X)
  385. + Math.Abs(HalfExtent.Y*localNormal.Y)
  386. + Math.Abs(HalfExtent.Z*localNormal.Z);
  387. if(dist > r)
  388. {
  389. return PlaneIntersectionType.Front;
  390. }
  391. else if(dist < -r)
  392. {
  393. return PlaneIntersectionType.Back;
  394. }
  395. else
  396. {
  397. return PlaneIntersectionType.Intersecting;
  398. }
  399. }
  400. #endregion
  401. #region Helper methods
  402. /// <summary>
  403. /// Return the 8 corner positions of this bounding box.
  404. ///
  405. /// ZMax ZMin
  406. /// 0----1 4----5
  407. /// | | | |
  408. /// | | | |
  409. /// 3----2 7----6
  410. ///
  411. /// The ordering of indices is a little strange to match what BoundingBox.GetCorners() does.
  412. /// </summary>
  413. public Vector3[] GetCorners()
  414. {
  415. Vector3[] corners = new Vector3[CornerCount];
  416. GetCorners(corners, 0);
  417. return corners;
  418. }
  419. /// <summary>
  420. /// Return the 8 corner positions of this bounding box.
  421. ///
  422. /// ZMax ZMin
  423. /// 0----1 4----5
  424. /// | | | |
  425. /// | | | |
  426. /// 3----2 7----6
  427. ///
  428. /// The ordering of indices is a little strange to match what BoundingBox.GetCorners() does.
  429. /// </summary>
  430. /// <param name="corners">Array to fill with the eight corner positions</param>
  431. /// <param name="startIndex">Index within corners array to start writing positions</param>
  432. public void GetCorners(Vector3[] corners, int startIndex)
  433. {
  434. Matrix m = Matrix.CreateFromQuaternion(Orientation);
  435. Vector3 hX = m.Left * HalfExtent.X;
  436. Vector3 hY = m.Up * HalfExtent.Y;
  437. Vector3 hZ = m.Backward * HalfExtent.Z;
  438. int i = startIndex;
  439. corners[i++] = Center - hX + hY + hZ;
  440. corners[i++] = Center + hX + hY + hZ;
  441. corners[i++] = Center + hX - hY + hZ;
  442. corners[i++] = Center - hX - hY + hZ;
  443. corners[i++] = Center - hX + hY - hZ;
  444. corners[i++] = Center + hX + hY - hZ;
  445. corners[i++] = Center + hX - hY - hZ;
  446. corners[i++] = Center - hX - hY - hZ;
  447. }
  448. /// <summary>
  449. /// Determine whether the box described by half-extents hA, axis-aligned and centered at the origin, contains
  450. /// the box described by half-extents hB, whose position and orientation are given by the transform matrix mB.
  451. /// The matrix is assumed to contain only rigid motion; if it contains scaling or perpsective the result of
  452. /// this method will be incorrect.
  453. /// </summary>
  454. /// <param name="hA">Half-extents of first box</param>
  455. /// <param name="hB">Half-extents of second box</param>
  456. /// <param name="mB">Position and orientation of second box relative to first box</param>
  457. /// <returns>ContainmentType enum indicating whether the boxes are disjoin, intersecting, or
  458. /// whether box A contains box B.</returns>
  459. public static ContainmentType ContainsRelativeBox(ref Vector3 hA, ref Vector3 hB, ref Matrix mB)
  460. {
  461. Vector3 mB_T = mB.Translation;
  462. Vector3 mB_TA = new Vector3(Math.Abs(mB_T.X), Math.Abs(mB_T.Y), Math.Abs(mB_T.Z));
  463. // Transform the extents of B
  464. // TODO: check which coords Right/Up/Back refer to and access them directly. This looks dumb.
  465. Vector3 bX = mB.Right; // x-axis of box B
  466. Vector3 bY = mB.Up; // y-axis of box B
  467. Vector3 bZ = mB.Backward; // z-axis of box B
  468. Vector3 hx_B = bX * hB.X; // x extent of box B
  469. Vector3 hy_B = bY * hB.Y; // y extent of box B
  470. Vector3 hz_B = bZ * hB.Z; // z extent of box B
  471. // Check for containment first.
  472. float projx_B = Math.Abs(hx_B.X) + Math.Abs(hy_B.X) + Math.Abs(hz_B.X);
  473. float projy_B = Math.Abs(hx_B.Y) + Math.Abs(hy_B.Y) + Math.Abs(hz_B.Y);
  474. float projz_B = Math.Abs(hx_B.Z) + Math.Abs(hy_B.Z) + Math.Abs(hz_B.Z);
  475. if (mB_TA.X + projx_B <= hA.X && mB_TA.Y + projy_B <= hA.Y && mB_TA.Z + projz_B <= hA.Z)
  476. return ContainmentType.Contains;
  477. // Check for separation along the faces of the other box,
  478. // by projecting each local axis onto the other boxes' axes
  479. // http://www.cs.unc.edu/~geom/theses/gottschalk/main.pdf
  480. //
  481. // The general test form, given a choice of separating axis, is:
  482. // sizeA = abs(dot(A.e1,axis)) + abs(dot(A.e2,axis)) + abs(dot(A.e3,axis))
  483. // sizeB = abs(dot(B.e1,axis)) + abs(dot(B.e2,axis)) + abs(dot(B.e3,axis))
  484. // distance = abs(dot(B.center - A.center),axis))
  485. // if distance >= sizeA+sizeB, the boxes are disjoint
  486. //
  487. // We need to do this test on 15 axes:
  488. // x, y, z axis of box A
  489. // x, y, z axis of box B
  490. // (v1 cross v2) for each v1 in A's axes, for each v2 in B's axes
  491. //
  492. // Since we're working in a space where A is axis-aligned and A.center=0, many
  493. // of the tests and products simplify away.
  494. // Check for separation along the axes of box A
  495. if (mB_TA.X >= hA.X + Math.Abs(hx_B.X) + Math.Abs(hy_B.X) + Math.Abs(hz_B.X))
  496. return ContainmentType.Disjoint;
  497. if (mB_TA.Y >= hA.Y + Math.Abs(hx_B.Y) + Math.Abs(hy_B.Y) + Math.Abs(hz_B.Y))
  498. return ContainmentType.Disjoint;
  499. if (mB_TA.Z >= hA.Z + Math.Abs(hx_B.Z) + Math.Abs(hy_B.Z) + Math.Abs(hz_B.Z))
  500. return ContainmentType.Disjoint;
  501. // Check for separation along the axes box B, hx_B/hy_B/hz_B
  502. if (Math.Abs(Vector3.Dot(mB_T, bX)) >= Math.Abs(hA.X * bX.X) + Math.Abs(hA.Y * bX.Y) + Math.Abs(hA.Z * bX.Z) + hB.X)
  503. return ContainmentType.Disjoint;
  504. if (Math.Abs(Vector3.Dot(mB_T, bY)) >= Math.Abs(hA.X * bY.X) + Math.Abs(hA.Y * bY.Y) + Math.Abs(hA.Z * bY.Z) + hB.Y)
  505. return ContainmentType.Disjoint;
  506. if (Math.Abs(Vector3.Dot(mB_T, bZ)) >= Math.Abs(hA.X * bZ.X) + Math.Abs(hA.Y * bZ.Y) + Math.Abs(hA.Z * bZ.Z) + hB.Z)
  507. return ContainmentType.Disjoint;
  508. // Check for separation in plane containing an axis of box A and and axis of box B
  509. //
  510. // We need to compute all 9 cross products to find them, but a lot of terms drop out
  511. // since we're working in A's local space. Also, since each such plane is parallel
  512. // to the defining axis in each box, we know those dot products will be 0 and can
  513. // omit them.
  514. Vector3 axis;
  515. // a.X ^ b.X = (1,0,0) ^ bX
  516. axis = new Vector3(0, -bX.Z, bX.Y);
  517. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Y * axis.Y) + Math.Abs(hA.Z * axis.Z) + Math.Abs(Vector3.Dot(axis, hy_B)) + Math.Abs(Vector3.Dot(axis, hz_B)))
  518. return ContainmentType.Disjoint;
  519. // a.X ^ b.Y = (1,0,0) ^ bY
  520. axis = new Vector3(0, -bY.Z, bY.Y);
  521. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Y * axis.Y) + Math.Abs(hA.Z * axis.Z) + Math.Abs(Vector3.Dot(axis, hz_B)) + Math.Abs(Vector3.Dot(axis, hx_B)))
  522. return ContainmentType.Disjoint;
  523. // a.X ^ b.Z = (1,0,0) ^ bZ
  524. axis = new Vector3(0, -bZ.Z, bZ.Y);
  525. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Y * axis.Y) + Math.Abs(hA.Z * axis.Z) + Math.Abs(Vector3.Dot(axis, hx_B)) + Math.Abs(Vector3.Dot(axis, hy_B)))
  526. return ContainmentType.Disjoint;
  527. // a.Y ^ b.X = (0,1,0) ^ bX
  528. axis = new Vector3(bX.Z, 0, -bX.X);
  529. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Z * axis.Z) + Math.Abs(hA.X * axis.X) + Math.Abs(Vector3.Dot(axis, hy_B)) + Math.Abs(Vector3.Dot(axis, hz_B)))
  530. return ContainmentType.Disjoint;
  531. // a.Y ^ b.Y = (0,1,0) ^ bY
  532. axis = new Vector3(bY.Z, 0, -bY.X);
  533. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Z * axis.Z) + Math.Abs(hA.X * axis.X) + Math.Abs(Vector3.Dot(axis, hz_B)) + Math.Abs(Vector3.Dot(axis, hx_B)))
  534. return ContainmentType.Disjoint;
  535. // a.Y ^ b.Z = (0,1,0) ^ bZ
  536. axis = new Vector3(bZ.Z, 0, -bZ.X);
  537. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.Z * axis.Z) + Math.Abs(hA.X * axis.X) + Math.Abs(Vector3.Dot(axis, hx_B)) + Math.Abs(Vector3.Dot(axis, hy_B)))
  538. return ContainmentType.Disjoint;
  539. // a.Z ^ b.X = (0,0,1) ^ bX
  540. axis = new Vector3(-bX.Y, bX.X, 0);
  541. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.X * axis.X) + Math.Abs(hA.Y * axis.Y) + Math.Abs(Vector3.Dot(axis, hy_B)) + Math.Abs(Vector3.Dot(axis, hz_B)))
  542. return ContainmentType.Disjoint;
  543. // a.Z ^ b.Y = (0,0,1) ^ bY
  544. axis = new Vector3(-bY.Y, bY.X, 0);
  545. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.X * axis.X) + Math.Abs(hA.Y * axis.Y) + Math.Abs(Vector3.Dot(axis, hz_B)) + Math.Abs(Vector3.Dot(axis, hx_B)))
  546. return ContainmentType.Disjoint;
  547. // a.Z ^ b.Z = (0,0,1) ^ bZ
  548. axis = new Vector3(-bZ.Y, bZ.X, 0);
  549. if (Math.Abs(Vector3.Dot(mB_T, axis)) >= Math.Abs(hA.X * axis.X) + Math.Abs(hA.Y * axis.Y) + Math.Abs(Vector3.Dot(axis, hx_B)) + Math.Abs(Vector3.Dot(axis, hy_B)))
  550. return ContainmentType.Disjoint;
  551. return ContainmentType.Intersects;
  552. }
  553. /// <summary>
  554. /// Convert this BoundingOrientedBox to a BoundingFrustum describing the same volume.
  555. ///
  556. /// A BoundingFrustum is defined by the matrix that carries its volume to the
  557. /// box from (-1,-1,0) to (1,1,1), so we just need a matrix that carries our box there.
  558. /// </summary>
  559. public BoundingFrustum ConvertToFrustum()
  560. {
  561. Quaternion invOrientation;
  562. Quaternion.Conjugate(ref Orientation, out invOrientation);
  563. float sx = 1.0f / HalfExtent.X;
  564. float sy = 1.0f / HalfExtent.Y;
  565. float sz = .5f / HalfExtent.Z;
  566. Matrix temp;
  567. Matrix.CreateFromQuaternion(ref invOrientation, out temp);
  568. temp.M11 *= sx; temp.M21 *= sx; temp.M31 *= sx;
  569. temp.M12 *= sy; temp.M22 *= sy; temp.M32 *= sy;
  570. temp.M13 *= sz; temp.M23 *= sz; temp.M33 *= sz;
  571. temp.Translation = Vector3.UnitZ*0.5f + Vector3.TransformNormal(-Center, temp);
  572. return new BoundingFrustum(temp);
  573. }
  574. #endregion
  575. }
  576. }