Пример #1
0
        /// <summary>
        /// Performs a raycast against the mesh triangles and returns info
        /// about the closest hit or null if no triangle was hit by the ray.
        /// </summary>
        /// <param name="meshTransform">
        /// The mesh transform which brings the mesh in the same space as the
        /// ray.
        /// </param>
        /// <remarks>
        /// This method will build the tree if it hasn't already been built.
        /// </remarks>
        public MeshRayHit RaycastClosest(Ray ray, Matrix4x4 meshTransform)
        {
            // Build the tree if it hasn't already been built
            if (!_isBuilt)
            {
                Build();
            }

            // Work in mesh local space by transforming the ray by the inverse of
            // the mesh transform. It is faster to perform this transformation here
            // instead of transforming every possibly hit triangle by 'meshTransform'.
            Ray modelSpaceRay = ray.InverseTransform(meshTransform);

            // Get the list of tree nodes which are hit by the ray
            List <SphereTreeNodeRayHit <MeshTriangle> > nodeHits = _tree.RaycastAll(modelSpaceRay);

            if (nodeHits.Count == 0)
            {
                return(null);
            }

            // Store data in preparation for closest hit identification
            float        t;
            float        minT            = float.MaxValue;
            MeshTriangle closestTriangle = null;
            bool         foundTriangle   = false;

            // Loop through each node hit
            foreach (SphereTreeNodeRayHit <MeshTriangle> nodeHit in nodeHits)
            {
                // Get the associated mesh triangle and check if the ray intersects it
                MeshTriangle meshTriangle = nodeHit.HitNode.Data;
                if (TriangleMath.Raycast(modelSpaceRay, out t, meshTriangle.Vertex0, meshTriangle.Vertex1, meshTriangle.Vertex2))
                {
                    if (Vector3.Dot(modelSpaceRay.direction, meshTriangle.Normal) < 0.0f)
                    {
                        // If the intersection offset is smaller than what we have so far,
                        // it means we have a new closest hit.
                        if (t < minT)
                        {
                            minT            = t;
                            closestTriangle = meshTriangle;
                            foundTriangle   = true;
                        }
                    }
                }
            }

            // If we found a triangle, we can return the mesh ray hit information
            if (foundTriangle)
            {
                // Convert the t value in world space. Do the same for the normal.
                Vector3 worldHit = meshTransform.MultiplyPoint(modelSpaceRay.GetPoint(minT));
                minT = (ray.origin - worldHit).magnitude / ray.direction.magnitude;
                Vector3 transformedNormal = meshTransform.inverse.transpose.MultiplyVector(closestTriangle.Normal).normalized;

                // Return the hit instance
                return(new MeshRayHit(ray, closestTriangle.TriangleIndex, minT, transformedNormal));
            }

            return(null);
        }