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); }
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)); }
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); }
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}"); }
public static Vec3 Random(double min, double max) { return(new Vec3(RayTracerUtils.RandomDouble(min, max), RayTracerUtils.RandomDouble(min, max), RayTracerUtils.RandomDouble(min, max))); }
public static Vec3 Random() { return(new Vec3(RayTracerUtils.RandomDouble(), RayTracerUtils.RandomDouble(), RayTracerUtils.RandomDouble())); }