PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/3D_FileExplorer/3D_FileExplorer/Vizualization/CursorOperations/Picking.cs

#
C# | 295 lines | 154 code | 66 blank | 75 comment | 21 complexity | f6692bc40fb31be23097e17c45eb6b65 MD5 | raw file
  1. #region Using Statements
  2. using System;
  3. using System.Collections.Generic;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Content;
  6. using Microsoft.Xna.Framework.Graphics;
  7. using Microsoft.Xna.Framework.Input;
  8. #endregion
  9. namespace _3D_FileExplorer
  10. {
  11. /// <summary>
  12. /// Sample showing how to implement per-triangle picking. This uses a custom
  13. /// content pipeline processor to attach a list of vertex position data to each
  14. /// model as part of the build process, and then implements a ray-to-triangle
  15. /// intersection method to collide against this vertex data.
  16. /// </summary>
  17. public class Picking
  18. {
  19. #region Fields
  20. List<string> insideBoundingSpheres = new List<string>();
  21. public static string pickedModelName;
  22. int index = -1;
  23. #endregion
  24. public Picking()
  25. {
  26. }
  27. #region Update and Draw
  28. public Primitives UpdatePicking(List<Primitives> cilTree, Ray cursorRay)
  29. {
  30. // Look up a collision ray based on the current cursor position. See the
  31. // Picking Sample documentation for a detailed explanation of this.
  32. // Clear the previous picking results.
  33. insideBoundingSpheres.Clear();
  34. pickedModelName = null;
  35. // Keep track of the closest object we have seen so far, so we can
  36. // choose the closest one if there are several models under the cursor.
  37. float closestIntersection = float.MaxValue;
  38. // Loop over all our models.
  39. for (int i = 0; i < cilTree.Count; i++)
  40. {
  41. bool insideBoundingSphere;
  42. Vector3 vertex1, vertex2, vertex3;
  43. // Perform the ray to model intersection test.
  44. float? intersection = RayIntersectsModel(cursorRay, cilTree[i],
  45. cilTree[i].fulltransform,
  46. out insideBoundingSphere,
  47. out vertex1, out vertex2,
  48. out vertex3);
  49. // If this model passed the initial bounding sphere test, remember
  50. // that so we can display it at the top of the screen.
  51. if (insideBoundingSphere)
  52. insideBoundingSpheres.Add(cilTree[i].name);
  53. // Do we have a per-triangle intersection with this model?
  54. if (intersection != null)
  55. {
  56. // If so, is it closer than any other model we might have
  57. // previously intersected?
  58. if (intersection < closestIntersection)
  59. {
  60. // Store information about this model.
  61. closestIntersection = intersection.Value;
  62. pickedModelName = cilTree[i].name;
  63. index = i;
  64. }
  65. }
  66. }
  67. //if nothing is selected uncolor last selected cilinder
  68. if (pickedModelName != null)
  69. {
  70. Fe.form.StatusLabel.Text = cilTree[index].shortName;
  71. // Console.WriteLine(cilTree[index].rotation.Up);
  72. // Console.WriteLine(Fe.camera.cameraUp);
  73. return cilTree[index];
  74. }
  75. else
  76. {
  77. Fe.form.StatusLabel.Text = "";
  78. return null;
  79. }
  80. }
  81. /// <summary>
  82. /// Checks whether a ray intersects a model. This method needs to access
  83. /// the model vertex data, so the model must have been built using the
  84. /// custom TrianglePickingProcessor provided as part of this sample.
  85. /// Returns the distance along the ray to the point of intersection, or null
  86. /// if there is no intersection.
  87. /// </summary>
  88. static float? RayIntersectsModel(Ray ray, Primitives cilinder, Matrix modelTransform,
  89. out bool insideBoundingSphere,
  90. out Vector3 vertex1, out Vector3 vertex2,
  91. out Vector3 vertex3)
  92. {
  93. vertex1 = vertex2 = vertex3 = Vector3.Zero;
  94. // The input ray is in world space, but our model data is stored in object
  95. // space. We would normally have to transform all the model data by the
  96. // modelTransform matrix, moving it into world space before we test it
  97. // against the ray. That transform can be slow if there are a lot of
  98. // triangles in the model, however, so instead we do the opposite.
  99. // Transforming our ray by the inverse modelTransform moves it into object
  100. // space, where we can test it directly against our model data. Since there
  101. // is only one ray but typically many triangles, doing things this way
  102. // around can be much faster.
  103. Matrix inverseTransform = Matrix.Invert(modelTransform);
  104. ray.Position = Vector3.Transform(ray.Position, inverseTransform);
  105. ray.Direction = Vector3.TransformNormal(ray.Direction, inverseTransform);
  106. // Start off with a fast bounding sphere test.
  107. if (cilinder.boudingSphere.Intersects(ray) == null)
  108. {
  109. // If the ray does not intersect the bounding sphere, we cannot
  110. // possibly have picked this model, so there is no need to even
  111. // bother looking at the individual triangle data.
  112. insideBoundingSphere = false;
  113. return null;
  114. }
  115. else
  116. {
  117. // The bounding sphere test passed, so we need to do a full
  118. // triangle picking test.
  119. insideBoundingSphere = true;
  120. // Keep track of the closest triangle we found so far,
  121. // so we can always return the closest one.
  122. float? closestIntersection = null;
  123. // Loop over the vertex data, 3 at a time (3 vertices = 1 triangle).
  124. Vector3[] vertices = cilinder.pvertices.ToArray();
  125. for (int i = 0; i < cilinder.indices.Count; i += 3)
  126. {
  127. // Perform a ray to triangle intersection test.
  128. float? intersection;
  129. RayIntersectsTriangle(ref ray,
  130. ref vertices[cilinder.indices[i]],
  131. ref vertices[cilinder.indices[i+1]],
  132. ref vertices[cilinder.indices[i+2]],
  133. out intersection);
  134. // Does the ray intersect this triangle?
  135. if (intersection != null)
  136. {
  137. // If so, is it closer than any other previous triangle?
  138. if ((closestIntersection == null) ||
  139. (intersection < closestIntersection))
  140. {
  141. // Store the distance to this triangle.
  142. closestIntersection = intersection;
  143. // Transform the three vertex positions into world space,
  144. // and store them into the output vertex parameters.
  145. Vector3.Transform(ref vertices[cilinder.indices[i]],
  146. ref modelTransform, out vertex1);
  147. Vector3.Transform(ref vertices[cilinder.indices[i+1]],
  148. ref modelTransform, out vertex2);
  149. Vector3.Transform(ref vertices[cilinder.indices[i+2]],
  150. ref modelTransform, out vertex3);
  151. }
  152. }
  153. }
  154. return closestIntersection;
  155. }
  156. }
  157. /// <summary>
  158. /// Checks whether a ray intersects a triangle. This uses the algorithm
  159. /// developed by Tomas Moller and Ben Trumbore, which was published in the
  160. /// Journal of Graphics Tools, volume 2, "Fast, Minimum Storage Ray-Triangle
  161. /// Intersection".
  162. ///
  163. /// This method is implemented using the pass-by-reference versions of the
  164. /// XNA math functions. Using these overloads is generally not recommended,
  165. /// because they make the code less readable than the normal pass-by-value
  166. /// versions. This method can be called very frequently in a tight inner loop,
  167. /// however, so in this particular case the performance benefits from passing
  168. /// everything by reference outweigh the loss of readability.
  169. /// </summary>
  170. static void RayIntersectsTriangle(ref Ray ray,
  171. ref Vector3 vertex1,
  172. ref Vector3 vertex2,
  173. ref Vector3 vertex3, out float? result)
  174. {
  175. // Compute vectors along two edges of the triangle.
  176. Vector3 edge1, edge2;
  177. Vector3.Subtract(ref vertex2, ref vertex1, out edge1);
  178. Vector3.Subtract(ref vertex3, ref vertex1, out edge2);
  179. // Compute the determinant.
  180. Vector3 directionCrossEdge2;
  181. Vector3.Cross(ref ray.Direction, ref edge2, out directionCrossEdge2);
  182. float determinant;
  183. Vector3.Dot(ref edge1, ref directionCrossEdge2, out determinant);
  184. // If the ray is parallel to the triangle plane, there is no collision.
  185. if (determinant > -float.Epsilon && determinant < float.Epsilon)
  186. {
  187. result = null;
  188. return;
  189. }
  190. float inverseDeterminant = 1.0f / determinant;
  191. // Calculate the U parameter of the intersection point.
  192. Vector3 distanceVector;
  193. Vector3.Subtract(ref ray.Position, ref vertex1, out distanceVector);
  194. float triangleU;
  195. Vector3.Dot(ref distanceVector, ref directionCrossEdge2, out triangleU);
  196. triangleU *= inverseDeterminant;
  197. // Make sure it is inside the triangle.
  198. if (triangleU < 0 || triangleU > 1)
  199. {
  200. result = null;
  201. return;
  202. }
  203. // Calculate the V parameter of the intersection point.
  204. Vector3 distanceCrossEdge1;
  205. Vector3.Cross(ref distanceVector, ref edge1, out distanceCrossEdge1);
  206. float triangleV;
  207. Vector3.Dot(ref ray.Direction, ref distanceCrossEdge1, out triangleV);
  208. triangleV *= inverseDeterminant;
  209. // Make sure it is inside the triangle.
  210. if (triangleV < 0 || triangleU + triangleV > 1)
  211. {
  212. result = null;
  213. return;
  214. }
  215. // Compute the distance along the ray to the triangle.
  216. float rayDistance;
  217. Vector3.Dot(ref edge2, ref distanceCrossEdge1, out rayDistance);
  218. rayDistance *= inverseDeterminant;
  219. // Is the triangle behind the ray origin?
  220. if (rayDistance < 0)
  221. {
  222. result = null;
  223. return;
  224. }
  225. result = rayDistance;
  226. }
  227. #endregion
  228. }
  229. }