private static void ShowSceneDef(SceneDefinition sceneDef) { Console.WriteLine("====================================="); Console.WriteLine("ImageWidth: " + sceneDef.ImageWidth); Console.WriteLine("ImageHeight: " + sceneDef.ImageHeight); Console.WriteLine("NumSamples: " + sceneDef.NumSamples); Console.WriteLine("ChunkSize: " + sceneDef.ChunkSize); Console.WriteLine("CameraLookFrom: " + string.Join(", ", sceneDef.CameraLookFrom)); Console.WriteLine("CameraLookAt: " + string.Join(", ", sceneDef.CameraLookAt)); Console.WriteLine("CameraFocusDistance: " + sceneDef.CameraFocusDistance); Console.WriteLine("CameraAperture: " + sceneDef.CameraAperture); }
private static void RenderPart(int i, int j, SceneDefinition sceneDef, Camera cam, IHitable world, StringBuilder output) { var col = new Vec3(); for (var s = 0; s < sceneDef.NumSamples; s++) { var u = (i + Utils.NextFloat()) / sceneDef.ImageWidth; var v = (j + Utils.NextFloat()) / sceneDef.ImageHeight; var r = cam.GetRay(u, v); col += Color(r, world, 0); } col /= sceneDef.NumSamples; // gamma correction col = new Vec3((float)Math.Sqrt(col.R), (float)Math.Sqrt(col.G), (float)Math.Sqrt(col.B)); var ir = (int)(255.99 * col[0]); var ig = (int)(255.99 * col[1]); var ib = (int)(255.99 * col[2]); output.AppendLine($"{ir} {ig} {ib}"); }
private static void Render(SceneDefinition sceneDef, StringBuilder output) { /*var world = new HitableList() * { * new Sphere(new Vec3(0.0f, 0.0f, -1.0f), 0.5f, new Lambertian(new Vec3(0.8f, 0.3f, 0.3f))), * new Sphere(new Vec3(0.0f, -100.5f, -1.0f), 100.0f, new Lambertian(new Vec3(0.8f, 0.8f, 0.0f))), * new Sphere(new Vec3(1.0f, 0.0f, -1.0f), 0.5f, new Metal(new Vec3(0.8f, 0.6f, 0.2f), 1.0f)), * * // make bubble by having a smaller sphere with negative radius * new Sphere(new Vec3(-1.0f, 0.0f, -1.0f), 0.5f, new Dielectric(1.5f)), * new Sphere(new Vec3(-1.0f, 0.0f, -1.0f), -0.45f, new Dielectric(1.5f)), * };*/ var world = new BvhNode(RandomScene()); // var world = TwoPerlinSpheres(); var lookFrom = new Vec3(sceneDef.CameraLookFrom[0], sceneDef.CameraLookFrom[1], sceneDef.CameraLookFrom[2]); var lookAt = new Vec3(sceneDef.CameraLookAt[0], sceneDef.CameraLookAt[1], sceneDef.CameraLookAt[2]); var focusDistance = sceneDef.CameraFocusDistance; var aperture = sceneDef.CameraAperture; var cam = new Camera(lookFrom, lookAt, new Vec3(0.0f, 1.0f, 0.0f), 20.0f, sceneDef.ImageWidth / (float)sceneDef.ImageHeight, aperture, focusDistance); var totalCount = sceneDef.ImageWidth * sceneDef.ImageHeight; var currentCount = 0; var sw = new Stopwatch(); sw.Start(); output.AppendLine($"P3\n{sceneDef.ImageWidth} {sceneDef.ImageHeight}\n255"); if (sceneDef.ChunkSize > 0) { var chunks = Enumerable.Range(0, totalCount).Chunk(sceneDef.ChunkSize * sceneDef.ChunkSize).ToArray(); var bag = new ConcurrentBag <Tuple <int, StringBuilder> >(); var progress = new Progress <int>(cnt => ReportProgress(cnt, totalCount, sw.Elapsed)) as IProgress <int>; Parallel.ForEach(chunks, chunk => { var chunkOutput = new StringBuilder(); foreach (var idx in chunk) { var i = idx % sceneDef.ImageWidth; var j = sceneDef.ImageHeight - 1 - idx / sceneDef.ImageWidth; RenderPart(i, j, sceneDef, cam, world, chunkOutput); Interlocked.Increment(ref currentCount); progress.Report(currentCount); } bag.Add(new Tuple <int, StringBuilder>(chunk.First(), chunkOutput)); }); foreach (var tuple in bag.OrderBy(x => x.Item1)) { output.Append(tuple.Item2); } } else { for (var j = sceneDef.ImageHeight - 1; j >= 0; j--) { for (var i = 0; i < sceneDef.ImageWidth; i++) { RenderPart(i, j, sceneDef, cam, world, output); ReportProgress(++currentCount, totalCount, sw.Elapsed); } } } sw.Stop(); Console.WriteLine($"\nElapsed: {sw.Elapsed.Hours:00}:{sw.Elapsed.Minutes:00}:{sw.Elapsed.Seconds:00}"); }