public static bool RaycastShArc(Ray ray, out float t, Vector3 arcOrigin, Vector3 arcStartPoint, Vector3 arcPlaneNormal, float degreesFromStart, ArcEpsilon epsilon = new ArcEpsilon())
        {
            t = 0.0f;

            degreesFromStart = ConvertToSh3DArcAngle(arcOrigin, arcStartPoint, arcPlaneNormal, degreesFromStart);
            Plane arcPlane = new Plane(arcPlaneNormal, arcOrigin);

            float rayEnter;

            if (arcPlane.Raycast(ray, out rayEnter) &&
                ShArcContains3DPoint(ray.GetPoint(rayEnter), false, arcOrigin,
                                     arcStartPoint, arcPlaneNormal, degreesFromStart, epsilon))
            {
                t = rayEnter;
                return(true);
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, arcPlaneNormal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OBB arcOBB = CalcSh3DArcOBB(arcOrigin, arcStartPoint, arcPlaneNormal, degreesFromStart, epsilon);
                    return(BoxMath.Raycast(ray, arcOBB.Center, arcOBB.Size, arcOBB.Rotation));
                }
            }

            return(false);
        }
Example #2
0
        public static bool Raycast(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon())
        {
            t = 0.0f;
            Vector3 quadNormal = Vector3.Normalize(Vector3.Cross(quadRight, quadUp));
            Plane   quadPlane  = new Plane(quadNormal, quadCenter);

            float rayEnter;

            if (quadPlane.Raycast(ray, out rayEnter) &&
                Contains3DPoint(ray.GetPoint(rayEnter), false, quadCenter, quadWidth, quadHeight, quadRight, quadUp, epsilon))
            {
                t = rayEnter;
                return(true);
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OBB quadOBB = Calc3DQuadOBB(quadCenter, new Vector2(quadWidth, quadHeight), Quaternion.LookRotation(quadNormal, quadUp), epsilon);
                    return(BoxMath.Raycast(ray, quadOBB.Center, quadOBB.Size, quadOBB.Rotation));
                }
            }

            return(false);
        }
        public static bool Raycast(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon())
        {
            t = 0.0f;

            float rayEnter;
            Plane trianglePlane = new Plane(p0, p1, p2);

            if (trianglePlane.Raycast(ray, out rayEnter) &&
                Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2, epsilon))
            {
                t = rayEnter;
                return(true);
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OBB obb = Calc3DTriangleOBB(p0, p1, p2, trianglePlane.normal, epsilon);
                    return(BoxMath.Raycast(ray, obb.Center, obb.Size, obb.Rotation));
                }
            }

            return(false);
        }
