protected override Intersections IntersectsInt(Ray r)
        {
            var dir_cross_e2 = Tuple.Cross(r.Direction, E2);
            var det          = Tuple.Dot(E1, dir_cross_e2);

            if (Math.Abs(det) < EPSILON)
            {
                return(Intersections.EMPTY);
            }

            var f            = 1.0 / det;
            var p1_to_origin = r.Origin - P1;
            var u            = f * Tuple.Dot(p1_to_origin, dir_cross_e2);

            if (u < 0 || u > 1)
            {
                return(Intersections.EMPTY);
            }

            var origin_cross_e1 = Tuple.Cross(p1_to_origin, E1);
            var v = f * Tuple.Dot(r.Direction, origin_cross_e1);

            if (v < 0 || (u + v) > 1)
            {
                return(Intersections.EMPTY);
            }

            var t = f * Tuple.Dot(E2, origin_cross_e1);

            return(new Intersections(
                       new Intersection(t, this, u, v)));
        }
        public double Schlick()
        {
            var cos = Tuple.Dot(EyeV, NormalV);

            if (N1 > N2)
            {
                var n     = N1 / N2;
                var sin2T = (n * n) * (1 - (cos * cos));
                if (sin2T > 1)
                {
                    return(1);
                }
                var cos_t = Math.Sqrt(1 - sin2T);
                cos = cos_t;
            }
            var r0 = Math.Pow((N1 - N2) / (N1 + N2), 2);

            return(r0 + (1 - r0) * Math.Pow(1 - cos, 5));
        }
        public static Color Lighting(Material mat, Shape shape, PointLight light,
                                     Point pt, Tuple eye, Tuple normal, bool inShadow)
        {
            Color diffuse  = new Color(0, 0, 0);
            Color specular = new Color(0, 0, 0);

            Color color;

            if (mat.Pattern != null)
            {
                color = mat.Pattern.PatternAtObject(shape, pt);
            }
            else
            {
                color = mat.Color;
            }

            var effectiveColor = color * light.Intensity;
            var lightv         = (light.Position - pt).Normalize();
            var ambient        = effectiveColor * mat.Ambient;

            if (inShadow)
            {
                return(ambient);
            }
            var lightDotNormal = Tuple.Dot(lightv, normal);

            if (lightDotNormal >= 0)
            {
                diffuse = effectiveColor * mat.Diffuse * lightDotNormal;
                var reflectv      = (-lightv).ReflectOn(normal);
                var reflectDotEye = Tuple.Dot(reflectv, eye);

                if (reflectDotEye > 0)
                {
                    var factor = Math.Pow(reflectDotEye, mat.Shininess);
                    specular = light.Intensity * mat.Specular * factor;
                }
            }
            return(ambient + diffuse + specular);
        }
        protected override Intersections IntersectsInt(Ray ray)
        {
            var sphereToRay = ray.Origin - new Point(0, 0, 0);
            var a           = Tuple.Dot(ray.Direction, ray.Direction);
            var b           = 2 * Tuple.Dot(ray.Direction, sphereToRay);
            var c           = Tuple.Dot(sphereToRay, sphereToRay) - 1;

            var discriminant = (b * b) - 4 * a * c;

            if (discriminant < 0)
            {
                return(new Intersections());
            }

            double t1 = (-b - Math.Sqrt(discriminant)) / (2 * a);
            double t2 = (-b + Math.Sqrt(discriminant)) / (2 * a);

            var i1 = new Intersection(t1, this);
            var i2 = new Intersection(t2, this);

            return(new Intersections(new List <Intersection> {
                i1, i2
            }));
        }
        public Computation PrepareComputations(Ray ray, Intersections xs)
        {
            var comps = new Computation();

            comps.T     = T;
            comps.Shape = Shape;

            comps.Point = ray.Position(T);
            comps.EyeV  = -ray.Direction;

            comps.NormalV  = Shape.NormalAt(comps.Point, this);
            comps.ReflectV = ray.Direction.ReflectOn(comps.NormalV);

            if (Tuple.Dot(comps.NormalV, comps.EyeV) < 0)
            {
                comps.Inside  = true;
                comps.NormalV = -comps.NormalV;
            }
            comps.OverPoint  = (comps.Point + comps.NormalV * EPSILON).ToPoint();
            comps.UnderPoint = (comps.Point - comps.NormalV * EPSILON).ToPoint();

            List <Shape> containers = new List <Shape>();

            foreach (var i in xs)
            {
                if (i == this)
                {
                    if (containers.Count == 0)
                    {
                        comps.N1 = 1.0;
                    }
                    else
                    {
                        comps.N1 = containers.Last().Material.RefractiveIndex;
                    }
                }

                if (containers.Contains(i.Shape))
                {
                    containers.Remove(i.Shape);
                }
                else
                {
                    containers.Add(i.Shape);
                }

                if (i == this)
                {
                    if (containers.Count == 0)
                    {
                        comps.N2 = 1.0;
                    }
                    else
                    {
                        comps.N2 = containers.Last().Material.RefractiveIndex;
                    }
                    break;
                }
            }

            return(comps);
        }