/// <summary>
        /// Performs a raycast and returns a list of hits for all objects whose oriented
        /// boxes are intersected by the specified ray.
        /// </summary>
        public List <GameObjectRayHit> RaycastAllBox(Ray ray)
        {
            // First, retrieve a list of the sphere tree nodes which were hit by the ray.
            // If no nodes were hit, it means no object was hit either.
            List <SphereTreeNodeRayHit <GameObject> > allNodeHits = _sphereTree.RaycastAll(ray);

            if (allNodeHits.Count == 0)
            {
                return(new List <GameObjectRayHit>());
            }

            // Loop through all nodes which were hit by the ray. For each node, we have to detect
            // if the ray hits the actual object box.
            var gameObjectHits = new List <GameObjectRayHit>();

            foreach (SphereTreeNodeRayHit <GameObject> nodeHit in allNodeHits)
            {
                // Retrieve the object which resides in the node
                GameObject gameObject = nodeHit.HitNode.Data;
                if (gameObject == null)
                {
                    continue;
                }
                if (!gameObject.activeInHierarchy)
                {
                    continue;
                }

                // If the ray intersects the object's box, add the hit to the list
                GameObjectRayHit gameObjectRayHit = null;
                if (gameObject.RaycastBox(ray, out gameObjectRayHit))
                {
                    gameObjectHits.Add(gameObjectRayHit);
                }
            }

            return(gameObjectHits);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Performs a ray cast against the mesh tree and returns an instance of the 'MeshRayHit'
        /// class which holds information about the ray hit. The method returns the hit which is
        /// closest to the ray origin. If no triangle was hit, the method returns null.
        /// </summary>
        public MeshRayHit Raycast(Ray ray, TransformMatrix meshTransformMatrix)
        {
            // If the tree was not yet build, we need to build it because we need
            // the triangle information in order to perform the raycast.
            if (!_wasBuilt)
            {
                Build();
            }

            // When the sphere tree is constructed it is constructed in the mesh local space (i.e. it takes
            // no position/rotation/scale into account). This is required because a mesh can be shared by
            // lots of different objects each with its own transform data. This is why we need the mes matrix
            // parameter. It allows us to transform the ray in the mesh local space and perform our tests there.
            Ray meshLocalSpaceRay = ray.InverseTransform(meshTransformMatrix.ToMatrix4x4x);

            // First collect all terminal nodes which are intersected by this ray. If no nodes
            // are intersected, we will return null.
            List <SphereTreeNodeRayHit <MeshSphereTreeTriangle> > nodeRayHits = _sphereTree.RaycastAll(meshLocalSpaceRay);

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

            // We now have to loop thorugh all intersected nodes and find the triangle whose
            // intersection point is closest to the ray origin.
            float      minT                   = float.MaxValue;
            Triangle3D closestTriangle        = null;
            int        indexOfClosestTriangle = -1;
            Vector3    closestHitPoint        = Vector3.zero;

            foreach (var nodeRayHit in nodeRayHits)
            {
                // Retrieve the data associated with the node and construct the mesh triangle instance
                MeshSphereTreeTriangle sphereTreeTriangle = nodeRayHit.HitNode.Data;
                Triangle3D             meshTriangle       = _octave3DMesh.GetTriangle(sphereTreeTriangle.TriangleIndex);

                // Check if the ray intersects the trianlge which resides in the node
                float hitEnter;
                if (meshTriangle.Raycast(meshLocalSpaceRay, out hitEnter))
                {
                    // The trianlge is intersected by the ray, but we also have to ensure that the
                    // intersection point is closer than what we have found so far. If it is, we
                    // store all relevant information.
                    if (hitEnter < minT)
                    {
                        minT                   = hitEnter;
                        closestTriangle        = meshTriangle;
                        indexOfClosestTriangle = sphereTreeTriangle.TriangleIndex;
                        closestHitPoint        = meshLocalSpaceRay.GetPoint(hitEnter);
                    }
                }
            }

            // If we found the closest triangle, we can construct the ray hit instance and return it.
            // Otherwise we return null. This can happen when the ray intersects the triangle node
            // spheres, but the triangles themselves.
            if (closestTriangle != null)
            {
                // We have worked in mesh local space up until this point, but we want to return the
                // hit info in world space, so we have to transform the hit data accordingly.
                closestHitPoint = meshTransformMatrix.MultiplyPoint(closestHitPoint);
                minT            = (ray.origin - closestHitPoint).magnitude;
                Vector3 worldNormal = meshTransformMatrix.MultiplyVector(closestTriangle.Normal);

                return(new MeshRayHit(ray, minT, _octave3DMesh, indexOfClosestTriangle, closestHitPoint, worldNormal, meshTransformMatrix));
            }
            else
            {
                return(null);
            }
        }