public static RayImage Render(int width, int height, int samples) { // As simple as possible code for now. var img = new RayImage(); img.Width = width; img.Height = height; img.Pixels = new Rgb3f[width * height]; //int samples = 50; var lookFrom = new Vec3f(5f, 5f, 5f); var lookAt = new Vec3f(0, 0, -1f); float dist_to_focus = (lookFrom - lookAt).GetLength(); float aperture = 2.0f; var cam = new Camera(lookFrom, lookAt, Vec3f.UnitY, 40, (float)width / (float)height, aperture, dist_to_focus); var drand = new Random(); var world = RandomScene(drand); //var world = new HitableList( // new Sphere(new Vec3f(0f, 0f, -1f), 0.5f, new Lambertian(new Vec3f(0.1f, 0.2f, 0.5f))), // new Sphere(new Vec3f(0, -100.5f, -1f), 100, new Lambertian(new Vec3f(0.8f, 0.8f, 0.0f))), // new Sphere(new Vec3f(1f, 0f, -1f), 0.5f, new Metal(new Vec3f(0.8f, 0.6f, 0.2f), 0.0f)), // new Sphere(new Vec3f(-1f, 0f, -1f), 0.5f, new Dielectric(1.5f)), // new Sphere(new Vec3f(-1f, 0f, -1f), -0.45f, new Dielectric(1.5f)) // ); int cur = 0; for (int j = height - 1; j >= 0; j--) { for (int i = 0; i < width; i++) { Vec3f col = Vec3f.Zero; for (int s = 0; s < samples; s++) { float u = (float)(i + drand.NextDouble()) / (float)width; float v = (float)(j + drand.NextDouble()) / (float)height; Ray r = cam.GetRay(u, v, drand); //Vec3f p = r.PointAtParameter(2.0f); // still not used. col += Color(r, world, 0, drand); } col /= (float)samples; // gamma correction ?? col = new Vec3f(MathF.Sqrt(col.X), MathF.Sqrt(col.Y), MathF.Sqrt(col.Z)); img.Pixels[cur++] = (Rgb3f)col; //img.Pixels[cur++] = new Rgb3f() { R = r, G = g, B = b }; } } return(img); }
public static bool WriteTga(this RayImage img, Stream output) { try { var sizeHeader = Marshal.SizeOf <TgaHeader>(); //const int sizeHeader = 18; var sizePixels = img.Width * img.Height * 3; var buffer = new byte[sizeHeader + sizePixels]; var span = new Span <byte>(buffer); // write header. // IMPORTENT TO USE REF HERE. ref TgaHeader header = ref MemoryMarshal.Cast <byte, TgaHeader>(span)[0]; //var header = MemoryMarshal.Cast<byte, TgaHeader>(span)[0]; //var header = MemoryMarshal.AsRef<TgaHeader>(span.Slice(0, sizeHeader)); header.DataTypeCode = 2; header.Width = (short)img.Width; header.Height = (short)img.Height; header.BitsPerPixel = 24; // convert rgb3f to bgr8 var slicePixels = span.Slice(sizeHeader, sizePixels); FormatUtils.ConvertBGR8(img, ref slicePixels); output.Write(span); output.Flush(); return(true); }
public static bool WritePpm(this RayImage img, Stream output) { try { using (var writer = new StreamWriter(output)) { //var writer = new StreamWriter(output); writer.WriteLine("P3"); writer.WriteLine($"{img.Width} {img.Height}"); writer.WriteLine("255"); foreach (var p in img.Pixels) { int ir = (int)(255.99 * p.R); int ig = (int)(255.99 * p.G); int ib = (int)(255.99 * p.B); writer.WriteLine($"{ir} {ig} {ib} "); } writer.Flush(); } return(true); } catch (Exception) { return(false); } }
public static bool WriteBmp(this RayImage img, Stream output) { try { var sizeFileHeader = Marshal.SizeOf <BmpFileHeader>(); //const int sizeFileHeader = 14; var sizeInfoHeader = Marshal.SizeOf <BmpInfoHeader>(); //const int sizeInfoHeader = 40; var sizePixels = img.Width * img.Height * 3; var buffer = new byte[sizeFileHeader + sizeInfoHeader + sizePixels]; var span = new Span <byte>(buffer); // write file header. ref BmpFileHeader fileHeader = ref MemoryMarshal.Cast <byte, BmpFileHeader>(span)[0]; fileHeader.Signature = (int)('B') + ((int)('M') << 8); fileHeader.FileSize = buffer.Length; fileHeader.DataOffset = sizeFileHeader + sizeInfoHeader; // write info header. ref BmpInfoHeader infoHeader = ref MemoryMarshal.Cast <byte, BmpInfoHeader>(span.Slice(sizeFileHeader, sizeInfoHeader))[0];
public static void ConvertBGR8(RayImage img, ref Span <byte> output, bool FlipHorizontal = false) { if (output.Length < (img.Pixels.Length * 3)) { throw new ArgumentException("output cant hold all of the pixel data..."); } int cur = 0; //TODO: Fold this code into single algorithm. if (FlipHorizontal) { for (int y = img.Height - 1; y > 0; y--) { int line = y * img.Width; for (int x = 0; x < img.Width; x++) { var p = img.Pixels[line + x]; output[cur++] = (byte)(255.99 * p.B); output[cur++] = (byte)(255.99 * p.G); output[cur++] = (byte)(255.99 * p.R); } } } else { foreach (var p in img.Pixels) { output[cur++] = (byte)(255.99 * p.B); output[cur++] = (byte)(255.99 * p.G); output[cur++] = (byte)(255.99 * p.R); } } }
public static RayImage RenderParallelFor(int width, int height, int samples) { // creating image and storage. var img = new RayImage(); img.Width = width; img.Height = height; img.Pixels = new Rgb3f[width * height]; // setting up camera: var lookFrom = new Vec3f(5f, 5f, 5f); var lookAt = new Vec3f(0, 0, -1f); float dist_to_focus = (lookFrom - lookAt).GetLength(); float aperture = 2.0f; var cam = new Camera(lookFrom, lookAt, Vec3f.UnitY, 40, (float)width / (float)height, aperture, dist_to_focus); var wrand = new Random(); var world = RandomScene(wrand); // creating world. //var world = new HitableList( // new Sphere(new Vec3f(0f, 0f, -1f), 0.5f, new Lambertian(new Vec3f(0.1f, 0.2f, 0.5f))), // new Sphere(new Vec3f(0, -100.5f, -1f), 100, new Lambertian(new Vec3f(0.8f, 0.8f, 0.0f))), // new Sphere(new Vec3f(1f, 0f, -1f), 0.5f, new Metal(new Vec3f(0.8f, 0.6f, 0.2f), 0.0f)), // new Sphere(new Vec3f(-1f, 0f, -1f), 0.5f, new Dielectric(1.5f)), // new Sphere(new Vec3f(-1f, 0f, -1f), -0.45f, new Dielectric(1.5f)) // ); // looping height lines. Parallel.For(0, height - 1, (cur) => { var j = height - cur - 1; // invert it? int curLine = cur * width; var drand = new Random(); // create unique random object for each thread to prevent locking. for (int i = 0; i < width; i++) { Vec3f col = Vec3f.Zero; for (int s = 0; s < samples; s++) { float u = (float)(i + drand.NextDouble()) / (float)width; float v = (float)(j + drand.NextDouble()) / (float)height; Ray r = cam.GetRay(u, v, drand); //Vec3f p = r.PointAtParameter(2.0f); // still not used. col += Color(r, world, 0, drand); } col /= (float)samples; col = new Vec3f(MathF.Sqrt(col.X), MathF.Sqrt(col.Y), MathF.Sqrt(col.Z)); img.Pixels[curLine + i] = (Rgb3f)col; //img.Pixels[curLine + i] = new Rgb3f(0.3f, 0.4f, 0.6f); } //System.Threading.Thread.Sleep(5); }); return(img); }