public override bool Scatter(Ray rIn, HitRecord rec, ref Vec3 attenuation, ref Ray scattered)
        {
            attenuation = new Vec3(1, 1, 1);
            double etaIOverEtaT = rec.FrontFace ? (1.0 / RefIdx) : RefIdx;

            Vec3   unitDirection = Vec3.UnitVector(rIn.Direction);
            double cosTheta      = Math.Min(Vec3.Dot(-unitDirection, rec.Normal), 1.0);
            double sinTheta      = Math.Sqrt(1.0 - cosTheta * cosTheta);

            if (etaIOverEtaT * sinTheta > 1.0)
            {
                Vec3 reflected = Vec3.Reflect(unitDirection, rec.Normal);
                scattered = new Ray(rec.P, reflected);
                return(true);
            }

            double reflectProb = RayTracerUtils.Schlick(cosTheta, etaIOverEtaT);

            if (RayTracerUtils.RandomDouble() < reflectProb)
            {
                Vec3 reflected = Vec3.Reflect(unitDirection, rec.Normal);
                scattered = new Ray(rec.P, reflected);
                return(true);
            }

            Vec3 refracted = Vec3.Refract(unitDirection, rec.Normal, etaIOverEtaT);

            scattered = new Ray(rec.P, refracted);
            return(true);
        }
Ejemplo n.º 2
0
        public static Vec3 RandomUnitVector()
        {
            double a = RayTracerUtils.RandomDouble(0, 2 * Math.PI);
            double z = RayTracerUtils.RandomDouble(-1, 1);
            double r = Math.Sqrt(1 - z * z);

            return(new Vec3(r * Math.Cos(a), r * Math.Sin(a), z));
        }
Ejemplo n.º 3
0
        public static Vec3 RandomInUnitDisk()
        {
            Vec3 p;

            do
            {
                p = new Vec3(RayTracerUtils.RandomDouble(-1, 1), RayTracerUtils.RandomDouble(-1, 1), 0);
            } while (p.LengthSquared >= 1);

            return(p);
        }
