CollisionSample.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. //-----------------------------------------------------------------------------
  2. // CollisionSample.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 System.Linq;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Audio;
  12. using Microsoft.Xna.Framework.GamerServices;
  13. using Microsoft.Xna.Framework.Graphics;
  14. using Microsoft.Xna.Framework.Input;
  15. using Microsoft.Xna.Framework.Input.Touch;
  16. using Microsoft.Xna.Framework.Media;
  17. namespace CollisionSample
  18. {
  19. /// <summary>
  20. /// This sample demonstrates various forms of collision detection for primitives
  21. /// supplied in the framework, plus oriented bounding boxes and triangles.
  22. /// </summary>
  23. public class CollisionSample : Microsoft.Xna.Framework.Game
  24. {
  25. #region Constants
  26. public const int FrustumGroupIndex = 0;
  27. public const int AABoxGroupIndex = 1;
  28. public const int OBoxGroupIndex = 2;
  29. public const int SphereGroupIndex = 3;
  30. public const int RayGroupIndex = 4;
  31. public const int NumGroups = 5;
  32. public const int TriIndex = 0;
  33. public const int SphereIndex = 1;
  34. public const int AABoxIndex = 2;
  35. public const int OBoxIndex = 3;
  36. public const int NumSecondaryShapes = 4;
  37. public const float CAMERA_SPACING = 50.0F;
  38. public const float YAW_RATE = 1; // radians per second for keyboard controls
  39. public const float PITCH_RATE = 0.75f; // radians per second for keyboard controls
  40. public const float YAW_DRAG_RATE = .01f; // radians per pixel for drag control
  41. public const float PITCH_DRAG_RATE = .01f; // radians per pixel for drag control
  42. public const float PINCH_ZOOM_RATE = .01f; // scale factor for pinch-zoom rate
  43. public const float DISTANCE_RATE = 10;
  44. #endregion
  45. #region Fields
  46. // Rendering helpers
  47. GraphicsDeviceManager graphics;
  48. DebugDraw debugDraw;
  49. // Primary shapes
  50. BoundingFrustum primaryFrustum;
  51. BoundingBox primaryAABox;
  52. BoundingOrientedBox primaryOBox;
  53. BoundingSphere primarySphere;
  54. Ray primaryRay;
  55. // Secondary shapes.
  56. Triangle[] secondaryTris = new Triangle[NumGroups];
  57. BoundingSphere[] secondarySpheres = new BoundingSphere[NumGroups];
  58. BoundingBox[] secondaryAABoxes = new BoundingBox[NumGroups];
  59. BoundingOrientedBox[] secondaryOBoxes = new BoundingOrientedBox[NumGroups];
  60. // Collision results
  61. ContainmentType[,] collideResults = new ContainmentType[NumGroups, NumSecondaryShapes];
  62. Vector3? rayHitResult;
  63. // Camera state
  64. Vector3[] cameraOrigins = new Vector3[NumGroups];
  65. int currentCamera;
  66. bool cameraOrtho;
  67. float cameraYaw;
  68. float cameraPitch;
  69. float cameraDistance;
  70. Vector3 cameraTarget;
  71. KeyboardState currentKeyboardState = new KeyboardState();
  72. GamePadState currentGamePadState = new GamePadState();
  73. List<GestureSample> currentGestures = new List<GestureSample>();
  74. KeyboardState previousKeyboardState = new KeyboardState();
  75. GamePadState previousGamePadState = new GamePadState();
  76. TimeSpan unpausedClock = new TimeSpan();
  77. bool paused;
  78. #endregion
  79. #region Initialization
  80. public CollisionSample()
  81. {
  82. graphics = new GraphicsDeviceManager(this);
  83. TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Pinch | GestureType.FreeDrag;
  84. #if WINDOWS_PHONE
  85. TargetElapsedTime = TimeSpan.FromTicks(333333);
  86. graphics.IsFullScreen = true;
  87. #endif
  88. #if WINDOWS || XBOX
  89. graphics.PreferredBackBufferWidth = 853;
  90. graphics.PreferredBackBufferHeight = 480;
  91. #endif
  92. }
  93. // Set up initial bounding shapes for the primary (static) and secondary (moving)
  94. // bounding shapes along with relevant camera position information.
  95. protected override void Initialize()
  96. {
  97. Console.WriteLine("DEBUG - Game Initialize!");
  98. debugDraw = new DebugDraw(GraphicsDevice);
  99. Components.Add(new FrameRateCounter(this));
  100. // Primary frustum
  101. Matrix m1 = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.77778F, 0.5f, 10.0f);
  102. Matrix m2 = Matrix.CreateTranslation(new Vector3(0, 0, -7));
  103. primaryFrustum = new BoundingFrustum(Matrix.Multiply(m2, m1));
  104. cameraOrigins[FrustumGroupIndex] = Vector3.Zero;
  105. // Primary axis-aligned box
  106. primaryAABox.Min = new Vector3(CAMERA_SPACING - 3, -4, -5);
  107. primaryAABox.Max = new Vector3(CAMERA_SPACING + 3, 4, 5);
  108. cameraOrigins[AABoxGroupIndex] = new Vector3(CAMERA_SPACING, 0, 0);
  109. // Primary oriented box
  110. primaryOBox.Center = new Vector3(-CAMERA_SPACING, 0, 0);
  111. primaryOBox.HalfExtent = new Vector3(3, 4, 5);
  112. primaryOBox.Orientation = Quaternion.CreateFromYawPitchRoll(0.8f, 0.7f, 0);
  113. cameraOrigins[OBoxGroupIndex] = primaryOBox.Center;
  114. // Primary sphere
  115. primarySphere.Center = new Vector3(0, 0, -CAMERA_SPACING);
  116. primarySphere.Radius = 5;
  117. cameraOrigins[SphereGroupIndex] = primarySphere.Center;
  118. // Primary ray
  119. primaryRay.Position = new Vector3(0, 0, CAMERA_SPACING);
  120. primaryRay.Direction = Vector3.UnitZ;
  121. cameraOrigins[RayGroupIndex] = primaryRay.Position;
  122. // Initialize all of the secondary objects with default values
  123. Vector3 half = new Vector3(0.5F, 0.5F, 0.5F);
  124. for (int i = 0; i < NumGroups; i++)
  125. {
  126. secondarySpheres[i] = new BoundingSphere(Vector3.Zero, 1.0f);
  127. secondaryOBoxes[i] = new BoundingOrientedBox(Vector3.Zero, half, Quaternion.Identity);
  128. secondaryAABoxes[i] = new BoundingBox(-half, half);
  129. secondaryTris[i] = new Triangle();
  130. }
  131. rayHitResult = null;
  132. currentCamera = 3;
  133. cameraOrtho = false;
  134. cameraYaw = (float)Math.PI * 0.75F;
  135. cameraPitch = MathHelper.PiOver4;
  136. cameraDistance = 20;
  137. cameraTarget = cameraOrigins[0];
  138. paused = false;
  139. base.Initialize();
  140. }
  141. #endregion
  142. #region Update
  143. protected override void Update(GameTime gameTime)
  144. {
  145. ReadInputDevices();
  146. if (currentKeyboardState.IsKeyDown(Keys.Escape) || currentGamePadState.IsButtonDown(Buttons.Back))
  147. this.Exit();
  148. if (!paused)
  149. {
  150. unpausedClock += gameTime.ElapsedGameTime;
  151. }
  152. // Run collision even when paused, for timing and debugging, and so the step
  153. // forward/backward keys work.
  154. Animate();
  155. Collide();
  156. HandleInput(gameTime);
  157. base.Update(gameTime);
  158. }
  159. private void ReadInputDevices()
  160. {
  161. previousKeyboardState = currentKeyboardState;
  162. previousGamePadState = currentGamePadState;
  163. currentKeyboardState = Keyboard.GetState();
  164. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  165. currentGestures.Clear();
  166. while (TouchPanel.IsGestureAvailable)
  167. {
  168. currentGestures.Add(TouchPanel.ReadGesture());
  169. }
  170. }
  171. /// <summary>
  172. /// Move all the secondary shapes around, and move the ray so it
  173. /// sweeps back and forth across its secondry shapes.
  174. /// </summary>
  175. private void Animate()
  176. {
  177. float t = (float)unpausedClock.TotalSeconds / 2.0F;
  178. // Rates at which x,y,z cycle
  179. const float xRate = 1.1f;
  180. const float yRate = 3.6f;
  181. const float zRate = 1.9f;
  182. const float pathSize = 6;
  183. // how far apart following shapes are, in seconds
  184. const float gap = 0.25f;
  185. // orientation for rotatable shapes
  186. Quaternion orientation = Quaternion.CreateFromYawPitchRoll(t * 0.2f, t * 1.4f, t);
  187. for (int g = 0; g < NumGroups; g++)
  188. {
  189. // Animate spheres
  190. secondarySpheres[g].Center = cameraOrigins[g];
  191. secondarySpheres[g].Center.X += pathSize * (float)Math.Sin(xRate * t);
  192. secondarySpheres[g].Center.Y += pathSize * (float)Math.Sin(yRate * t);
  193. secondarySpheres[g].Center.Z += pathSize * (float)Math.Sin(zRate * t);
  194. // Animate oriented boxes
  195. secondaryOBoxes[g].Center = cameraOrigins[g];
  196. secondaryOBoxes[g].Orientation = orientation;
  197. secondaryOBoxes[g].Center.X += pathSize * (float)Math.Sin(xRate * (t - gap));
  198. secondaryOBoxes[g].Center.Y += pathSize * (float)Math.Sin(yRate * (t - gap));
  199. secondaryOBoxes[g].Center.Z += pathSize * (float)Math.Sin(zRate * (t - gap));
  200. // Animate axis-aligned boxes
  201. Vector3 boxsize = new Vector3(1.0f, 1.3f, 1.9f);
  202. secondaryAABoxes[g].Min = cameraOrigins[g] - boxsize * 0.5f;
  203. secondaryAABoxes[g].Min.X += pathSize * (float)Math.Sin(xRate * (t - 2 * gap));
  204. secondaryAABoxes[g].Min.Y += pathSize * (float)Math.Sin(yRate * (t - 2 * gap));
  205. secondaryAABoxes[g].Min.Z += pathSize * (float)Math.Sin(zRate * (t - 2 * gap));
  206. secondaryAABoxes[g].Max = secondaryAABoxes[g].Min + boxsize;
  207. // Animate triangles
  208. Vector3 trianglePos = cameraOrigins[g];
  209. trianglePos.X += pathSize * (float)Math.Sin(xRate * (t - 3 * gap));
  210. trianglePos.Y += pathSize * (float)Math.Sin(yRate * (t - 3 * gap));
  211. trianglePos.Z += pathSize * (float)Math.Sin(zRate * (t - 3 * gap));
  212. // triangle points in local space - equilateral triangle with radius of 2
  213. secondaryTris[g].V0 = trianglePos + Vector3.Transform(new Vector3(0, 2, 0), orientation);
  214. secondaryTris[g].V1 = trianglePos + Vector3.Transform(new Vector3(1.73f, -1, 0), orientation);
  215. secondaryTris[g].V2 = trianglePos + Vector3.Transform(new Vector3(-1.73f, -1, 0), orientation);
  216. }
  217. //int index = (int)(t*5);
  218. //secondaryOBoxes[OBoxGroupIndex] = BoundingOrientedBox.iboxes[index % BoundingOrientedBox.iboxes.Length];
  219. // Animate primary ray (this is the only animated primary object)
  220. // It sweeps back and forth across the secondary objects
  221. const float sweepTime = 3.1f;
  222. float rayDt = (-Math.Abs((t/sweepTime) % 2.0f - 1.0f) * NumSecondaryShapes + 0.5f) * gap;
  223. primaryRay.Direction.X = (float)Math.Sin(xRate * (t + rayDt));
  224. primaryRay.Direction.Y = (float)Math.Sin(yRate * (t + rayDt));
  225. primaryRay.Direction.Z = (float)Math.Sin(zRate * (t + rayDt));
  226. primaryRay.Direction.Normalize();
  227. }
  228. /// <summary>
  229. /// Check each pair of objects for collision/containment and store the results for
  230. /// coloring them at render time.
  231. /// </summary>
  232. private void Collide()
  233. {
  234. // test collisions between objects and frustum
  235. collideResults[FrustumGroupIndex, SphereIndex] = primaryFrustum.Contains(secondarySpheres[FrustumGroupIndex]);
  236. collideResults[FrustumGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(primaryFrustum, ref secondaryOBoxes[FrustumGroupIndex]);
  237. collideResults[FrustumGroupIndex, AABoxIndex] = primaryFrustum.Contains(secondaryAABoxes[FrustumGroupIndex]);
  238. collideResults[FrustumGroupIndex, TriIndex] = TriangleTest.Contains(primaryFrustum, ref secondaryTris[FrustumGroupIndex]);
  239. // test collisions between objects and aligned box
  240. collideResults[AABoxGroupIndex, SphereIndex] = primaryAABox.Contains(secondarySpheres[AABoxGroupIndex]);
  241. collideResults[AABoxGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(ref primaryAABox, ref secondaryOBoxes[AABoxGroupIndex]);
  242. collideResults[AABoxGroupIndex, AABoxIndex] = primaryAABox.Contains(secondaryAABoxes[AABoxGroupIndex]);
  243. collideResults[AABoxGroupIndex, TriIndex] = TriangleTest.Contains(ref primaryAABox, ref secondaryTris[AABoxGroupIndex]);
  244. // test collisions between objects and oriented box
  245. collideResults[OBoxGroupIndex, SphereIndex] = primaryOBox.Contains(ref secondarySpheres[OBoxGroupIndex]);
  246. collideResults[OBoxGroupIndex, OBoxIndex] = primaryOBox.Contains(ref secondaryOBoxes[OBoxGroupIndex]);
  247. collideResults[OBoxGroupIndex, AABoxIndex] = primaryOBox.Contains(ref secondaryAABoxes[OBoxGroupIndex]);
  248. collideResults[OBoxGroupIndex, TriIndex] = TriangleTest.Contains(ref primaryOBox, ref secondaryTris[OBoxGroupIndex]);
  249. // test collisions between objects and sphere
  250. collideResults[SphereGroupIndex, SphereIndex] = primarySphere.Contains(secondarySpheres[SphereGroupIndex]);
  251. collideResults[SphereGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(ref primarySphere, ref secondaryOBoxes[SphereGroupIndex]);
  252. collideResults[SphereGroupIndex, AABoxIndex] = primarySphere.Contains(secondaryAABoxes[SphereGroupIndex]);
  253. collideResults[SphereGroupIndex, TriIndex] = TriangleTest.Contains(ref primarySphere, ref secondaryTris[SphereGroupIndex]);
  254. // test collisions between objects and ray
  255. float dist = -1;
  256. collideResults[RayGroupIndex, SphereIndex] =
  257. collideResults[RayGroupIndex, OBoxIndex] =
  258. collideResults[RayGroupIndex, AABoxIndex] =
  259. collideResults[RayGroupIndex, TriIndex] = ContainmentType.Disjoint;
  260. rayHitResult = null;
  261. float? r = primaryRay.Intersects(secondarySpheres[RayGroupIndex]);
  262. if (r.HasValue)
  263. {
  264. collideResults[RayGroupIndex, SphereIndex] = ContainmentType.Intersects;
  265. dist = r.Value;
  266. }
  267. r = secondaryOBoxes[RayGroupIndex].Intersects(ref primaryRay);
  268. if (r.HasValue)
  269. {
  270. collideResults[RayGroupIndex, OBoxIndex] = ContainmentType.Intersects;
  271. dist = r.Value;
  272. }
  273. r = primaryRay.Intersects(secondaryAABoxes[RayGroupIndex]);
  274. if (r.HasValue)
  275. {
  276. collideResults[RayGroupIndex, AABoxIndex] = ContainmentType.Intersects;
  277. dist = r.Value;
  278. }
  279. r = TriangleTest.Intersects(ref primaryRay, ref secondaryTris[RayGroupIndex]);
  280. if (r.HasValue)
  281. {
  282. collideResults[RayGroupIndex, TriIndex] = ContainmentType.Intersects;
  283. dist = r.Value;
  284. }
  285. // If one of the ray intersection tests was successful, fDistance will be positive.
  286. // If so, compute the intersection location and store it in g_RayHitResultBox.
  287. if (dist > 0)
  288. {
  289. rayHitResult = primaryRay.Position + primaryRay.Direction * dist;
  290. }
  291. }
  292. private void HandleInput(GameTime gameTime)
  293. {
  294. // Rely on the fact that we are using fixed time-step update
  295. float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
  296. // Allow single-stepping through time
  297. if (paused)
  298. {
  299. if (currentKeyboardState.IsKeyDown(Keys.OemOpenBrackets))
  300. unpausedClock -= TimeSpan.FromSeconds(dt);
  301. if (currentKeyboardState.IsKeyDown(Keys.OemCloseBrackets))
  302. unpausedClock += TimeSpan.FromSeconds(dt);
  303. }
  304. // Change yaw/pitch based on right thumbstickb
  305. cameraYaw += currentGamePadState.ThumbSticks.Right.X * dt * YAW_RATE;
  306. cameraPitch += currentGamePadState.ThumbSticks.Right.Y * dt * PITCH_RATE;
  307. if (currentKeyboardState.IsKeyDown(Keys.Right))
  308. cameraYaw += dt * YAW_RATE;
  309. if (currentKeyboardState.IsKeyDown(Keys.Left))
  310. cameraYaw -= dt * YAW_RATE;
  311. if (currentKeyboardState.IsKeyDown(Keys.Up))
  312. cameraPitch += dt * PITCH_RATE;
  313. if (currentKeyboardState.IsKeyDown(Keys.Down))
  314. cameraPitch -= dt * PITCH_RATE;
  315. // Change distance based on right/left trigger
  316. if (currentGamePadState.IsButtonDown(Buttons.LeftTrigger)
  317. || currentKeyboardState.IsKeyDown(Keys.Subtract)
  318. || currentKeyboardState.IsKeyDown(Keys.OemMinus))
  319. {
  320. cameraDistance += dt * DISTANCE_RATE;
  321. }
  322. if (currentGamePadState.IsButtonDown(Buttons.RightTrigger)
  323. || currentKeyboardState.IsKeyDown(Keys.Add)
  324. || currentKeyboardState.IsKeyDown(Keys.OemPlus))
  325. {
  326. cameraDistance -= dt * DISTANCE_RATE;
  327. }
  328. // Group cycle
  329. if ( (currentKeyboardState.IsKeyDown(Keys.G) && previousKeyboardState.IsKeyUp(Keys.G)) ||
  330. (currentGamePadState.IsButtonDown(Buttons.A) && previousGamePadState.IsButtonUp(Buttons.A)))
  331. {
  332. currentCamera = (currentCamera + 1) % NumGroups;
  333. }
  334. // Camera reset
  335. if ((currentKeyboardState.IsKeyDown(Keys.Home) && previousKeyboardState.IsKeyUp(Keys.Home))
  336. || (currentGamePadState.IsButtonDown(Buttons.Y) && previousGamePadState.IsButtonUp(Buttons.Y)))
  337. {
  338. cameraYaw = (float)Math.PI * 0.75F;
  339. cameraPitch = MathHelper.PiOver4;
  340. cameraDistance = 40;
  341. }
  342. // Orthographic vs. perpsective projection toggle
  343. if ((currentKeyboardState.IsKeyDown(Keys.B) && previousKeyboardState.IsKeyUp(Keys.B))
  344. || (currentGamePadState.IsButtonDown(Buttons.B) && previousGamePadState.IsButtonUp(Buttons.B)))
  345. {
  346. cameraOrtho = !cameraOrtho;
  347. }
  348. if (currentKeyboardState.IsKeyDown(Keys.O))
  349. {
  350. cameraOrtho = true;
  351. }
  352. if (currentKeyboardState.IsKeyDown(Keys.P))
  353. {
  354. cameraOrtho = false;
  355. }
  356. // Pause animation
  357. if ((currentKeyboardState.IsKeyDown(Keys.Space) && previousKeyboardState.IsKeyUp(Keys.Space))
  358. || (currentGamePadState.IsButtonDown(Buttons.X) && previousGamePadState.IsButtonUp(Buttons.X)))
  359. {
  360. paused = !paused;
  361. }
  362. // Handle tap, drag, and pinch gestures
  363. foreach (GestureSample sample in currentGestures)
  364. {
  365. switch (sample.GestureType)
  366. {
  367. case GestureType.Tap:
  368. currentCamera = (currentCamera + 1) % NumGroups;
  369. break;
  370. case GestureType.FreeDrag:
  371. cameraYaw += sample.Delta.X * -YAW_DRAG_RATE;
  372. cameraPitch += sample.Delta.Y * PITCH_DRAG_RATE;
  373. break;
  374. case GestureType.Pinch:
  375. float dOld = Vector2.Distance(sample.Position - sample.Delta, sample.Position2 - sample.Delta2);
  376. float dNew = Vector2.Distance(sample.Position, sample.Position2);
  377. cameraDistance *= (float)Math.Exp((dOld - dNew) * PINCH_ZOOM_RATE);
  378. break;
  379. }
  380. }
  381. // Clamp camera to safe values
  382. cameraYaw = MathHelper.WrapAngle(cameraYaw);
  383. cameraPitch = MathHelper.Clamp(cameraPitch, -MathHelper.PiOver2, MathHelper.PiOver2);
  384. cameraDistance = MathHelper.Clamp(cameraDistance, 2, 80);
  385. // Handle time-based lerp for group transition
  386. float lerp = Math.Min(4.0F * dt, 1.0F);
  387. cameraTarget = (lerp * cameraOrigins[currentCamera]) + ((1.0F - lerp) * cameraTarget);
  388. }
  389. #endregion
  390. #region Draw
  391. /// <summary>
  392. /// This draws the bounding shapes and HUD for the sample.
  393. /// </summary>
  394. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  395. protected override void Draw(GameTime gameTime)
  396. {
  397. GraphicsDevice.Clear(Color.CornflowerBlue);
  398. float aspect = GraphicsDevice.Viewport.AspectRatio;
  399. float yawCos = (float)Math.Cos(cameraYaw);
  400. float yawSin = (float)Math.Sin(cameraYaw);
  401. float pitchCos = (float)Math.Cos(cameraPitch);
  402. float pitchSin = (float)Math.Sin(cameraPitch);
  403. Vector3 eye = new Vector3(cameraDistance * pitchCos * yawSin + cameraTarget.X,
  404. cameraDistance * pitchSin + cameraTarget.Y,
  405. cameraDistance * pitchCos * yawCos + cameraTarget.Z);
  406. Matrix view = Matrix.CreateLookAt(eye, cameraTarget, Vector3.Up);
  407. Matrix projection = (cameraOrtho)
  408. ? Matrix.CreateOrthographic(aspect * cameraDistance, cameraDistance, 1.0F, 1000.0F)
  409. : Matrix.CreatePerspectiveFieldOfView((float)(System.Math.PI) / 4.0F, aspect, 1.0F, 1000.0F);
  410. debugDraw.Begin(view, projection);
  411. // Draw ground planes
  412. for (int g = 0; g < NumGroups; ++g)
  413. {
  414. Vector3 origin = new Vector3(cameraOrigins[g].X - 20, cameraOrigins[g].Y - 10, cameraOrigins[g].Z - 20);
  415. debugDraw.DrawWireGrid(Vector3.UnitX*40, Vector3.UnitZ*40, origin, 20, 20, Color.Black);
  416. }
  417. DrawPrimaryShapes();
  418. // Draw secondary shapes
  419. for (int g = 0; g < NumGroups; g++)
  420. {
  421. debugDraw.DrawWireSphere(secondarySpheres[g], GetCollideColor(g, SphereIndex));
  422. debugDraw.DrawWireBox(secondaryAABoxes[g], GetCollideColor(g, AABoxIndex));
  423. debugDraw.DrawWireBox(secondaryOBoxes[g], GetCollideColor(g, OBoxIndex));
  424. debugDraw.DrawWireTriangle(secondaryTris[g], GetCollideColor(g, TriIndex));
  425. }
  426. // Draw results of ray-object intersection, if there was a hit this frame
  427. if (rayHitResult.HasValue)
  428. {
  429. Vector3 size = new Vector3(0.05f, 0.05f, 0.05f);
  430. BoundingBox weeBox = new BoundingBox(rayHitResult.Value - size, rayHitResult.Value + size);
  431. debugDraw.DrawWireBox(weeBox, Color.Yellow);
  432. }
  433. debugDraw.End();
  434. // Draw overlay text.
  435. // string text = "A = (G)roup\nY = Reset (Home)\nB = (O)rtho/(P)erspective\nX = Pause (Space)";
  436. // spriteBatch.Begin();
  437. // spriteBatch.DrawString(spriteFont, text, new Vector2(86, 48), Color.White);
  438. // spriteBatch.End();
  439. base.Draw(gameTime);
  440. }
  441. void DrawPrimaryShapes()
  442. {
  443. debugDraw.DrawWireBox(primaryAABox, Color.White);
  444. debugDraw.DrawWireBox(primaryOBox, Color.White);
  445. debugDraw.DrawWireFrustum(primaryFrustum, Color.White);
  446. debugDraw.DrawWireSphere(primarySphere, Color.White);
  447. debugDraw.DrawRay(primaryRay, Color.Red, 10.0f);
  448. }
  449. private Color GetCollideColor(int group, int shape)
  450. {
  451. ContainmentType cr = collideResults[group, shape];
  452. switch (cr)
  453. {
  454. case ContainmentType.Contains:
  455. return Color.Red;
  456. case ContainmentType.Disjoint:
  457. return Color.LightGray;
  458. case ContainmentType.Intersects:
  459. return Color.Yellow;
  460. default:
  461. return Color.Black;
  462. }
  463. }
  464. #endregion
  465. }
  466. }