public void RefractedColorWithRay()
        {
            var w = World.Default;
            var s = w.Objects[0];

            s.Material.Ambient = 1f;
            s.Material.Pattern = new TestPattern();
            var b = w.Objects[1];

            b.Material.Transparency = 1;
            b.Material.IOR          = 1.5f;
            var r  = new Ray(0, 0, .1f, 0, 1, 0);
            var xs = new List <Intersection>
            {
                new(-.9899f, s),
                new(-.4899f, b),
                new(.4899f, b),
                new(.9899f, s)
            };
            var hit   = xs[2];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);
            var c     = w.RefractedColor(ref comps, 5);

            Assert.That.VectorsAreEqual(c, new Color(0, .99888f, .04725f), 1e-3f);
        }
        public void ChapterVI()
        {
            const float wallZ     = 10f;
            const float wallSize  = 7f;
            const int   px        = 100;
            const float pxSize    = wallSize / px;
            const float half      = wallSize / 2f;
            var         canvas    = new Canvas(px, px);
            var         rayOrigin = Point(0f, 0f, -5f);
            var         shape     = new Sphere {
                Material = new PhongMaterial(new Color(1f, .2f, 1f))
            };
            var l = new PointLight(Point(-10f, 10f, -10f), Color.White);

            Parallel.For(0, px, y =>
            {
                var wY = half - pxSize * y;
                for (var x = 0; x < px; x++)
                {
                    var wx  = -half + pxSize * x;
                    var pos = Point(wx, wY, wallZ);
                    var ray = new Ray(rayOrigin, Vector4.Normalize(pos - rayOrigin));
                    var hit = shape.Hit(ref ray);
                    if (hit == null)
                    {
                        continue;
                    }
                    var comps    = IntersectionState.Prepare(ref hit, ref ray);
                    canvas[x, y] = shape.Material.Shade(l, ref comps, 0);
                }
            });
        }
        public void ShadeHitSchlick()
        {
            var w     = World.Default;
            var floor = new Plane(Translation(0, -1, 0))
            {
                Material = { Transparency = .5f, IOR = 1.5f, Reflectivity = .5f }
            };

            w.Objects.Add(floor);
            var s = new Sphere(Translation(0, -3.5f, -.5f))
            {
                Material =
                {
                    BaseColor = new Color(1, 0, 0),
                    Ambient   = .5f
                }
            };

            w.Objects.Add(s);
            var r     = new Ray(0, 0, -3, 0, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f);
            var xs    = new Intersection(MathF.Sqrt(2f), floor);
            var comps = IntersectionState.Prepare(ref xs, ref r);
            var color = w.ShadeHit(ref comps, 5);

            Assert.That.VectorsAreEqual(color, new Color(.93391f, .69643f, .69243f), 1e-4f);
        }
        public void SchlickN2GreaterN1()
        {
            var s     = Sphere.GlassSphere;
            var r     = new Ray(0, .99f, -2, 0, 0, 1);
            var xs    = new Intersection(1.8589f, s);
            var comps = IntersectionState.Prepare(ref xs, ref r);

            Assert.That.FloatsAreEqual(comps.Schlick(), .48873f);
        }
        public void PrecomputingReflectionVector()
        {
            var s     = new Plane();
            var r     = new Ray(0f, 1f, -1f, 0f, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f);
            var i     = new Intersection(MathF.Sqrt(2f), s);
            var comps = IntersectionState.Prepare(ref i, ref r);

            Assert.AreEqual(comps.Reflect, Direction(0f, MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f));
        }
        public void HitOccursOutside()
        {
            var r     = new Ray(0f, 0f, -5f, 0f, 0f, 1f);
            var s     = new Sphere();
            var i     = new Intersection(4f, s);
            var comps = IntersectionState.Prepare(ref i, ref r);

            Assert.IsFalse(comps.IsInside);
        }
        public void HitOffsetsPoint()
        {
            var r = new Ray(0f, 0f, -5f, 0f, 0f, 1f);
            var s = new Sphere(Translation(0f, 0f, 1f));
            var i = new Intersection(5f, s);
            var c = IntersectionState.Prepare(ref i, ref r);

            Assert.IsTrue(c.OverPoint.Z < -Constants.Epsilon / 2f);
            Assert.IsTrue(c.Point.Z > c.OverPoint.Z);
        }
        public void ShadingIntersection()
        {
            var w     = World.Default;
            var r     = new Ray(0f, 0f, -5f, 0f, 0f, 1f);
            var s     = w.Objects[0];
            var i     = new Intersection(4f, s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var c     = w.ShadeHit(ref comps);

            Assert.That.VectorsAreEqual(c, new Color(.38066f, .47583f, .2855f));
        }
        public void UnderPointIstBelowSurf()
        {
            var r = new Ray(0, 0, -5, 0, 0, 1);
            var s = Sphere.GlassSphere;

            s.Transform = Translation(0, 0, 1);
            var i     = new Intersection(5, s);
            var comps = IntersectionState.Prepare(ref i, ref r); //third argument is list of i

            Assert.IsTrue(comps.UnderPoint.Z > Constants.Epsilon / 2f);
            Assert.IsTrue(comps.Point.Z < comps.UnderPoint.Z);
        }
        public void HitOccursInside()
        {
            var r     = new Ray(0f, 0f, 0f, 0f, 0f, 1f);
            var s     = new Sphere();
            var i     = new Intersection(1f, s);
            var comps = IntersectionState.Prepare(ref i, ref r);

            Assert.IsTrue(comps.IsInside);
            Assert.That.VectorsAreEqual(comps.Point, Point(0f, 0f, 1f));
            Assert.That.VectorsAreEqual(comps.Eye, Direction(0f, 0f, -1f));
            Assert.That.VectorsAreEqual(comps.Normal, Direction(0f, 0f, -1f));
        }
        public void PrecomputingStateOfIntersection()
        {
            var r     = new Ray(0f, 0f, -5f, 0f, 0f, 1f);
            var s     = new Sphere();
            var i     = new Intersection(4f, s);
            var comps = IntersectionState.Prepare(ref i, ref r);

            Assert.AreEqual(comps.Distance, i.Distance);
            Assert.AreEqual(comps.Object, i.Object);
            Assert.That.VectorsAreEqual(comps.Point, Point(0f, 0f, -1f));
            Assert.That.VectorsAreEqual(comps.Eye, Direction(0f, 0f, -1f));
            Assert.That.VectorsAreEqual(comps.Normal, Direction(0f, 0f, -1f));
        }
        public void ShadingIntersectionInside()
        {
            var w = World.Default;
            var r = new Ray(0f, 0f, 0f, 0f, 0f, 1f);
            var s = w.Objects[1];

            w.Lights[0] = new PointLight(Point(0f, .25f, 0f), Color.White);
            var i     = new Intersection(.5f, s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var c     = w.ShadeHit(ref comps);

            Assert.That.VectorsAreEqual(c, new Color(.90498f, .90498f, .90498f));
        }
        public void ReflectedColorForNonReflectiveMaterial()
        {
            var w = World.Default;
            var r = new Ray(0f, 0f, 0f, 0f, 0f, 1f);
            var s = w.Objects[1];

            s.Material.Ambient = 1;
            var i     = new Intersection(1, s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var col   = w.ReflectedColor(ref comps);

            Assert.That.VectorsAreEqual(col, Color.Black);
        }
        public void SchlickTotalReflection()
        {
            var s  = Sphere.GlassSphere;
            var r  = new Ray(0, 0, MathF.Sqrt(2f) / 2f, 0, 1, 0);
            var xs = new List <Intersection>
            {
                new(-MathF.Sqrt(2f) / 2f, s),
                new(MathF.Sqrt(2f) / 2f, s)
            };
            var hit   = xs[1];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);

            Assert.AreEqual(comps.Schlick(), 1f);
        }
        public void SchlickPerpendicular()
        {
            var s  = Sphere.GlassSphere;
            var r  = new Ray(0, 0, 0, 0, 1, 0);
            var xs = new List <Intersection>
            {
                new(-1, s),
                new(1, s)
            };
            var hit   = xs[1];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);

            Assert.That.FloatsAreEqual(comps.Schlick(), .04f);
        }
        public void RefractedColorOpaque()
        {
            var w  = World.Default;
            var s  = w.Objects[0];
            var r  = new Ray(0, 0, -5, 0, 0, 1);
            var xs = new List <Intersection>
            {
                new(4, s),
                new(6, s)
            };
            var hit   = xs[0];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);

            Assert.AreEqual(w.RefractedColor(ref comps, 5), Color.Black);
        }
        public void LimitRecursion()
        {
            var w = World.Default;
            var s = new Plane(Translation(0, -1, 0))
            {
                Material = { Reflectivity = .5f }
            };

            w.Objects.Add(s);
            var r     = new Ray(0, 0, -3, 0, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f);
            var i     = new Intersection(MathF.Sqrt(2f), s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var col   = w.ReflectedColor(ref comps, 0);

            Assert.That.VectorsAreEqual(col, Color.Black);
        }
        public void ShadeHitWithReflective()
        {
            var w = World.Default;
            var s = new Plane(Translation(0f, -1f, 0f))
            {
                Material = { Reflectivity = .5f }
            };

            w.Objects.Add(s);
            var r     = new Ray(0, 0, -3, 0, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f);
            var i     = new Intersection(MathF.Sqrt(2f), s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var col   = w.ShadeHit(ref comps, 5);

            Assert.That.VectorsAreEqual(col, new Color(.87677f, .92436f, .82918f), 1e-3f);
        }
        public void ReflectedColorReflectiveMaterial()
        {
            var w = World.Default;
            var s = new Plane(Translation(0, -1, 0))
            {
                Material = { Reflectivity = .5f }
            };

            w.Objects.Add(s);
            var r     = new Ray(0, 0, -3, 0, -MathF.Sqrt(2f) / 2f, MathF.Sqrt(2f) / 2f);
            var i     = new Intersection(MathF.Sqrt(2f), s);
            var comps = IntersectionState.Prepare(ref i, ref r);
            var col   = w.ReflectedColor(ref comps, 1);

            Assert.That.VectorsAreEqual(col, new Color(.19032f, .2379f, .14274f), 1e-3f);
        }
        public void RefractedColorUnterTotalReflection()
        {
            var w = World.Default;
            var s = w.Objects[0];

            s.Material.Transparency = 1;
            s.Material.IOR          = 1.5f;
            var r  = new Ray(0, 0, MathF.Sqrt(2f) / 2f, 0, 1, 0);
            var xs = new List <Intersection>
            {
                new(-MathF.Sqrt(2f) / 2f, s),
                new(MathF.Sqrt(2f) / 2f, s)
            };
            var hit   = xs[1];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);

            Assert.AreEqual(w.RefractedColor(ref comps, 5), Color.Black);
        }
        public void RefractedColorLimit()
        {
            var w = World.Default;
            var s = w.Objects[0];

            s.Material.Transparency = 1;
            s.Material.IOR          = 1.5f;
            var r  = new Ray(0, 0, -5, 0, 0, 1);
            var xs = new List <Intersection>
            {
                new(4, s),
                new(6, s)
            };
            var hit   = xs[0];
            var comps = IntersectionState.Prepare(ref hit, ref r, xs);

            Assert.AreEqual(w.RefractedColor(ref comps, 0), Color.Black);
        }
        public void FindingN1AndN2()
        {
            var a = Sphere.GlassSphere;

            a.Transform = Scale(2f);

            var b = Sphere.GlassSphere;

            b.Transform    = Translation(0, 0, -.25f);
            b.Material.IOR = 2f;

            var c = Sphere.GlassSphere;

            c.Transform    = Translation(0, 0, .25f);
            c.Material.IOR = 2.5f;
            var r  = new Ray(0, 0, -4, 0, 0, 1);
            var xs = new List <Intersection>
            {
                new(2f, a),
                new(2.75f, b),
                new(3.25f, c),
                new(4.75f, b),
                new(5.25f, c),
                new(6, a)
            };
            var n1 = new[] { 1, 1.5f, 2, 2.5f, 2.5f, 1.5f };
            var n2 = new[] { 1.5f, 2, 2.5f, 2.5f, 1.5f, 1 };

            for (var i = 0; i <= 5; i++)
            {
                var hit   = xs[i];
                var comps = IntersectionState.Prepare(ref hit, ref r, xs);
                Assert.AreEqual(comps.N1, n1[i]);
                Assert.AreEqual(comps.N2, n2[i]);
            }
        }