public void TreadSafeSamplerShouldBeThreadSafe() { const int samplesCount = 1; List <int> Generator(int count) => Enumerable.Range(0, count).ToList(); ThreadSafeSampler <int> sampler = new ThreadSafeSampler <int>(Generator, samplesCount); Action action = () => { Parallel.For(0, 1000, _ => { for (; _ < 1000; _++) { sampler.GetSample(); } }); }; action.Should().NotThrow(); }
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); } } }