Esempio n. 1
0
        public override IEnumerable IntersectionIterator(Ray ray)
        {
            double radiusSquared = radius * radius;

            Vector2 rayOrigin = new Vector2(ray.origin);
            Vector2 rayDirectionXY = new Vector2(ray.direction);
            Vector2 rayDirection = rayDirectionXY.GetNormal();
            Vector2 thisPosition = Vector2.Zero;
            Vector2 deltaFromShpereCenterToRayOrigin = rayOrigin - thisPosition;
            double distanceFromCircleCenterToRayOrigin = Vector2.Dot(deltaFromShpereCenterToRayOrigin, rayDirection);
            double lengthFromRayOrginToCircleCenterSquared = Vector2.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin);
            double lengthFromRayOrigintoNearEdgeOfCircleSquared = lengthFromRayOrginToCircleCenterSquared - radiusSquared;
            double distanceFromCircleCenterToRaySquared = distanceFromCircleCenterToRayOrigin * distanceFromCircleCenterToRayOrigin;
            double amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromCircleCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfCircleSquared;

            if (amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0)
            {
                double distanceFromRayOriginToCircleCenter = -distanceFromCircleCenterToRayOrigin;
                double amountCircleCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared);
                double scaleRatio = ray.direction.Length / rayDirectionXY.Length;

                if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace)
                {
                    IntersectInfo info = new IntersectInfo();
                    info.hitType = IntersectionType.FrontFace;
                    info.closestHitObject = this;
                    double distanceToFrontHit = (distanceFromRayOriginToCircleCenter - amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio;
                    info.distanceToHit = distanceToFrontHit;
                    info.hitPosition = ray.origin + ray.direction * info.distanceToHit;
                    if (info.hitPosition.z > -height / 2 && info.hitPosition.z < height / 2)
                    {
                        info.normalAtHit = new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal();
                        yield return info;
                    }
                }


                if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace)
                {
                    IntersectInfo info = new IntersectInfo();
                    info.hitType = IntersectionType.BackFace;
                    info.closestHitObject = this;
                    double distanceToBackHit = (distanceFromRayOriginToCircleCenter + amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio;
                    info.distanceToHit = distanceToBackHit;
                    info.hitPosition = ray.origin + ray.direction * info.distanceToHit;
                    if (info.hitPosition.z > -height / 2 && info.hitPosition.z < height / 2)
                    {
                        info.normalAtHit = -(new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal());
                        yield return info;
                    }
                }

                {
                    bool inFrontOfTopFace;
                    double testDistanceToHit = topPlane.GetDistanceToIntersection(ray, out inFrontOfTopFace);
                    Vector3 topHitPosition = ray.origin + ray.direction * testDistanceToHit;

                    if (topHitPosition.x * topHitPosition.x + topHitPosition.y * topHitPosition.y < topRadius * topRadius)
                    {
                        if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfTopFace)
                        {
                            IntersectInfo topHitInfo = new IntersectInfo();
                            topHitInfo.hitPosition = topHitPosition;
                            topHitInfo.closestHitObject = this;
                            topHitInfo.hitType = IntersectionType.FrontFace;
                            topHitInfo.normalAtHit = topPlane.planeNormal;
                            topHitInfo.distanceToHit = testDistanceToHit;

                            yield return topHitInfo;
                        }

                        if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfTopFace)
                        {
                            IntersectInfo topHitInfo = new IntersectInfo();
                            topHitInfo.hitPosition = topHitPosition;
                            topHitInfo.closestHitObject = this;
                            topHitInfo.hitType = IntersectionType.BackFace;
                            topHitInfo.normalAtHit = -topPlane.planeNormal;
                            topHitInfo.distanceToHit = testDistanceToHit;

                            yield return topHitInfo;
                        }
                    }
                }

                {
                    bool inFrontOfBottomFace;
                    double testDistanceToHit = bottomPlane.GetDistanceToIntersection(ray, out inFrontOfBottomFace);
                    Vector3 bottomHitPosition = ray.origin + ray.direction * testDistanceToHit;

                    if (bottomHitPosition.x * bottomHitPosition.x + bottomHitPosition.y * bottomHitPosition.y < radius * radius)
                    {
                        if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfBottomFace)
                        {
                            IntersectInfo bottomHitInfo = new IntersectInfo();
                            bottomHitInfo.hitPosition = bottomHitPosition;
                            bottomHitInfo.closestHitObject = this;
                            bottomHitInfo.hitType = IntersectionType.FrontFace;
                            bottomHitInfo.normalAtHit = bottomPlane.planeNormal;
                            bottomHitInfo.distanceToHit = testDistanceToHit;

                            yield return bottomHitInfo;
                        }

                        if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfBottomFace)
                        {
                            IntersectInfo bottomHitInfo = new IntersectInfo();
                            bottomHitInfo.hitPosition = bottomHitPosition;
                            bottomHitInfo.closestHitObject = this;
                            bottomHitInfo.hitType = IntersectionType.BackFace;
                            bottomHitInfo.normalAtHit = -bottomPlane.planeNormal;
                            bottomHitInfo.distanceToHit = testDistanceToHit;

                            yield return bottomHitInfo;
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        public override IntersectInfo GetClosestIntersection(Ray ray)
        {
            double radiusSquared = radius * radius;

            Vector2 rayOrigin = new Vector2(ray.origin);
            Vector2 rayDirectionXY = new Vector2(ray.direction);
            Vector2 rayDirection = rayDirectionXY.GetNormal();
            Vector2 thisPosition = Vector2.Zero;
            Vector2 deltaFromShpereCenterToRayOrigin = rayOrigin - thisPosition;
            double distanceFromCircleCenterToRayOrigin = Vector2.Dot(deltaFromShpereCenterToRayOrigin, rayDirection); // negative means the Circle is in front of the ray.
            double lengthFromRayOrginToCircleCenterSquared = Vector2.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin);
            double lengthFromRayOrigintoNearEdgeOfCircleSquared = lengthFromRayOrginToCircleCenterSquared - radiusSquared;
            double distanceFromCircleCenterToRaySquared = distanceFromCircleCenterToRayOrigin * distanceFromCircleCenterToRayOrigin;
            double amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromCircleCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfCircleSquared;

            if (amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0)
            {
                {
                    bool inFrontOfTop;
                    double testDistanceToHit = topPlane.GetDistanceToIntersection(ray, out inFrontOfTop);
                    bool wantFrontAndInFront = (ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfTop;
                    bool wantBackAndInBack = (ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfTop;
                    if (wantFrontAndInFront || wantBackAndInBack)
                    {
                        Vector3 topHitPosition = ray.origin + ray.direction * testDistanceToHit;

                        if (topHitPosition.x * topHitPosition.x + topHitPosition.y * topHitPosition.y < topRadius * topRadius)
                        {
                            IntersectInfo topHitInfo = new IntersectInfo();
                            topHitInfo.hitPosition = topHitPosition;
                            topHitInfo.closestHitObject = this;
                            if (ray.intersectionType == IntersectionType.FrontFace)
                            {
                                topHitInfo.hitType = IntersectionType.FrontFace;
                                topHitInfo.normalAtHit = topPlane.planeNormal;
                            }
                            else
                            {
                                topHitInfo.hitType = IntersectionType.BackFace;
                                topHitInfo.normalAtHit = -topPlane.planeNormal;
                            }
                            topHitInfo.distanceToHit = testDistanceToHit;

                            return topHitInfo;
                        }
                    }
                }

                {
                    bool inFrontOfBottom;
                    double testDistanceToHit = bottomPlane.GetDistanceToIntersection(ray, out inFrontOfBottom);
                    if (ray.intersectionType == IntersectionType.FrontFace && inFrontOfBottom
                        || ray.intersectionType == IntersectionType.BackFace && !inFrontOfBottom)
                    {
                        Vector3 bottomHitPosition = ray.origin + ray.direction * testDistanceToHit;

                        if (bottomHitPosition.x * bottomHitPosition.x + bottomHitPosition.y * bottomHitPosition.y < radius * radius)
                        {
                            IntersectInfo bottomHitInfo = new IntersectInfo();
                            bottomHitInfo.hitPosition = bottomHitPosition;
                            bottomHitInfo.closestHitObject = this;
                            if (ray.intersectionType == IntersectionType.FrontFace)
                            {
                                bottomHitInfo.hitType = IntersectionType.FrontFace;
                                bottomHitInfo.normalAtHit = bottomPlane.planeNormal;
                            }
                            else
                            {
                                bottomHitInfo.hitType = IntersectionType.BackFace;
                                bottomHitInfo.normalAtHit = -bottomPlane.planeNormal;
                            }
                            bottomHitInfo.distanceToHit = testDistanceToHit;

                            return bottomHitInfo;
                        }
                    }
                }

                IntersectInfo info = new IntersectInfo();
                info.closestHitObject = this;
                info.hitType = IntersectionType.FrontFace;
                if (ray.isShadowRay)
                {
                    return info;
                }
                double distanceFromRayOriginToCircleCenter = -distanceFromCircleCenterToRayOrigin;

                double amountCircleCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared);

                double scaleRatio = ray.direction.Length / rayDirectionXY.Length;

                if (ray.intersectionType == IntersectionType.FrontFace)
                {
                    double distanceToFrontHit = (distanceFromRayOriginToCircleCenter - amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio;
                    if (distanceToFrontHit > ray.maxDistanceToConsider || distanceToFrontHit < ray.minDistanceToConsider)
                    {
                        return null;
                    }
                    info.distanceToHit = distanceToFrontHit;
                    info.hitPosition = ray.origin + ray.direction * info.distanceToHit;
                    if (info.hitPosition.z < -height / 2 || info.hitPosition.z > height / 2)
                    {
                        return null;
                    }
                    info.normalAtHit = new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal();
                }
                else if (ray.intersectionType == IntersectionType.BackFace)// check back faces
                {
                    double distanceToBackHit = (distanceFromRayOriginToCircleCenter + amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio;
                    if (distanceToBackHit > ray.maxDistanceToConsider || distanceToBackHit < ray.minDistanceToConsider)
                    {
                        return null;
                    }
                    info.hitType = IntersectionType.BackFace;
                    info.distanceToHit = distanceToBackHit;
                    info.hitPosition = ray.origin + ray.direction * info.distanceToHit;
                    if (info.hitPosition.z < height / 2 || info.hitPosition.z > height / 2)
                    {
                        return null;
                    }
                    info.normalAtHit = -(new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal());
                }

                return info;
            }

            return null;
        }