2
0

CollisionContext.cs 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // CollisionContext.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Text;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Content;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using RobotGameData.GameObject;
  17. using RobotGameData.Helper;
  18. using RobotGameData.GameInterface;
  19. #endregion
  20. namespace RobotGameData.Collision
  21. {
  22. #region CollisionResult
  23. public enum ResultType
  24. {
  25. /// <summary>
  26. /// To find the nearest collision from itself.
  27. /// </summary>
  28. NearestOne = 0,
  29. }
  30. /// <summary>
  31. /// result report of collision
  32. /// </summary>
  33. public class CollisionResult
  34. {
  35. /// <summary>
  36. /// Distance between detected collision
  37. /// </summary>
  38. public float distance = 0.0f;
  39. /// <summary>
  40. /// Detection object count
  41. /// </summary>
  42. public int collideCount = 0;
  43. /// <summary>
  44. /// Detected object element
  45. /// </summary>
  46. public CollideElement detectedCollide = null;
  47. /// <summary>
  48. /// intersect point
  49. /// </summary>
  50. public Vector3? intersect = null;
  51. /// <summary>
  52. /// intersect normal
  53. /// </summary>
  54. public Vector3? normal = null;
  55. public void CopyTo(ref CollisionResult target)
  56. {
  57. target.distance = this.distance;
  58. target.collideCount = this.collideCount;
  59. target.detectedCollide = this.detectedCollide;
  60. target.intersect = this.intersect;
  61. target.normal = this.normal;
  62. }
  63. public void Clear()
  64. {
  65. this.distance = 0.0f;
  66. this.collideCount = 0;
  67. this.detectedCollide = null;
  68. this.intersect = null;
  69. this.normal = null;
  70. }
  71. }
  72. #endregion
  73. #region CollisionLayer
  74. /// <summary>
  75. /// This layer groups collision elements that need to be processed
  76. /// for the collision collectively.
  77. /// </summary>
  78. public class CollisionLayer : INamed, IIdentity
  79. {
  80. #region Field
  81. string name = String.Empty;
  82. int id = -1;
  83. List<CollideElement> collideContainer = new List<CollideElement>();
  84. #endregion
  85. #region Properties
  86. public string Name
  87. {
  88. get { return name; }
  89. set { name = value; }
  90. }
  91. public int Id
  92. {
  93. get { return id; }
  94. set { id = value; }
  95. }
  96. public int CollideCount
  97. {
  98. get { return collideContainer.Count; }
  99. }
  100. #endregion
  101. /// <summary>
  102. /// Add a collsion element.
  103. /// </summary>
  104. public void AddCollide(CollideElement collide)
  105. {
  106. if (collideContainer.Contains(collide))
  107. throw new InvalidOperationException("Already entry the collide");
  108. collideContainer.Add(collide);
  109. collide.ParentLayer = this;
  110. }
  111. /// <summary>
  112. /// Get collision element using the index.
  113. /// </summary>
  114. public CollideElement GetCollide(int index)
  115. {
  116. return collideContainer[index];
  117. }
  118. /// <summary>
  119. /// Find a collision element using the name.
  120. /// </summary>
  121. public CollideElement FindCollide(string name)
  122. {
  123. // Finding collision by name
  124. for (int i = 0; i < collideContainer.Count; i++)
  125. {
  126. CollideElement collide = collideContainer[i];
  127. if (collide.Name == name)
  128. return collide;
  129. }
  130. return null;
  131. }
  132. /// <summary>
  133. /// it checks whether the collision element which has been included.
  134. /// </summary>
  135. public bool IsContain(CollideElement collide)
  136. {
  137. return (collideContainer.IndexOf(collide) == -1 ? false : true);
  138. }
  139. /// <summary>
  140. /// Remove the collision element.
  141. /// </summary>
  142. public bool RemoveCollide(CollideElement collide)
  143. {
  144. return collideContainer.Remove(collide);
  145. }
  146. /// <summary>
  147. /// Remove a collision element using the index.
  148. /// </summary>
  149. public void RemoveCollide(int index)
  150. {
  151. collideContainer.RemoveAt(index);
  152. }
  153. /// <summary>
  154. /// Remove all collision elements.
  155. /// </summary>
  156. public void RemoveAll()
  157. {
  158. collideContainer.Clear();
  159. }
  160. /// <summary>
  161. /// Make an Identity number.
  162. /// </summary>
  163. public int MakeId()
  164. {
  165. this.id = GetHashCode();
  166. return this.id;
  167. }
  168. }
  169. #endregion
  170. /// <summary>
  171. /// It tests for collision again the registered collision elements.
  172. /// When you request CollisionContext a collision test with the source
  173. /// CollideElement, a result from a collision test would be returned with
  174. /// all CollideElements that have been registered to the specific collision
  175. /// layer as the target.
  176. /// It supports the following collision types: ray, model, box, and sphere.
  177. /// </summary>
  178. public class CollisionContext
  179. {
  180. #region Fields
  181. /// <summary>
  182. /// If set to false, all of the related functions get turned off.
  183. /// </summary>
  184. bool activeOn = true;
  185. List<CollisionLayer> collideLayerContainer
  186. = new List<CollisionLayer>();
  187. CollisionResult tempResult = new CollisionResult();
  188. int totalCollidingCount = 0;
  189. #endregion
  190. #region Properties
  191. public int LayerCount
  192. {
  193. get { return collideLayerContainer.Count; }
  194. }
  195. public int TotalCollidingCount
  196. {
  197. get { return totalCollidingCount; }
  198. }
  199. #endregion
  200. /// <summary>
  201. /// Creates a new collision layer using the name.
  202. /// </summary>
  203. /// <param name="name">The layer name</param>
  204. public CollisionLayer AddLayer(string name)
  205. {
  206. CollisionLayer newLayer = new CollisionLayer();
  207. newLayer.Name = name;
  208. newLayer.MakeId();
  209. collideLayerContainer.Add(newLayer);
  210. return newLayer;
  211. }
  212. /// <summary>
  213. /// Get a collison layer using the ID number.
  214. /// </summary>
  215. /// <param name="id">ID number</param>
  216. public CollisionLayer GetLayer(int id)
  217. {
  218. for (int i = 0; i < collideLayerContainer.Count; i++)
  219. {
  220. if( id == collideLayerContainer[i].Id)
  221. return collideLayerContainer[i];
  222. }
  223. return null;
  224. }
  225. /// <summary>
  226. /// Get a collison layer using the name.
  227. /// </summary>
  228. /// <param name="layerName">The layer name</param>
  229. public CollisionLayer GetLayer(string layerName)
  230. {
  231. for (int i = 0; i < collideLayerContainer.Count; i++)
  232. {
  233. if (layerName == collideLayerContainer[i].Name)
  234. return collideLayerContainer[i];
  235. }
  236. return null;
  237. }
  238. /// <summary>
  239. /// Remove all collsion layers.
  240. /// </summary>
  241. public void ClearAllLayer()
  242. {
  243. collideLayerContainer.Clear();
  244. }
  245. /// <summary>
  246. /// It tests for collision among the collision elements which
  247. /// have been registered to the collision layer and returns the result.
  248. /// </summary>
  249. /// <param name="collide">Source collsion element</param>
  250. /// <param name="idLayer">Destination collison layer ID number</param>
  251. /// <param name="resultType">type of result</param>
  252. /// <returns>A result report</returns>
  253. public CollisionResult HitTest(CollideElement collide, int idLayer,
  254. ResultType resultType)
  255. {
  256. // Get the collide layer
  257. CollisionLayer layer = GetLayer(idLayer);
  258. return HitTest(collide, ref layer, resultType);
  259. }
  260. /// <summary>
  261. /// It tests for collision among the collision elements which
  262. /// have been registered to the collision layer and returns the result.
  263. /// </summary>
  264. /// <param name="collide">Source collsion element</param>
  265. /// <param name="targetLayer">Target collison layer</param>
  266. /// <param name="resultType">type of result</param>
  267. /// <returns>A result report</returns>
  268. public CollisionResult HitTest(CollideElement collide,
  269. ref CollisionLayer targetLayer,
  270. ResultType resultType)
  271. {
  272. CollisionResult result = null;
  273. tempResult.Clear();
  274. totalCollidingCount = 0;
  275. if (activeOn == false)
  276. return null;
  277. if (collide == null)
  278. {
  279. throw new ArgumentNullException("collide");
  280. }
  281. if (targetLayer == null)
  282. {
  283. throw new ArgumentNullException("targetLayer");
  284. }
  285. // checking all collisions in current collision layer
  286. for (int i = 0; i < targetLayer.CollideCount; i++)
  287. {
  288. CollideElement targetCollide = targetLayer.GetCollide(i);
  289. // Skip ifself
  290. if (collide.Equals(targetCollide))
  291. {
  292. continue;
  293. }
  294. else if (collide.Id != 0 && targetCollide.Id != 0)
  295. {
  296. if (collide.Id == targetCollide.Id)
  297. continue;
  298. }
  299. // If source collision is BoundingSphere
  300. if (collide is CollideSphere)
  301. {
  302. CollideSphere sourceCollideSphere = collide as CollideSphere;
  303. // Test with target sphere
  304. if (targetCollide is CollideSphere)
  305. {
  306. CollideSphere targetCollideSphere =
  307. targetCollide as CollideSphere;
  308. TestSphereintersectSphere(sourceCollideSphere,
  309. targetCollideSphere, ref tempResult);
  310. }
  311. // Test with target model
  312. else if (targetCollide is CollideModel)
  313. {
  314. CollideModel targetCollideModel =
  315. targetCollide as CollideModel;
  316. TestSphereintersectModel(sourceCollideSphere,
  317. targetCollideModel, ref tempResult);
  318. }
  319. // Test with target box
  320. else if (targetCollide is CollideBox)
  321. {
  322. CollideBox targetCollideBox = targetCollide as CollideBox;
  323. TestSphereintersectBox(sourceCollideSphere,
  324. targetCollideBox, ref tempResult);
  325. }
  326. // Test with target ray
  327. if (targetCollide is CollideRay)
  328. {
  329. CollideRay targetCollideRay =
  330. targetCollide as CollideRay;
  331. TestRayintersectSphere(targetCollideRay,
  332. sourceCollideSphere, ref tempResult);
  333. }
  334. }
  335. // If source collision is Ray
  336. else if (collide is CollideRay)
  337. {
  338. CollideRay sourceCollideRay = collide as CollideRay;
  339. // Test with target model
  340. if (targetCollide is CollideModel)
  341. {
  342. CollideModel targetCollideModel =
  343. targetCollide as CollideModel;
  344. TestRayintersectModel(sourceCollideRay,
  345. targetCollideModel, ref tempResult);
  346. }
  347. // Test with target sphere
  348. else if (targetCollide is CollideSphere)
  349. {
  350. CollideSphere targetCollideSphere =
  351. targetCollide as CollideSphere;
  352. TestRayintersectSphere(sourceCollideRay,
  353. targetCollideSphere, ref tempResult);
  354. }
  355. // Test with target box
  356. else if (targetCollide is CollideBox)
  357. {
  358. CollideBox targetCollideBox = targetCollide as CollideBox;
  359. TestRayintersectBox(sourceCollideRay,
  360. targetCollideBox, ref tempResult);
  361. }
  362. }
  363. // If source collision is Ray
  364. else if (collide is CollideBox)
  365. {
  366. CollideBox sourceCollideBox = collide as CollideBox;
  367. // Test with target sphere
  368. if (targetCollide is CollideSphere)
  369. {
  370. CollideSphere targetCollideSphere =
  371. targetCollide as CollideSphere;
  372. TestSphereintersectBox(targetCollideSphere,
  373. sourceCollideBox, ref tempResult);
  374. }
  375. // Test with target box
  376. else if (targetCollide is CollideBox)
  377. {
  378. CollideBox targetCollideBox = targetCollide as CollideBox;
  379. TestBoxintersectBox(sourceCollideBox,
  380. targetCollideBox, ref tempResult);
  381. }
  382. // Test with target ray
  383. else if (targetCollide is CollideRay)
  384. {
  385. CollideRay targetCollideRay = targetCollide as CollideRay;
  386. TestRayintersectBox(targetCollideRay,
  387. sourceCollideBox, ref tempResult);
  388. }
  389. }
  390. // To find the nearest detected collision.
  391. if (resultType == ResultType.NearestOne)
  392. {
  393. if (tempResult.collideCount > 0)
  394. {
  395. if(result == null)
  396. {
  397. result = new CollisionResult();
  398. result.distance = float.MaxValue;
  399. }
  400. if (result.distance > tempResult.distance)
  401. {
  402. tempResult.CopyTo(ref result);
  403. }
  404. }
  405. }
  406. }
  407. return result;
  408. }
  409. /// <summary>
  410. /// It checks for the collision between two collision spheres.
  411. /// </summary>
  412. /// <param name="sourceCollide">Source collision sphere</param>
  413. /// <param name="targetCollide">Target collision sphere</param>
  414. /// <param name="result">A result report</param>
  415. /// <returns>True if there is a collision</returns>
  416. public bool TestSphereintersectSphere(CollideSphere sourceCollide,
  417. CollideSphere targetCollide, ref CollisionResult result)
  418. {
  419. totalCollidingCount++;
  420. // Test sphere with the other sphere
  421. if (sourceCollide.BoundingSphere.Intersects(targetCollide.BoundingSphere))
  422. {
  423. if (result != null)
  424. {
  425. float twoSphereDistance = Vector3.Distance(
  426. targetCollide.BoundingSphere.Center,
  427. sourceCollide.BoundingSphere.Center);
  428. Vector3 twoSphereDirection = Vector3.Normalize(
  429. targetCollide.BoundingSphere.Center -
  430. sourceCollide.BoundingSphere.Center);
  431. result.distance = Math.Abs(twoSphereDistance) -
  432. (sourceCollide.Radius + targetCollide.Radius);
  433. result.detectedCollide = targetCollide;
  434. result.intersect = twoSphereDirection * result.distance;
  435. result.collideCount++;
  436. }
  437. return true;
  438. }
  439. return false;
  440. }
  441. /// <summary>
  442. /// It checks for the collision between a collision sphere and a collision model.
  443. /// </summary>
  444. /// <param name="sourceCollide">Source collision sphere</param>
  445. /// <param name="targetCollide">Target collision model</param>
  446. /// <param name="result">A result report</param>
  447. /// <returns>True if there is a collision</returns>
  448. public bool TestSphereintersectModel(CollideSphere sourceCollide,
  449. CollideModel targetCollide, ref CollisionResult result)
  450. {
  451. Vector3 intersect;
  452. Vector3 normal;
  453. float distance;
  454. BoundingSphere sphere = sourceCollide.BoundingSphere;
  455. // use quad tree.
  456. if (targetCollide.QuadTree != null)
  457. {
  458. if( TestUsingQuadTree((CollideElement)sourceCollide,
  459. targetCollide.QuadTree.RootNode,
  460. out intersect,
  461. out normal,
  462. out distance))
  463. {
  464. result.detectedCollide = targetCollide;
  465. result.intersect = intersect;
  466. result.normal = normal;
  467. result.distance = distance;
  468. result.collideCount++;
  469. return true;
  470. }
  471. }
  472. // Hit test sphere with the model
  473. else
  474. {
  475. if( TestSphereintersectModel(sphere, targetCollide.Vertices,
  476. targetCollide.TransformMatrix,
  477. out intersect, out normal,
  478. out distance))
  479. {
  480. result.detectedCollide = targetCollide;
  481. result.intersect = intersect;
  482. result.normal = normal;
  483. result.distance = distance;
  484. result.collideCount++;
  485. return true;
  486. }
  487. }
  488. return false;
  489. }
  490. /// <summary>
  491. /// It checks for the collision between a collision ray and a collision model.
  492. /// </summary>
  493. /// <param name="sourceCollide">Source collision ray</param>
  494. /// <param name="targetCollide">Target collision model</param>
  495. /// <param name="result">A result report</param>
  496. /// <returns>True if there is a collision</returns>
  497. public bool TestRayintersectModel(CollideRay sourceCollide,
  498. CollideModel targetCollide,
  499. ref CollisionResult result)
  500. {
  501. Vector3 intersect;
  502. Vector3 normal;
  503. float distance;
  504. // use quad tree.
  505. if (targetCollide.QuadTree != null)
  506. {
  507. if( TestUsingQuadTree((CollideElement)sourceCollide,
  508. targetCollide.QuadTree.RootNode,
  509. out intersect,
  510. out normal,
  511. out distance))
  512. {
  513. result.detectedCollide = targetCollide;
  514. result.intersect = intersect;
  515. result.normal = normal;
  516. result.distance = distance;
  517. result.collideCount++;
  518. return true;
  519. }
  520. }
  521. // Test ray with the model
  522. else
  523. {
  524. if( TestRayintersectModel(sourceCollide.Ray, targetCollide.Vertices,
  525. targetCollide.TransformMatrix,
  526. out intersect,
  527. out normal,
  528. out distance))
  529. {
  530. result.distance = distance;
  531. result.detectedCollide = targetCollide;
  532. result.intersect = intersect;
  533. result.normal = normal;
  534. result.collideCount++;
  535. }
  536. }
  537. return false;
  538. }
  539. /// <summary>
  540. /// It checks for the collision between a collision ray and a collision box.
  541. /// </summary>
  542. /// <param name="sourceCollide">Source collision ray</param>
  543. /// <param name="targetCollide">Target collision box</param>
  544. /// <param name="result">A result report</param>
  545. /// <returns>True if there is a collision</returns>
  546. public bool TestRayintersectBox(CollideRay sourceCollide,
  547. CollideBox targetCollide,
  548. ref CollisionResult result)
  549. {
  550. totalCollidingCount++;
  551. // Test ray with the box
  552. float? distance = sourceCollide.Ray.Intersects(targetCollide.BoundingBox);
  553. if (distance != null)
  554. {
  555. if (result != null)
  556. {
  557. result.distance = (float)distance;
  558. result.detectedCollide = targetCollide;
  559. result.intersect = null;
  560. result.normal = null;
  561. result.collideCount++;
  562. }
  563. return true;
  564. }
  565. return false;
  566. }
  567. /// <summary>
  568. /// It checks for the collision between a collision sphere and a collision box.
  569. /// </summary>
  570. /// <param name="sourceCollide">Source collision ray</param>
  571. /// <param name="targetCollide">Target collision box</param>
  572. /// <param name="result">A result report</param>
  573. /// <returns>True if there is a collision</returns>
  574. public bool TestSphereintersectBox(CollideSphere sourceCollide,
  575. CollideBox targetCollide,
  576. ref CollisionResult result)
  577. {
  578. totalCollidingCount++;
  579. // Test sphere with the box
  580. if (sourceCollide.BoundingSphere.Intersects(targetCollide.BoundingBox))
  581. {
  582. if (result != null)
  583. {
  584. Vector3 centerBox = 0.5f *
  585. (targetCollide.BoundingBox.Max + targetCollide.BoundingBox.Min);
  586. result.distance = (float)Vector3.Distance(
  587. sourceCollide.BoundingSphere.Center, centerBox)
  588. - sourceCollide.BoundingSphere.Radius;
  589. result.detectedCollide = targetCollide;
  590. result.intersect = null;
  591. result.normal = null;
  592. result.collideCount++;
  593. }
  594. return true;
  595. }
  596. return false;
  597. }
  598. /// <summary>
  599. /// It checks for two collision boxes.
  600. /// </summary>
  601. /// <param name="sourceCollide">Source collision box</param>
  602. /// <param name="targetCollide">Target collision box</param>
  603. /// <param name="result">A result report</param>
  604. /// <returns>True if there is a collision</returns>
  605. public bool TestBoxintersectBox(CollideBox sourceCollide,
  606. CollideBox targetCollide,
  607. ref CollisionResult result)
  608. {
  609. totalCollidingCount++;
  610. // // Test two boxes
  611. if (sourceCollide.BoundingBox.Intersects(targetCollide.BoundingBox))
  612. {
  613. if (result != null)
  614. {
  615. Vector3 centerSourceBox = 0.5f *
  616. (sourceCollide.BoundingBox.Max + sourceCollide.BoundingBox.Min);
  617. Vector3 centerTargetBox = 0.5f *
  618. (targetCollide.BoundingBox.Max + targetCollide.BoundingBox.Min);
  619. result.distance =
  620. (float)Vector3.Distance(centerSourceBox, centerTargetBox);
  621. result.detectedCollide = targetCollide;
  622. result.intersect = null;
  623. result.normal = null;
  624. result.collideCount++;
  625. }
  626. return true;
  627. }
  628. return false;
  629. }
  630. /// <summary>
  631. /// It checks for the collision between a collision ray and a collision sphere.
  632. /// </summary>
  633. /// <param name="sourceCollide">Source collision ray</param>
  634. /// <param name="targetCollide">Target collision sphere</param>
  635. /// <param name="result">A result report</param>
  636. /// <returns>True if there is a collision</returns>
  637. public bool TestRayintersectSphere(CollideRay sourceCollide,
  638. CollideSphere targetCollide,
  639. ref CollisionResult result)
  640. {
  641. totalCollidingCount++;
  642. // Test ray with the sphere
  643. float? distance = sourceCollide.Ray.Intersects(targetCollide.BoundingSphere);
  644. if (distance != null)
  645. {
  646. if (result != null)
  647. {
  648. Vector3 dir = Vector3.Normalize(sourceCollide.Ray.Position -
  649. targetCollide.BoundingSphere.Center);
  650. Vector3 length = dir * targetCollide.Radius;
  651. result.distance = (float)distance;
  652. result.detectedCollide = targetCollide;
  653. result.intersect = targetCollide.BoundingSphere.Center + length;
  654. result.normal = null;
  655. result.collideCount++;
  656. }
  657. return true;
  658. }
  659. return false;
  660. }
  661. /// <summary>
  662. /// It checks for the collision between a collision sphere and a collision model.
  663. /// </summary>
  664. protected bool TestSphereintersectModel(BoundingSphere sphere,
  665. Vector3[] vertices,
  666. Matrix transform,
  667. out Vector3 intersect,
  668. out Vector3 normal,
  669. out float distance)
  670. {
  671. distance = 0.0f;
  672. intersect = Vector3.Zero;
  673. normal = Vector3.Zero;
  674. for (int i = 0; i < vertices.Length; i += 3)
  675. {
  676. // Transform the three vertex positions into world space
  677. Vector3 v1 = Vector3.Transform(vertices[i], transform);
  678. Vector3 v2 = Vector3.Transform(vertices[i + 1], transform);
  679. Vector3 v3 = Vector3.Transform(vertices[i + 2], transform);
  680. totalCollidingCount++;
  681. // Check collision
  682. if (Helper3D.SphereIntersectTriangle(sphere.Center, sphere.Radius,
  683. v1, v2, v3,
  684. out intersect, out distance))
  685. {
  686. normal = Vector3.Normalize(Vector3.Cross(v3 - v1, v2 - v1));
  687. return true;
  688. }
  689. }
  690. return false;
  691. }
  692. /// <summary>
  693. /// It checks for the collision between a collision ray and a collision model.
  694. /// </summary>
  695. protected bool TestRayintersectModel(Ray ray, Vector3[] vertices,
  696. Matrix transform,
  697. out Vector3 intersect,
  698. out Vector3 normal,
  699. out float distance)
  700. {
  701. Triangle outTriangle = new Triangle(Vector3.Zero, Vector3.Zero,
  702. Vector3.Zero);
  703. distance = 0.0f;
  704. intersect = Vector3.Zero;
  705. normal = Vector3.Zero;
  706. totalCollidingCount += vertices.Length;
  707. // Test ray with the model
  708. float? checkDistance = Helper3D.RayIntersectTriangle(ray, vertices,
  709. transform, out outTriangle);
  710. if (checkDistance != null)
  711. {
  712. // Retry test for intersect point and normal
  713. return Helper3D.PointIntersect(ray.Position, ray.Direction, outTriangle,
  714. out distance, out intersect, out normal);
  715. }
  716. return false;
  717. }
  718. protected bool TestUsingQuadTree(CollideElement sourceCollide,
  719. QuadNode quadNode,
  720. out Vector3 intersect,
  721. out Vector3 normal,
  722. out float distance)
  723. {
  724. bool result = false;
  725. float tempDistance = 0.0f;
  726. Vector3 tempIntersect = Vector3.Zero;
  727. Vector3 tempNormal = Vector3.Zero;
  728. float closestDistance = float.MaxValue;
  729. Vector3 closestIntersection = Vector3.Zero;
  730. Vector3 closestNormal = Vector3.Zero;
  731. distance = 0.0f;
  732. intersect = Vector3.Zero;
  733. normal = Vector3.Zero;
  734. // checks upper left node.
  735. if (quadNode.UpperLeftNode != null)
  736. {
  737. if (TestUsingQuadTree(sourceCollide, quadNode.UpperLeftNode,
  738. out tempIntersect, out tempNormal,
  739. out tempDistance))
  740. {
  741. result = true;
  742. // checks closest
  743. if (closestDistance > tempDistance)
  744. {
  745. closestDistance = tempDistance;
  746. closestIntersection = tempIntersect;
  747. closestNormal = tempNormal;
  748. }
  749. }
  750. }
  751. // checks upper right node.
  752. if (quadNode.UpperRightNode != null)
  753. {
  754. if (TestUsingQuadTree(sourceCollide, quadNode.UpperRightNode,
  755. out tempIntersect, out tempNormal,
  756. out tempDistance))
  757. {
  758. result = true;
  759. // checks closest
  760. if (closestDistance > tempDistance)
  761. {
  762. closestDistance = tempDistance;
  763. closestIntersection = tempIntersect;
  764. closestNormal = tempNormal;
  765. }
  766. }
  767. }
  768. // checks lower left node.
  769. if (quadNode.LowerLeftNode != null)
  770. {
  771. if (TestUsingQuadTree(sourceCollide, quadNode.LowerLeftNode,
  772. out tempIntersect, out tempNormal,
  773. out tempDistance))
  774. {
  775. result = true;
  776. // checks closest
  777. if (closestDistance > tempDistance)
  778. {
  779. closestDistance = tempDistance;
  780. closestIntersection = tempIntersect;
  781. closestNormal = tempNormal;
  782. }
  783. }
  784. }
  785. // checks lower right node.
  786. if (quadNode.LowerRightNode != null)
  787. {
  788. if (TestUsingQuadTree(sourceCollide, quadNode.LowerRightNode,
  789. out tempIntersect, out tempNormal,
  790. out tempDistance))
  791. {
  792. result = true;
  793. // checks closest
  794. if (closestDistance > tempDistance)
  795. {
  796. closestDistance = tempDistance;
  797. closestIntersection = tempIntersect;
  798. closestNormal = tempNormal;
  799. }
  800. }
  801. }
  802. // checks vertices in quad node.
  803. if (quadNode.Contains(ref sourceCollide))
  804. {
  805. // checks vertices with bounding sphere.
  806. if (sourceCollide is CollideSphere)
  807. {
  808. CollideSphere collide = sourceCollide as CollideSphere;
  809. // Hit test sphere with the model
  810. BoundingSphere sphere = collide.BoundingSphere;
  811. if (quadNode.Vertices != null)
  812. {
  813. if (TestSphereintersectModel(sphere, quadNode.Vertices,
  814. Matrix.Identity,
  815. out tempIntersect, out tempNormal,
  816. out tempDistance))
  817. {
  818. result = true;
  819. // checks closest
  820. if (closestDistance > tempDistance)
  821. {
  822. closestDistance = tempDistance;
  823. closestIntersection = tempIntersect;
  824. closestNormal = tempNormal;
  825. }
  826. }
  827. }
  828. }
  829. // checks vertices with ray.
  830. else if (sourceCollide is CollideRay)
  831. {
  832. CollideRay collide = sourceCollide as CollideRay;
  833. if (quadNode.Vertices != null)
  834. {
  835. if (TestRayintersectModel(collide.Ray, quadNode.Vertices,
  836. Matrix.Identity,
  837. out tempIntersect, out tempNormal,
  838. out tempDistance))
  839. {
  840. result = true;
  841. // checks closest
  842. if (closestDistance > tempDistance)
  843. {
  844. closestDistance = tempDistance;
  845. closestIntersection = tempIntersect;
  846. closestNormal = tempNormal;
  847. }
  848. }
  849. }
  850. }
  851. }
  852. // resolve final result.
  853. if (result)
  854. {
  855. distance = closestDistance;
  856. intersect = closestIntersection;
  857. normal = closestNormal;
  858. }
  859. return result;
  860. }
  861. }
  862. }