Example #4
0
        public static bool RaycastWire(Ray ray, out float t, Vector3 quadCenter, float quadWidth, float quadHeight, Vector3 quadRight, Vector3 quadUp, QuadEpsilon epsilon = new QuadEpsilon())
        {
            t = 0.0f;
            Vector3    quadNormal   = Vector3.Normalize(Vector3.Cross(quadRight, quadUp));
            Plane      quadPlane    = new Plane(quadNormal, quadCenter);
            Vector2    quadSize     = new Vector2(quadWidth, quadHeight);
            Quaternion quadRotation = Quaternion.LookRotation(quadNormal, quadUp);

            float rayEnter;

            if (quadPlane.Raycast(ray, out rayEnter))
            {
                Vector3 intersectPt  = ray.GetPoint(rayEnter);
                var     cornerPoints = Calc3DQuadCornerPoints(quadCenter, quadSize, quadRotation);

                float distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopLeft], cornerPoints[(int)QuadCorner.TopRight]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.TopRight], cornerPoints[(int)QuadCorner.BottomRight]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomRight], cornerPoints[(int)QuadCorner.BottomLeft]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distFromSegment = intersectPt.GetDistanceToSegment(cornerPoints[(int)QuadCorner.BottomLeft], cornerPoints[(int)QuadCorner.TopLeft]);
                if (distFromSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, quadPlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OBB quadOBB = Calc3DQuadOBB(quadCenter, quadSize, Quaternion.LookRotation(quadNormal, quadUp), epsilon);
                    return(BoxMath.Raycast(ray, quadOBB.Center, quadOBB.Size, quadOBB.Rotation));
                }
            }

            return(false);
        }
        public GameObjectRayHit RaycastSpriteObject(Ray ray, GameObject gameObject)
        {
            float t;
            OBB   worldOBB = ObjectBounds.CalcSpriteWorldOBB(gameObject);

            if (!worldOBB.IsValid)
            {
                return(null);
            }

            if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation))
            {
                return(new GameObjectRayHit(ray, gameObject, worldOBB.GetPointFaceNormal(ray.GetPoint(t)), t));
            }

            return(null);
        }
        public static bool RaycastWire(Ray ray, out float t, Vector3 p0, Vector3 p1, Vector3 p2, TriangleEpsilon epsilon = new TriangleEpsilon())
        {
            t = 0.0f;

            float rayEnter;
            Plane trianglePlane = new Plane(p0, p1, p2);

            if (trianglePlane.Raycast(ray, out rayEnter))
            {
                Vector3 intersectPt   = ray.GetPoint(rayEnter);
                float   distToSegment = intersectPt.GetDistanceToSegment(p0, p1);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distToSegment = intersectPt.GetDistanceToSegment(p1, p2);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }

                distToSegment = intersectPt.GetDistanceToSegment(p2, p0);
                if (distToSegment <= epsilon.WireEps)
                {
                    t = rayEnter;
                    return(true);
                }
            }

            if (epsilon.ExtrudeEps != 0.0f)
            {
                float dot = Vector3Ex.AbsDot(ray.direction, trianglePlane.normal);
                if (dot < ExtrudeEpsThreshold.Get)
                {
                    OBB obb = Calc3DTriangleOBB(p0, p1, p2, trianglePlane.normal, epsilon);
                    return(BoxMath.Raycast(ray, obb.Center, obb.Size, obb.Rotation));
                }
            }

            return(false);
        }
        public bool RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion, List <GameObjectRayHit> hits)
        {
            hits.Clear();
            if (!_objectTree.RaycastAll(ray, _nodeHitBuffer))
            {
                return(false);
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes  = GameObjectTypeHelper.AllCombined;
            boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(_nonMeshObjectSize);

            Vector3 camLook = RTFocusCamera.Get.Look;

            if (raycastPresicion == SceneRaycastPrecision.BestFit)
            {
                foreach (var nodeHit in _nodeHitBuffer)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    GameObjectType objectType = sceneObject.GetGameObjectType();
                    if (objectType == GameObjectType.Mesh)
                    {
                        GameObjectRayHit objectHit = RaycastMeshObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hits.Add(objectHit);
                        }
                    }
                    else
                    if (objectType == GameObjectType.Terrain)
                    {
                        TerrainCollider terrainCollider = sceneObject.GetComponent <TerrainCollider>();
                        if (terrainCollider != null)
                        {
                            RaycastHit hitInfo;
                            if (terrainCollider.Raycast(ray, out hitInfo, float.MaxValue))
                            {
                                hits.Add(new GameObjectRayHit(ray, hitInfo));
                            }
                        }
                    }
                    else
                    if (objectType == GameObjectType.Sprite)
                    {
                        GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hits.Add(objectHit);
                        }
                    }
                    else
                    {
                        OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig);
                        if (worldOBB.IsValid)
                        {
                            float t;
                            if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation))
                            {
                                var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook);
                                var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                                hits.Add(hit);
                            }
                        }
                    }
                }
            }
            else
            if (raycastPresicion == SceneRaycastPrecision.Box)
            {
                foreach (var nodeHit in _nodeHitBuffer)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    OBB worldOBB = ObjectBounds.CalcWorldOBB(sceneObject, boundsQConfig);
                    if (worldOBB.IsValid)
                    {
                        float t;
                        if (BoxMath.Raycast(ray, out t, worldOBB.Center, worldOBB.Size, worldOBB.Rotation))
                        {
                            var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOBB.Center, worldOBB.Size, worldOBB.Rotation, camLook);
                            var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                            hits.Add(hit);
                        }
                    }
                }
            }

            return(hits.Count != 0);
        }
        public static bool Raycast(Ray ray, out float t, Vector3 coneBaseCenter, float coneBaseRadius, float coneHeight, Quaternion coneRotation, ConeEpsilon epsilon = new ConeEpsilon())
        {
            t = 0.0f;
            Ray coneSpaceRay = ray.InverseTransform(Matrix4x4.TRS(coneBaseCenter, coneRotation, Vector3.one));

            float   xzAABBSize = coneBaseRadius * 2.0f;
            Vector3 aabbSize   = new Vector3(xzAABBSize, coneHeight + epsilon.VertEps * 2.0f, xzAABBSize);

            if (!BoxMath.Raycast(coneSpaceRay, Vector3.up * coneHeight * 0.5f, aabbSize, Quaternion.identity))
            {
                return(false);
            }

            // 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.
            float rayEnter;
            Plane bottomCapPlane = new Plane(-Vector3.up, Vector3.zero);

            if (bottomCapPlane.Raycast(coneSpaceRay, out rayEnter))
            {
                // 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 * rayEnter;
                if (intersectionPoint.magnitude <= coneBaseRadius)
                {
                    t = rayEnter;
                    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 (MathEx.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 < -epsilon.VertEps || intersectionPoint.y > coneHeight + epsilon.VertEps)
                {
                    t = 0.0f;
                    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);
        }
Example #9
0
        public static bool Raycast(Ray ray, out float t, Vector3 baseCenter, float baseWidth, float baseDepth, float height, Quaternion rotation)
        {
            t   = 0.0f;
            ray = ray.InverseTransform(Matrix4x4.TRS(baseCenter, rotation, Vector3.one));

            Vector3 aabbSize = new Vector3(baseWidth, height, baseDepth);

            if (!BoxMath.Raycast(ray, Vector3.up * height * 0.5f, aabbSize, Quaternion.identity))
            {
                return(false);
            }

            List <float> tValues = new List <float>(5);

            Plane basePlane = new Plane(Vector3.up, Vector3.zero);
            float rayEnter  = 0.0f;

            if (basePlane.Raycast(ray, out rayEnter) &&
                QuadMath.Contains3DPoint(ray.GetPoint(rayEnter), false, baseCenter, baseWidth, baseDepth, Vector3.right, Vector3.forward))
            {
                tValues.Add(rayEnter);
            }

            float   halfWidth     = 0.5f * baseWidth;
            float   halfDepth     = 0.5f * baseDepth;
            Vector3 tipPosition   = Vector3.up * height;
            Vector3 p0            = tipPosition;
            Vector3 p1            = Vector3.right * halfWidth - Vector3.forward * halfDepth;
            Vector3 p2            = p1 - Vector3.right * baseWidth;
            Plane   trianglePlane = new Plane(p0, p1, p2);

            if (trianglePlane.Raycast(ray, out rayEnter) &&
                TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2))
            {
                tValues.Add(rayEnter);
            }

            p0            = tipPosition;
            p1            = Vector3.right * halfWidth + Vector3.forward * halfDepth;
            p2            = p1 - Vector3.forward * baseDepth;
            trianglePlane = new Plane(p0, p1, p2);
            if (trianglePlane.Raycast(ray, out rayEnter) &&
                TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2))
            {
                tValues.Add(rayEnter);
            }

            p0            = tipPosition;
            p1            = -Vector3.right * halfWidth + Vector3.forward * halfDepth;
            p2            = p1 + Vector3.right * baseWidth;
            trianglePlane = new Plane(p0, p1, p2);
            if (trianglePlane.Raycast(ray, out rayEnter) &&
                TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2))
            {
                tValues.Add(rayEnter);
            }

            p0            = tipPosition;
            p1            = -Vector3.right * halfWidth - Vector3.forward * halfDepth;
            p2            = p1 + Vector3.forward * baseDepth;
            trianglePlane = new Plane(p0, p1, p2);
            if (trianglePlane.Raycast(ray, out rayEnter) &&
                TriangleMath.Contains3DPoint(ray.GetPoint(rayEnter), false, p0, p1, p2))
            {
                tValues.Add(rayEnter);
            }

            if (tValues.Count == 0)
            {
                return(false);
            }

            tValues.Sort(delegate(float t0, float t1) { return(t0.CompareTo(t1)); });
            t = tValues[0];

            return(true);
        }
