public override Color[,] RenderScene(Scene scene, Camera camera, Action <float> updateProcessCallback) { progress = 0; //Parallel.For(0, height, y => for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Vector3 colorValue = Vector3.Zero; for (int i = 0; i < samples; i++) { float xLerp = (float)(x + random.NextDouble()) / width; float yLerp = (float)(y + random.NextDouble()) / height; Ray ray = camera.GetRay(xLerp, yLerp); colorValue += GetColorValue(ray, scene, 0); } colorValue /= samples; colorValue = Vector3.Clamp(colorValue, Vector3.Zero, Vector3.One); // Gamma 2 colorValue.X = MathF.Sqrt(colorValue.X); colorValue.Y = MathF.Sqrt(colorValue.Y); colorValue.Z = MathF.Sqrt(colorValue.Z); colors[x, height - y - 1] = Color.FromArgb((int)(255 * colorValue.X), (int)(255 * colorValue.Y), (int)(255 * colorValue.Z)); progress += (float)1 / height / width; if (progress > 1) { progress = 1; } updateProcessCallback?.Invoke(progress); } } updateProcessCallback?.Invoke(1); return(colors); }
private void SaveFile() { int scannedPixels = 0; Parallel.For(0, Height, new ParallelOptions() { MaxDegreeOfParallelism = 1 }, (k) => { int j = Height - k; for (int i = 0; i < Width; i++) { Vector3 color = Vector3.Zero; for (int s = 0; s < samplesPerPixel; s++) { var u = (float)(i + Utils.Rand.NextDouble()) / (Width - 1); var v = (float)(j + Utils.Rand.NextDouble()) / (Height - 1); Ray r = Camera.GetRay(u, v); color += r.RayColor(EngineObjects, SceneLights, maxDepth); } //System.Threading.Interlocked.Increment(ref scannedPixels); //var tmp = MathF.Round((float)scannedPixels / ColorBuffer.Length * 100); //Console.WriteLine(tmp.ToString().Replace(',', '.') + " %"); ColorBuffer[(k * Width) + i] = color; } }); using StreamWriter sw = new StreamWriter(outputFilePath); sw.WriteLine("P3"); sw.WriteLine($"{Width} {Height}"); sw.WriteLine("255"); for (int i = 0; i < ColorBuffer.Length; i++) { sw.WriteColor(ColorBuffer[i], samplesPerPixel); } sw.Flush(); Console.WriteLine("Done!"); }
public override void Render(Scene scene, Camera camera) { scene.Preprocess(); if (camera is LensCamera lensCamera && lensCamera.AutoFocus) { var ray = lensCamera.GetRay(0.5f, 0.5f); var hitInfo = new HitInfo(); var hit = scene.HitTest(ray, ref hitInfo, 0.001f, float.PositiveInfinity); if (hit) { lensCamera.FocusDistance = hitInfo.Distance; } else { lensCamera.FocusDistance = 100000f; } } int width = Resolution; int height = (int)(width / camera.AspectRatio); var image = new Texture(width, height); AbstractSampler <Vector2> sampler = new ThreadSafeSampler <Vector2>(Sampling, Samples); for (int k = 0; k < Samples; k++) { try { Parallel.For(0, width, new ParallelOptions { CancellationToken = CancellationToken }, i => { for (int j = 0; j < height; j++) { var sample = sampler.GetSample(k); float u = (i + sample.X) / (width - 1); float v = (j + sample.Y) / (height - 1); Ray ray = camera.GetRay(u, v); var shade = Shade(ray, scene, MaxDepth); image.Bloom(shade, i, j, (int)shade.GetBrightness(), Bloom); image[i, j] += shade; } }); } catch (Exception e) { Log.Warn(e); } if (CancellationToken.IsCancellationRequested) { return; } if (k % SamplesRenderStep == 0 || k == Samples - 1) { var output = new Texture(image); output.Process(c => (c / (k + 1)).Clamp()); if (GammaCorrection) { output.AutoGammaCorrect(); } var percentage = (k + 1) * 100 / Samples; OnFrameReady?.Invoke(percentage, output); } } }