private HitableList GenerateWorld(Random rng) { UnitSphereUniformSampler sphereSampler = new UnitSphereUniformSampler(rng); List <IHitable> objects = new List <IHitable>(); // Add the main earth object IMaterial earthMaterial = new Lambertian(new Vector3(0.5, 0.5, 0.5), sphereSampler); objects.Add(new Sphere(new Vector3(0, -1000, 0), 1000, earthMaterial)); // Generate random objects Vector3 temp = new Vector3(4, 0.2, 0); for (int a = -11; a < 11; ++a) { for (int b = -11; b < 11; ++b) { double chooseMat = rng.NextDouble(); Vector3 center = new Vector3(a + 0.9 * rng.NextDouble(), 0.2, b + 0.9 * rng.NextDouble()); if ((center - temp).Length() > 0.9) { // 80% chance to choose diffuse if (chooseMat < 0.8) { double red = rng.NextDouble() * rng.NextDouble(); double green = rng.NextDouble() * rng.NextDouble(); double blue = rng.NextDouble() * rng.NextDouble(); var randomDiffuseMaterial = new Lambertian( new Vector3(red, green, blue), sphereSampler); objects.Add(new Sphere(center, 0.2, randomDiffuseMaterial)); } else if (chooseMat < 0.95) { // 15% chance for metal material double red = 0.5 * (1 + rng.NextDouble()); double green = 0.5 * (1 + rng.NextDouble()); double blue = 0.5 * (1 + rng.NextDouble()); double fuzz = 0.5 * rng.NextDouble(); var randomMetal = new Metal(new Vector3(red, green, blue), fuzz, sphereSampler); objects.Add(new Sphere(center, 0.2, randomMetal)); } else { // 5% chance for dielectric objects.Add(new Sphere(center, 0.2, new Dielectric(1.5, rng))); } } } } objects.Add(new Sphere(new Vector3(0, 1, 0), 1.0, new Dielectric(1.5, rng))); objects.Add(new Sphere(new Vector3(-4, 1, 0), 1.0, new Lambertian(new Vector3(0.4, 0.2, 0.1), sphereSampler))); objects.Add(new Sphere(new Vector3(4, 1, 0), 1.0, new Metal(new Vector3(0.7, 0.6, 0.5), 0.0, sphereSampler))); return(new HitableList(objects)); }
public Metal(Vector3 a, double fuzz, UnitSphereUniformSampler sampler) { this.albedo = a; this.fuzz = fuzz; this.sampler = sampler; }
public Lambertian(Vector3 albedo, UnitSphereUniformSampler sampler) { this.albedo = albedo; this.sampler = sampler; }
public void RenderScene() { int nx = 800; int ny = 400; int ns = 100; var lowerLeftCorner = new Vector3(-2.0, -1.0, -1.0); var horizontal = new Vector3(4.0, 0.0, 0.0); var vertical = new Vector3(0.0, 2.0, 0.0); var origin = new Vector3(0.0, 0.0, 0.0); Random rng = new Random(); UnitSphereUniformSampler sphereSampler = new UnitSphereUniformSampler(rng); UnitCircleUniformSampler circleSampler = new UnitCircleUniformSampler(rng); IMaterial mat1 = new Lambertian(new Vector3(0.1, 0.2, 0.5), sphereSampler); IMaterial mat2 = new Lambertian(new Vector3(0.8, 0.8, 0.0), sphereSampler); IMaterial mat3 = new Metal(new Vector3(0.8, 0.6, 0.2), 0.3, sphereSampler); IMaterial mat4 = new Dielectric(1.5, rng); List <IHitable> objects = new List <IHitable>(4); objects.Add(new Sphere(new Vector3(0, 0, -1), 0.5, mat1)); objects.Add(new Sphere(new Vector3(0, -100.5, -1), 100, mat2)); objects.Add(new Sphere(new Vector3(1, 0, -1), 0.5, mat3)); objects.Add(new Sphere(new Vector3(-1, 0, -1), 0.5, mat4)); objects.Add(new Sphere(new Vector3(-1, 0, -1), -0.45, mat4)); HitableList world = new HitableList(objects); Vector3 lookFrom = new Vector3(-2, 2, 1); Vector3 lookAt = new Vector3(0, 0, -1); Camera camera = new Camera( circleSampler, lookFrom, lookAt, new Vector3(0, 1, 0), 90.0 * Math.PI / 180.0, (double)nx / (double)ny, 0.2, (lookAt - lookFrom).Length()); Random random = new Random(); // Create folder to output frames if (!Directory.Exists("ThreeSpheres")) { Directory.CreateDirectory("ThreeSpheres"); } Sensor sensor = new Sensor(nx, ny, new SqrtColorSpace(), RGBColor.Black); int frameNum = 0; for (int s = 0; s < ns; ++s) { for (int j = ny - 1; j >= 0; --j) { for (int i = 0; i < nx; i++) { double u = (i + random.NextDouble()) / nx; double v = (j + random.NextDouble()) / ny; Ray3 r = new Ray3(camera.GetRay(u, v)); Vector3 color = Program.Color(r, world, 0); sensor.AddSample(i, j, new RGBColor(color[0], color[1], color[2])); } } if (s % (ns / 10) == 0) { // Output 1 frame with current number of samples sensor.WritePPMFile($"ThreeSpheres\\frame_{frameNum}.ppm").Wait(); frameNum++; } Console.Write("\r{0}", s); } sensor.WritePPMFile("finalOutput.ppm").Wait(); }