Ejemplo n.º 4
0
        public void WriteColor(StreamWriter writer, int samplesPerPixel)
        {
            double scale = 1.0 / samplesPerPixel;

            double r  = Math.Sqrt(scale * e[0]);
            double g  = Math.Sqrt(scale * e[1]);
            double b  = Math.Sqrt(scale * e[2]);
            int    ri = (int)(256 * RayTracerUtils.Clamp(r, 0.0, 0.999));
            int    gi = (int)(256 * RayTracerUtils.Clamp(g, 0.0, 0.999));
            int    bi = (int)(256 * RayTracerUtils.Clamp(b, 0.0, 0.999));

            writer.WriteLine($"{ri} {gi} {bi}");
        }
        private HittableList RandomScene()
        {
            HittableList world = new HittableList();

            world.Objects.Add(new Sphere(new Vec3(0, -1000, 0), 1000, new Lambertian(new Vec3(0.5, 0.5, 0.5))));

            int  i = 1;
            Vec3 differenceCenter = new Vec3(4, 0.2, 0);

            for (int a = -11; a < 11; a++)
            {
                for (int b = -11; b < 11; b++)
                {
                    double chooseMat = RayTracerUtils.RandomDouble();
                    Vec3   center    = new Vec3(a + 0.9 * RayTracerUtils.RandomDouble(), 0.2, b + 0.9 * RayTracerUtils.RandomDouble());
                    if ((center - differenceCenter).Length > 0.9)
                    {
                        if (chooseMat < 0.8)
                        {
                            //diffuse
                            Vec3 albedo = Vec3.Random() * Vec3.Random();
                            world.Objects.Add(new Sphere(center, 0.2, new Lambertian(albedo)));
                        }
                        else if (chooseMat < 0.95)
                        {
                            //metal
                            Vec3   albedo = Vec3.Random(0.5, 1);
                            double fuzz   = RayTracerUtils.RandomDouble(0, 0.5);
                            world.Objects.Add(new Sphere(center, 0.2, new Metal(albedo, fuzz)));
                        }
                        else
                        {
                            //glass
                            world.Objects.Add(new Sphere(center, 0.2, new Dielectric(1.5)));
                        }
                    }
                }
            }

            world.Objects.Add(new Sphere(new Vec3(0, 1, 0), 1.0, new Dielectric(1.5)));

            world.Objects.Add(new Sphere(new Vec3(-4, 1, 0), 1.0, new Lambertian(new Vec3(0.4, 0.2, 0.1))));

            world.Objects.Add(new Sphere(new Vec3(4, 1, 0), 1.0, new Metal(new Vec3(0.7, 0.6, 0.5), 0.0)));

            return(world);
        }
        /// <param name="vFov">Top to bottom, in degrees</param>
        public Camera(Vec3 lookFrom, Vec3 lookAt, Vec3 vUp, double vFov, double aspect, double aperture, double focusDistance)
        {
            Origin     = lookFrom;
            LensRadius = aperture / 2;

            double theta      = RayTracerUtils.DegreesToRadians(vFov);
            double halfHeight = Math.Tan(theta / 2);
            double halfWidth  = aspect * halfHeight;

            W = Vec3.UnitVector(lookFrom - lookAt);
            U = Vec3.UnitVector(Vec3.Cross(vUp, W));
            V = Vec3.Cross(W, U);

            LowerLeftCorner = Origin - halfWidth * focusDistance * U - halfHeight * focusDistance * V - focusDistance * W;
            Horizontal      = 2 * halfWidth * focusDistance * U;
            Vertical        = 2 * halfHeight * focusDistance * V;
        }
        public void Output(string path)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();
            using (StreamWriter writer = new StreamWriter(path))
            {
                writer.WriteLine("P3");
                writer.WriteLine(IMAGE_WIDTH + " " + IMAGE_HEIGHT);
                writer.WriteLine("255");

                double aspectRatio     = IMAGE_WIDTH / IMAGE_HEIGHT;
                Vec3   lookFrom        = new Vec3(13, 2, 3);
                Vec3   lookAt          = new Vec3(0, 0, 0);
                Vec3   vUp             = new Vec3(0, 1, 0);
                double distanceToFocus = 10.0;
                double aperture        = 0.1;

                Camera cam = new Camera(lookFrom, lookAt, vUp, 20, aspectRatio, aperture, distanceToFocus);

                HittableList world = RandomScene();
                Vec3[,] colors = new Vec3[IMAGE_HEIGHT, IMAGE_WIDTH];

                int linesRemaining = IMAGE_HEIGHT;

                Parallel.For(0, IMAGE_HEIGHT, j =>
                {
                    // We handle each pixel of the line on a different thread to speed up the process
                    Parallel.For(0, IMAGE_WIDTH, i =>
                    {
                        Vec3 color = new Vec3();
                        for (int s = 0; s < SAMPLES_PER_PIXEL; ++s)
                        {
                            double u = (i + RayTracerUtils.RandomDouble()) / IMAGE_WIDTH;
                            double v = (j + RayTracerUtils.RandomDouble()) / IMAGE_HEIGHT;
                            Ray r    = cam.GetRay(u, v);
                            color   += RayColor(r, world, MAX_DEPTH);
                        }

                        lock (colors)
                        {
                            colors[j, i] = color;
                        }
                    });

                    double percentage = 100.0 - (double)--linesRemaining / IMAGE_HEIGHT * 100.0;
                    Progress(this, new ProgressArgs(percentage));
                });

                // Output the colors in the file
                for (int j = IMAGE_HEIGHT - 1; j >= 0; --j)
                {
                    for (int i = 0; i < IMAGE_WIDTH; ++i)
                    {
                        colors[j, i].WriteColor(writer, SAMPLES_PER_PIXEL);
                    }
                }
            }

            sw.Stop();

            Console.WriteLine();
            Console.WriteLine($"Time: {sw.Elapsed.Minutes}:{sw.Elapsed.Seconds:00}");
        }
Ejemplo n.º 8
0
 public static Vec3 Random(double min, double max)
 {
     return(new Vec3(RayTracerUtils.RandomDouble(min, max), RayTracerUtils.RandomDouble(min, max), RayTracerUtils.RandomDouble(min, max)));
 }
Ejemplo n.º 9
0
 public static Vec3 Random()
 {
     return(new Vec3(RayTracerUtils.RandomDouble(), RayTracerUtils.RandomDouble(), RayTracerUtils.RandomDouble()));
 }