BoundingOrientedBox.cs 27 KB

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