/// <summary> /// When called will trace the scene from the given camera location. /// Width * height must equal the length of the color array. /// Each pixel in the color array will be traced. The convention is X lines first then y lines (accessed via tracingTarget[x + y * width]). /// </summary> /// <param name="scene"></param> /// <param name="camera"></param> /// <param name="options"></param> /// <param name="token">Optional cancellation token. If cancelled the method will return false.</param> /// <returns>True if the scene was fully traced, false otherwise.</returns>> public virtual bool TraceScene(Scene scene, Camera camera, TracingOptions options, CancellationToken?token = null) { var width = options.Width; var height = options.Height; var rayCountX = width - 1; var rayCountY = height - 1; var tracingTarget = options.TracingTarget; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (token?.IsCancellationRequested ?? false) { return(false); } Vector3 averageColor = Vector3.Zero; for (int i = 0; i < options.SampleCount; i++) { var ray = camera.GetRayForRasterPosition(x, y, rayCountX, rayCountY); var cv = GetColorVectorForRay(scene, ray, 0, i); cv = Vector3.Clamp(cv, Vector3.Zero, Vector3.One); averageColor += cv; } averageColor /= options.SampleCount; tracingTarget[x + y * width] = new Color(averageColor); } } return(true); }
public override bool TraceScene(Scene scene, Camera camera, TracingOptions options, CancellationToken?token = null) { // using Parallel.For to automatically get multithreading var width = options.Width; var height = options.Height; var rayCountX = width - 1; var rayCountY = height - 1; var tracingTarget = options.TracingTarget; int range = options.Width * options.Height; // divided by 2 because we usually have foreground + background raytracer running at the same time, if we don't then each will spawn as many threads as we have cores which will cause additional lag // due to too many thread context switches var pi = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount / 2 }; var r = Parallel.For(0, range, pi, (i, loopState) => { int x = i / options.Width; int y = i % options.Height; if (loopState.ShouldExitCurrentIteration) { return; } if (token?.IsCancellationRequested ?? false) { loopState.Stop(); return; } Vector3 averageColor = Vector3.Zero; for (int sample = 0; sample < options.SampleCount; sample++) { var ray = camera.GetRayForRasterPosition(x, y, rayCountX, rayCountY); var cv = GetColorVectorForRay(scene, ray, 0, sample); cv = Vector3.Clamp(cv, Vector3.Zero, Vector3.One); averageColor += cv; } averageColor /= options.SampleCount; tracingTarget[x + y * width] = new Color(averageColor); }); return(r.IsCompleted); }