/3D_FileExplorer/3D_FileExplorer/Vizualization/CursorOperations/Picking.cs
C# | 295 lines | 154 code | 66 blank | 75 comment | 21 complexity | f6692bc40fb31be23097e17c45eb6b65 MD5 | raw file
-
- #region Using Statements
- using System;
- using System.Collections.Generic;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Content;
- using Microsoft.Xna.Framework.Graphics;
- using Microsoft.Xna.Framework.Input;
- #endregion
-
- namespace _3D_FileExplorer
- {
- /// <summary>
- /// Sample showing how to implement per-triangle picking. This uses a custom
- /// content pipeline processor to attach a list of vertex position data to each
- /// model as part of the build process, and then implements a ray-to-triangle
- /// intersection method to collide against this vertex data.
- /// </summary>
- public class Picking
- {
-
-
- #region Fields
-
-
- List<string> insideBoundingSpheres = new List<string>();
- public static string pickedModelName;
- int index = -1;
-
-
- #endregion
-
- public Picking()
-
- {
-
- }
-
-
-
-
- #region Update and Draw
-
- public Primitives UpdatePicking(List<Primitives> cilTree, Ray cursorRay)
- {
- // Look up a collision ray based on the current cursor position. See the
- // Picking Sample documentation for a detailed explanation of this.
-
- // Clear the previous picking results.
- insideBoundingSpheres.Clear();
-
- pickedModelName = null;
-
- // Keep track of the closest object we have seen so far, so we can
- // choose the closest one if there are several models under the cursor.
- float closestIntersection = float.MaxValue;
-
- // Loop over all our models.
- for (int i = 0; i < cilTree.Count; i++)
- {
- bool insideBoundingSphere;
- Vector3 vertex1, vertex2, vertex3;
-
- // Perform the ray to model intersection test.
- float? intersection = RayIntersectsModel(cursorRay, cilTree[i],
- cilTree[i].fulltransform,
- out insideBoundingSphere,
- out vertex1, out vertex2,
- out vertex3);
-
- // If this model passed the initial bounding sphere test, remember
- // that so we can display it at the top of the screen.
- if (insideBoundingSphere)
- insideBoundingSpheres.Add(cilTree[i].name);
-
- // Do we have a per-triangle intersection with this model?
- if (intersection != null)
- {
- // If so, is it closer than any other model we might have
- // previously intersected?
- if (intersection < closestIntersection)
- {
- // Store information about this model.
- closestIntersection = intersection.Value;
- pickedModelName = cilTree[i].name;
- index = i;
- }
- }
-
- }
- //if nothing is selected uncolor last selected cilinder
-
- if (pickedModelName != null)
- {
- Fe.form.StatusLabel.Text = cilTree[index].shortName;
- // Console.WriteLine(cilTree[index].rotation.Up);
- // Console.WriteLine(Fe.camera.cameraUp);
- return cilTree[index];
- }
- else
- {
- Fe.form.StatusLabel.Text = "";
- return null;
- }
- }
-
-
- /// <summary>
- /// Checks whether a ray intersects a model. This method needs to access
- /// the model vertex data, so the model must have been built using the
- /// custom TrianglePickingProcessor provided as part of this sample.
- /// Returns the distance along the ray to the point of intersection, or null
- /// if there is no intersection.
- /// </summary>
- static float? RayIntersectsModel(Ray ray, Primitives cilinder, Matrix modelTransform,
- out bool insideBoundingSphere,
- out Vector3 vertex1, out Vector3 vertex2,
- out Vector3 vertex3)
- {
- vertex1 = vertex2 = vertex3 = Vector3.Zero;
-
- // The input ray is in world space, but our model data is stored in object
- // space. We would normally have to transform all the model data by the
- // modelTransform matrix, moving it into world space before we test it
- // against the ray. That transform can be slow if there are a lot of
- // triangles in the model, however, so instead we do the opposite.
- // Transforming our ray by the inverse modelTransform moves it into object
- // space, where we can test it directly against our model data. Since there
- // is only one ray but typically many triangles, doing things this way
- // around can be much faster.
-
- Matrix inverseTransform = Matrix.Invert(modelTransform);
-
- ray.Position = Vector3.Transform(ray.Position, inverseTransform);
- ray.Direction = Vector3.TransformNormal(ray.Direction, inverseTransform);
-
-
- // Start off with a fast bounding sphere test.
-
- if (cilinder.boudingSphere.Intersects(ray) == null)
- {
- // If the ray does not intersect the bounding sphere, we cannot
- // possibly have picked this model, so there is no need to even
- // bother looking at the individual triangle data.
- insideBoundingSphere = false;
-
- return null;
- }
- else
- {
- // The bounding sphere test passed, so we need to do a full
- // triangle picking test.
- insideBoundingSphere = true;
-
- // Keep track of the closest triangle we found so far,
- // so we can always return the closest one.
- float? closestIntersection = null;
-
- // Loop over the vertex data, 3 at a time (3 vertices = 1 triangle).
- Vector3[] vertices = cilinder.pvertices.ToArray();
-
-
- for (int i = 0; i < cilinder.indices.Count; i += 3)
- {
- // Perform a ray to triangle intersection test.
- float? intersection;
-
- RayIntersectsTriangle(ref ray,
- ref vertices[cilinder.indices[i]],
- ref vertices[cilinder.indices[i+1]],
- ref vertices[cilinder.indices[i+2]],
- out intersection);
-
- // Does the ray intersect this triangle?
- if (intersection != null)
- {
- // If so, is it closer than any other previous triangle?
- if ((closestIntersection == null) ||
- (intersection < closestIntersection))
- {
- // Store the distance to this triangle.
- closestIntersection = intersection;
-
- // Transform the three vertex positions into world space,
- // and store them into the output vertex parameters.
- Vector3.Transform(ref vertices[cilinder.indices[i]],
- ref modelTransform, out vertex1);
-
- Vector3.Transform(ref vertices[cilinder.indices[i+1]],
- ref modelTransform, out vertex2);
-
- Vector3.Transform(ref vertices[cilinder.indices[i+2]],
- ref modelTransform, out vertex3);
- }
- }
- }
-
- return closestIntersection;
- }
- }
-
-
- /// <summary>
- /// Checks whether a ray intersects a triangle. This uses the algorithm
- /// developed by Tomas Moller and Ben Trumbore, which was published in the
- /// Journal of Graphics Tools, volume 2, "Fast, Minimum Storage Ray-Triangle
- /// Intersection".
- ///
- /// This method is implemented using the pass-by-reference versions of the
- /// XNA math functions. Using these overloads is generally not recommended,
- /// because they make the code less readable than the normal pass-by-value
- /// versions. This method can be called very frequently in a tight inner loop,
- /// however, so in this particular case the performance benefits from passing
- /// everything by reference outweigh the loss of readability.
- /// </summary>
- static void RayIntersectsTriangle(ref Ray ray,
- ref Vector3 vertex1,
- ref Vector3 vertex2,
- ref Vector3 vertex3, out float? result)
- {
- // Compute vectors along two edges of the triangle.
- Vector3 edge1, edge2;
-
- Vector3.Subtract(ref vertex2, ref vertex1, out edge1);
- Vector3.Subtract(ref vertex3, ref vertex1, out edge2);
-
- // Compute the determinant.
- Vector3 directionCrossEdge2;
- Vector3.Cross(ref ray.Direction, ref edge2, out directionCrossEdge2);
-
- float determinant;
- Vector3.Dot(ref edge1, ref directionCrossEdge2, out determinant);
-
- // If the ray is parallel to the triangle plane, there is no collision.
- if (determinant > -float.Epsilon && determinant < float.Epsilon)
- {
- result = null;
- return;
- }
-
- float inverseDeterminant = 1.0f / determinant;
-
- // Calculate the U parameter of the intersection point.
- Vector3 distanceVector;
- Vector3.Subtract(ref ray.Position, ref vertex1, out distanceVector);
-
- float triangleU;
- Vector3.Dot(ref distanceVector, ref directionCrossEdge2, out triangleU);
- triangleU *= inverseDeterminant;
-
- // Make sure it is inside the triangle.
- if (triangleU < 0 || triangleU > 1)
- {
- result = null;
- return;
- }
-
- // Calculate the V parameter of the intersection point.
- Vector3 distanceCrossEdge1;
- Vector3.Cross(ref distanceVector, ref edge1, out distanceCrossEdge1);
-
- float triangleV;
- Vector3.Dot(ref ray.Direction, ref distanceCrossEdge1, out triangleV);
- triangleV *= inverseDeterminant;
-
- // Make sure it is inside the triangle.
- if (triangleV < 0 || triangleU + triangleV > 1)
- {
- result = null;
- return;
- }
-
- // Compute the distance along the ray to the triangle.
- float rayDistance;
- Vector3.Dot(ref edge2, ref distanceCrossEdge1, out rayDistance);
- rayDistance *= inverseDeterminant;
-
- // Is the triangle behind the ray origin?
- if (rayDistance < 0)
- {
- result = null;
- return;
- }
-
- result = rayDistance;
- }
-
- #endregion
-
-
- }
-
-
-
- }