//// ===========================================================================================================
        //// Methods
        //// ===========================================================================================================

        public static IntersectionState Create(Intersection hit, Ray ray, IntersectionList intersections)
        {
            // Copy the intersection's properties for convenience.
            double t     = hit.T;
            Shape  shape = hit.Shape;

            // Precompute some useful values.
            Point  point    = ray.PositionAt(hit.T);
            Vector eye      = -ray.Direction;
            Vector normal   = shape.NormalAt(point, hit);
            bool   isInside = false;

            if (normal.Dot(eye) < 0)
            {
                isInside = true;
                normal   = -normal;
            }

            Point overPoint  = point + (normal * NumberExtensions.Epsilon);
            Point underPoint = point - (normal * NumberExtensions.Epsilon);

            Vector reflection = ray.Direction.Reflect(normal);

            // Calculate the refraction values.
            var    containers = new List <Shape>();
            double n1         = 1.0;
            double n2         = 1.0;

            foreach (Intersection intersection in intersections)
            {
                if (intersection == hit)
                {
                    n1 = containers.Count == 0 ? 1.0 : containers[^ 1].Material.RefractiveIndex;
Example #2
0
        public bool IsShadowed(Point point, Light light)
        {
            Vector pointToLightVector = light.Position - point;
            double distance           = pointToLightVector.Magnitude;
            Vector direction          = pointToLightVector.Normalize();

            var ray = new Ray(point, direction);
            IntersectionList intersections = Intersect(ray);
            Intersection?    hit           = intersections.Hit;

            return(hit != null && hit.T < distance && !hit.Shape.IsShadowHidden);
        }
Example #3
0
        /// <summary>
        /// Iterates over all of the shapes in the world and returns all of the hits for the specified ray.
        /// </summary>
        /// <param name="ray">The ray to use for hit testing.</param>
        /// <returns>The list of all intersections for the specified ray.</returns>
        public IntersectionList Intersect(Ray ray)
        {
            var hits = new IntersectionList();

            foreach (Shape shape in Shapes)
            {
                IntersectionList shapeHits = shape.Intersect(ray);
                hits.AddRange(shapeHits);
            }

            return(hits);
        }
Example #4
0
        /// <summary>
        /// Finds the color of the first shape that is hit for the given ray.
        /// </summary>
        /// <param name="ray">The ray to use for hit testing.</param>
        /// <param name="maxRecursion">The maximum number of additional rays to use for reflection.</param>
        /// <returns>
        /// The color for the part of the shape that the ray hits, or <see cref="Colors.Black"/> if no shape is hit.
        /// </returns>
        public Color ColorAt(Ray ray, int maxRecursion = MaxRecursion)
        {
            IntersectionList intersections = Intersect(ray);
            Intersection?    hit           = intersections.Hit;

            if (hit == null)
            {
                return(Colors.Black);
            }

            var   state = IntersectionState.Create(hit, ray, intersections);
            Color color = ShadeHit(state, maxRecursion);

            return(color);
        }