// 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); }
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)); } }
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); } }
public abstract bool Scatter(Ray rIn, HitRecord record, Vector3 attenuation, Ray scattered);
public abstract bool Hit(Ray r, float tMin, float tMax, HitRecord record);