예제 #1
0
        // shader
        private static Vector Shade(Ray ray, int n)
        {
            var record = new HitRecord();

            if (World.Hit(ray, 0.01f, float.MaxValue, ref record))
            {
                var scattered   = new Ray();
                var attenuation = new Vector();
                if (n > 0 && record.Material.Scatter(ray, record, ref attenuation, ref scattered))
                {
                    return(Shade(scattered, n - 1).Scale(attenuation));
                }
                return(Vector.Zero);
            }
            var u = ray.Direction.Normalize();
            var t = 0.5f * (u.Y + 1);

            return(new Vector(1, 1, 1) * (1f - t) + new Vector(0.5f, 0.7f, 1.0f) * t);
        }
예제 #2
0
        private static Vec3 Color(Ray r, Hitable world, int depth)
        {
            HitRecord rec = new HitRecord();

            if (world.Hit(r, 0.001, double.MaxValue, out rec))
            {
                Ray  scattered   = new Ray();
                Vec3 attenuation = new Vec3();
                Vec3 emitted     = rec.Material.emitted(rec.U, rec.V, rec.P);

                if (depth < 50 && rec.Material.Scatter(r, rec, out attenuation, out scattered))
                {
                    return(emitted + attenuation * Color(scattered, world, depth + 1));
                }
                else
                {
                    return(emitted);
                }
            }
            else
            {
                return(new Vec3(0.0, 0.0, 0.0));
            }
        }
예제 #3
0
        static void Main(string[] args)
        {
            var width   = 200;
            var height  = 100;
            var samples = 100;

            var camera = new Camera();
            var rand   = new Random();

            var world = new HitableList();

            world.Add(new Sphere(
                          new Vector3(0, 0, -1),
                          0.5f
                          ));
            world.Add(new Sphere(
                          new Vector3(0, -100.5f, -1),
                          100f
                          ));

            using (var image = new Image <Rgba32>(width, height))
            {
                for (int j = height - 1; j >= 0; j--)
                {
                    for (int i = 0; i < width; i++)
                    {
                        var col = new Vector3(0);

                        for (int s = 0; s < samples; s++)
                        {
                            // the horizontal distance from the origin as a float between 0 and 1
                            // with a random number between 0 and 1 added to it for each sample
                            var u = (i + (float)rand.NextDouble()) / (float)width;

                            // the vertical distance from the origin as a float between 0 and 1
                            // with a random number between 0 and 1 added to it for each sample
                            var v = 1 - ((j + (float)rand.NextDouble()) / (float)height);

                            var r = camera.GetRay(u, v);
                            col += Color(r, world);
                        }

                        // generates the average color over all the samples
                        col /= (float)samples;

                        // gamma correction
                        // basically fixes the color
                        // this is gamma 2 so you raise the color to the power 1/gamma which in this case means sqrt
                        col = new Vector3((float)Math.Sqrt(col.X), (float)Math.Sqrt(col.Y), (float)Math.Sqrt(col.Z));

                        image[i, j] = new Rgba32(col);
                    }
                }

                image.Save("images/gammacorr.png");
            }

            Vector3 Color(Ray r, Hitable world)
            {
                var rec = new HitRecord();

                if (world.Hit(r, 0.001f, float.MaxValue, rec))
                {
                    // generates a random point in a sphere that is tangent to the hitpoint
                    var target = rec.P + rec.Normal + RandomInUnitSphere();

                    // sends out a new ray in the direction of the target from the hitpoint
                    // returns when one of the subsequent rays either hits the sky or the t values become so close that they're basically zero
                    // the 0.5 means that 50% of the rays are absorbed into the material
                    return(0.5f * Color(new Ray(rec.P, target - rec.P), world));
                }
                else
                {
                    // this creates the sky
                    var unitDirection = Vector3.Normalize(r.Direction);                    // makes direction vector go between -1 and 1
                    var t             = 0.5f * (unitDirection.Y + 1.0f);                   // scales vector so it goes between 0 and 1
                    return((1 - t) * new Vector3(1f) + t * new Vector3(0.5f, 0.7f, 1.0f)); // linearly interpolates color
                }
            }

            Vector3 RandomInUnitSphere()
            {
                var p = new Vector3();

                do
                {
                    // This generates a random point with XYZ between -1 and 1
                    p = 2 * new Vector3((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()) - new Vector3(1);
                } while (p.LengthSquared() >= 1f);

                return(p);
            }
        }
예제 #4
0
 public abstract bool Scatter(Ray rIn, HitRecord record, Vector3 attenuation, Ray scattered);
예제 #5
0
 public abstract bool Hit(Ray r, float tMin, float tMax, HitRecord record);