Example #10
0
 public override bool Raycast(Ray ray, out float t)
 {
     return(BoxMath.Raycast(ray, out t, _center, _size, _rotation, _epsilon));
 }
Example #11
0
        public static bool RaycastTriangular(Ray ray, out float t, Vector3 baseCenter,
                                             float baseWidth, float baseDepth, float topWidth, float topDepth, float height, Quaternion prismRotation)
        {
            t = 0.0f;
            if (baseWidth == 0.0f || baseDepth == 0.0f ||
                topWidth == 0.0f || topDepth == 0.0f || height == 0.0f)
            {
                return(false);
            }

            baseWidth = Mathf.Abs(baseWidth);
            baseDepth = Mathf.Abs(baseDepth);
            topWidth  = Mathf.Abs(topWidth);
            topDepth  = Mathf.Abs(topDepth);

            ray = ray.InverseTransform(Matrix4x4.TRS(baseCenter, prismRotation, Vector3.one));

            // Since the raycast calculations can be quite expensive for a prism, we will
            // first check if the ray intersects its AABB to quickly return false if no
            // intersection is found. If the ray does not intersect the AABB it can not
            // possibly intersect the prism.
            Vector3 aabbSize = Vector3.Max(new Vector3(baseWidth, height, baseDepth), new Vector3(topWidth, height, topDepth));

            if (!BoxMath.Raycast(ray, Vector3.up * height * 0.5f, aabbSize, Quaternion.identity))
            {
                return(false);
            }

            List <Vector3> cornerPoints  = CalcTriangPrismCornerPoints(Vector3.zero, baseWidth, baseDepth, topWidth, topDepth, height, Quaternion.identity);
            Vector3        baseLeftPt    = cornerPoints[(int)TriangularPrismCorner.BaseLeft];
            Vector3        baseRightPt   = cornerPoints[(int)TriangularPrismCorner.BaseRight];
            Vector3        baseForwardPt = cornerPoints[(int)TriangularPrismCorner.BaseForward];

            Vector3 topLeftPt    = cornerPoints[(int)TriangularPrismCorner.TopLeft];
            Vector3 topRightPt   = cornerPoints[(int)TriangularPrismCorner.TopRight];
            Vector3 topForwardPt = cornerPoints[(int)TriangularPrismCorner.TopForward];

            List <float> tValues = new List <float>(5);

            // Base triangle
            float rayEnter;

            if (TriangleMath.Raycast(ray, out rayEnter, baseLeftPt, baseRightPt, baseForwardPt))
            {
                tValues.Add(rayEnter);
            }

            // Top triangle
            if (TriangleMath.Raycast(ray, out rayEnter, topLeftPt, topForwardPt, topRightPt))
            {
                tValues.Add(rayEnter);
            }

            // Back face
            List <Vector3> facePoints = new List <Vector3>(4)
            {
                baseLeftPt, topLeftPt, topRightPt, baseRightPt
            };
            Vector3 faceNormal = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized;

            if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal))
            {
                tValues.Add(rayEnter);
            }

            // Left face
            // facePoints[0] = baseLeftPt;
            facePoints[1] = baseForwardPt;
            facePoints[2] = topForwardPt;
            facePoints[3] = topLeftPt;
            faceNormal    = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized;
            if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal))
            {
                tValues.Add(rayEnter);
            }

            // Right face
            facePoints[0] = baseRightPt;
            facePoints[1] = topRightPt;
            // facePoints[2] = topForwardPt;
            facePoints[3] = baseForwardPt;
            faceNormal    = Vector3.Cross((facePoints[1] - facePoints[0]), facePoints[3] - facePoints[0]).normalized;
            if (PolygonMath.Raycast(ray, out rayEnter, facePoints, false, faceNormal))
            {
                tValues.Add(rayEnter);
            }

            if (tValues.Count == 0)
            {
                return(false);
            }

            tValues.Sort(delegate(float t0, float t1) { return(t0.CompareTo(t1)); });
            t = tValues[0];

            return(true);
        }