コード例 #1
0
        /// <summary>
        /// Checks if the specified ray intersects the specified sphere.
        /// </summary>
        /// <param name="ray">
        /// The ray involved in the intersection test.
        /// </param>
        /// <param name="sphereCenter">
        /// The center of the sphere.
        /// </param>
        /// <param name="sphereRadius">
        /// The sphere's radius.
        /// </param>
        /// <param name="t">
        /// The offset along the ray at which the intersection happens. Whenever the function returns
        /// false, this will be set to 0.0f. When checking the intersection between a ray and a sphere,
        /// we can obtain 2 intersection points and thus 2 t values. The function will always return
        /// the smallest positive t value. If both t values are negative, it means the ray only intersects
        /// the sphere from behind and in that case the method will return false.
        /// </param>
        /// <returns>
        /// True if the ray intersects the sphere and false otherwise.
        /// </returns>
        public static bool IntersectsSphere(this Ray ray, Vector3 sphereCenter, float sphereRadius, out float t)
        {
            t = 0.0f;

            // Calculate the coefficients of the quadratic equation
            Vector3 sphereCenterToRayOrigin = ray.origin - sphereCenter;
            float   a = Vector3.SqrMagnitude(ray.direction);
            float   b = 2.0f * Vector3.Dot(ray.direction, sphereCenterToRayOrigin);
            float   c = Vector3.SqrMagnitude(sphereCenterToRayOrigin) - sphereRadius * sphereRadius;

            // If we have a solution to the equation, the ray most likely intersects the sphere.
            float t1, t2;

            if (Equation.SolveQuadratic(a, b, c, out t1, out t2))
            {
                // Make sure the ray doesn't intersect the sphere only from behind
                if (t1 < 0.0f && t2 < 0.0f)
                {
                    return(false);
                }

                // Make sure we are using the smallest positive t value
                if (t1 < 0.0f)
                {
                    float temp = t1;
                    t1 = t2;
                    t2 = temp;
                }
                t = t1;

                return(true);
            }

            // If we reach this point it means the ray does not intersect the sphere in any way
            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Checks if the specified ray intersects the specified cone.
        /// </summary>
        /// <param name="ray">
        /// The ray involved in the intersection test.
        /// </param>
        /// <param name="coneBaseRadius">
        /// The radius of the cone's base.
        /// </param>
        /// <param name="coneHeight">
        /// The cone's height.
        /// </param>
        /// <param name="coneTransformMatrix">
        /// This is a 4x4 matrix which describes the rotation, scale and position of the cone in 3D space.
        /// </param>
        /// <param name="t">
        /// The offset along the ray at which the intersection happens. Whenever the function returns
        /// false, this will be set to 0.0f. When checking the intersection between a ray and a cone,
        /// we can obtain 2 intersection points and thus 2 t values. The function will always return
        /// the smallest positive t value. If both t values are negative, it means the ray only intersects
        /// the cone from behind and in that case the method will return false.
        /// </param>
        /// <returns>
        /// True if the ray intersects the cone and false otherwise.
        /// </returns>
        public static bool IntersectsCone(this Ray ray, float coneBaseRadius, float coneHeight, Matrix4x4 coneTransformMatrix, out float t)
        {
            t = 0.0f;

            // Because of the way in which the cone equation works, we will need to work with a ray which exists
            // in the cone's local space. That will make sure that we are dealing with a cone which sits at the
            // origin of the coordinate system with its height axis extending along the global up vector.
            Ray coneSpaceRay = ray.InverseTransform(coneTransformMatrix);

            // We will first perform a preliminary check to see if the ray intersects the bottom cap of the cone.
            // This is necessary because the cone equation views the cone as infinite (i.e. no bottom cap), and
            // if we didn't perform this check, we would never be able to tell when the bottom cap was hit and we
            // would also get false positives when the ray intersects the 'imaginary' part of the cone.
            // Note: In order to calculate the cone's bottom cap plane, we need to know the plane normal and a
            //       point known to be on the plane. Remembering that we are currently working in cone local space,
            //       the bottom cap plane normal is pointing downwards along the Y axis and the point on the plane
            //       is the center of the bottom cap, which is the zero vector. This is the standard default pose
            //       for a cone object.
            float rayOffset;
            Plane bottomCapPlane = new Plane(-Vector3.up, Vector3.zero);

            if (bottomCapPlane.Raycast(coneSpaceRay, out rayOffset))
            {
                // If the ray intersects the plane of the bottom cap, we will calculate the intersection point
                // and if it lies inside the cone's bottom cap area, it means we have a valid intersection. We
                // store the t value and then return true.
                Vector3 intersectionPoint = coneSpaceRay.origin + coneSpaceRay.direction * rayOffset;
                if (intersectionPoint.magnitude <= coneBaseRadius)
                {
                    t = rayOffset;
                    return(true);
                }
            }

            // We need this for the calculation of the quadratic coefficients
            float ratioSquared = coneBaseRadius / coneHeight;

            ratioSquared *= ratioSquared;

            // Calculate the coefficients.
            // Note: The cone equation which was used is: (X^2 + Z^2) / ratioSquared = (Y - coneHeight)^2.
            //       Where X, Y and Z are the coordinates of the point along the ray: (Origin + Direction * t).xyz
            float a = coneSpaceRay.direction.x * coneSpaceRay.direction.x + coneSpaceRay.direction.z * coneSpaceRay.direction.z - ratioSquared * coneSpaceRay.direction.y * coneSpaceRay.direction.y;
            float b = 2.0f * (coneSpaceRay.origin.x * coneSpaceRay.direction.x + coneSpaceRay.origin.z * coneSpaceRay.direction.z - ratioSquared * coneSpaceRay.direction.y * (coneSpaceRay.origin.y - coneHeight));
            float c = coneSpaceRay.origin.x * coneSpaceRay.origin.x + coneSpaceRay.origin.z * coneSpaceRay.origin.z - ratioSquared * (coneSpaceRay.origin.y - coneHeight) * (coneSpaceRay.origin.y - coneHeight);

            // The intersection happnes only if the quadratic equation has solutions
            float t1, t2;

            if (Equation.SolveQuadratic(a, b, c, out t1, out t2))
            {
                // Make sure the ray does not intersect the cone only from behind
                if (t1 < 0.0f && t2 < 0.0f)
                {
                    return(false);
                }

                // Make sure we are using the smallest positive t value
                if (t1 < 0.0f)
                {
                    float temp = t1;
                    t1 = t2;
                    t2 = temp;
                }
                t = t1;

                // Make sure the intersection point does not sit below the cone's bottom cap or above the cone's cap
                Vector3 intersectionPoint = coneSpaceRay.origin + coneSpaceRay.direction * t;
                if (intersectionPoint.y < 0.0f || intersectionPoint.y > coneHeight)
                {
                    return(false);
                }

                // The intersection point is valid
                return(true);
            }

            // If we reached this point, it means the ray does not intersect the cone in any way
            return(false);
        }
コード例 #3
0
        /// <summary>
        /// Checks if the specified ray intersects the specified cylinder.
        /// </summary>
        /// <param name="ray">
        /// The ray involved in the intersection test.
        /// </param>
        /// <param name="cylinderAxisFirstPoint">
        /// The first point which makes up the cylinder axis.
        /// </param>
        /// <param name="cylinderAxisSecondPoint">
        /// The second point which makes up the cylinder axis.
        /// </param>
        /// <param name="cylinderRadius">
        /// The radius of the cylinder.
        /// </param>
        /// <param name="t">
        /// The offset along the ray at which the intersection happens. Whenever the function returns
        /// false, this will be set to 0.0f. When checking the intersection between a ray and a cylinder,
        /// we can obtain 2 intersection points and thus 2 t values. The function will always return
        /// the smallest positive t value. If both t values are negative, it means the ray only intersects
        /// the cylinder from behind and in that case the method will return false.
        /// </param>
        /// <returns>
        /// True if the ray intersects the cylinder and false otherwise.
        /// </returns>
        public static bool IntersectsCylinder(this Ray ray, Vector3 cylinderAxisFirstPoint, Vector3 cylinderAxisSecondPoint, float cylinderRadius, out float t)
        {
            t = 0;

            // We will need the length of the cylinder axis later. We also need to normalize the
            // cylinder axis in order to use it for the quadratic coefficients calculation.
            Vector3 cylinderAxis       = cylinderAxisSecondPoint - cylinderAxisFirstPoint;
            float   cylinderAxisLength = cylinderAxis.magnitude;

            cylinderAxis.Normalize();

            // We need these for the quadratic coefficients calculation
            Vector3 crossRayDirectionCylinderAxis = Vector3.Cross(ray.direction, cylinderAxis);
            Vector3 crossToOriginCylinderAxis     = Vector3.Cross((ray.origin - cylinderAxisFirstPoint), cylinderAxis);

            // Calculate the quadratic coefficients
            float a = crossRayDirectionCylinderAxis.sqrMagnitude;
            float b = 2.0f * Vector3.Dot(crossRayDirectionCylinderAxis, crossToOriginCylinderAxis);
            float c = crossToOriginCylinderAxis.sqrMagnitude - cylinderRadius * cylinderRadius;

            // If we have a solution to the equation, the ray most likely intersects the cylinder.
            float t1, t2;

            if (Equation.SolveQuadratic(a, b, c, out t1, out t2))
            {
                // Make sure the ray doesn't intersect the cylinder only from behind
                if (t1 < 0.0f && t2 < 0.0f)
                {
                    return(false);
                }

                // Make sure we are using the smallest positive t value
                if (t1 < 0.0f)
                {
                    float temp = t1;
                    t1 = t2;
                    t2 = temp;
                }
                t = t1;

                // Now make sure that the intersection point lies within the boundaries of the cylinder axis. That is,
                // make sure its projection on the cylinder axis lies between the first and second axis points. We will
                // do this by constructing a vector which goes from the cylinder axis first point to the intersection
                // point. We then project the resulting vector on the cylinder axis and analyze the result. If the result
                // is less than 0, it means the intersection point exists below the first cylinder axis point. If the
                // result is greater than the cylinder axis length, it means the intersection point exists above the
                // second cylinder axis point. In both of these cases, we will return false because it means the intersection
                // point is outside the cylinder axis range.
                Vector3 intersectionPoint = ray.origin + ray.direction * t;
                float   projection        = Vector3.Dot(cylinderAxis, (intersectionPoint - cylinderAxisFirstPoint));

                // Below the first cylinder axis point?
                if (projection < 0.0f)
                {
                    return(false);
                }

                // Above the second cylinder axis point?
                if (projection > cylinderAxisLength)
                {
                    return(false);
                }

                // The intersection point is valid, so we can return true
                return(true);
            }

            // If we reach this point, it means the ray does not intersect the cylinder in any way
            return(false);
        }