Пример #1
0
        /// <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);
        }
Пример #2
0
        protected override void Initialize()
        {
            base.Initialize();

            SetupScene();
            IsMouseVisible = false;
            // instead of creating a texture of the size width * height where we then end up filling Raster*Raster sized blocks with the same pixeldata
            // we create a smaller buffer and scale it when rendering
            var primaryWidth  = _options.Width / _options.RealtimeRasterLevel;
            var primaryHeight = _options.Height / _options.RealtimeRasterLevel;
            var pixels        = new Color[primaryWidth * primaryHeight];

            _primaryTracingOptions = new TracingOptions(primaryWidth, primaryHeight, pixels, _options.RealtimeSampleCount);

            if (_options.BackgroundRasterLevel < _options.RealtimeRasterLevel)
            {
                // only enable background rendering if it is more accurate than realtime rendering, otherwise disable it by leaving the backgroundTracingOptions null
                var backgroundWidth  = _options.Width / _options.BackgroundRasterLevel;
                var backgroundHeight = _options.Width / _options.BackgroundRasterLevel;
                var secondBuffer     = new Color[backgroundWidth * backgroundHeight];
                _backgroundTracingOptions = new TracingOptions(backgroundWidth, backgroundHeight, secondBuffer, _options.BackgroundSampleCount);
                _backgroundScene          = new Texture2D(GraphicsDevice, backgroundWidth, backgroundHeight);
            }

            _primaryScene = new Texture2D(GraphicsDevice, primaryWidth, primaryHeight);
            // we have 2 distinct textures: primary and background
            // primary is usually smaller (for real time rendering)
            // for rendering we always use _renderReference which just points to one of the 2 other textures

            // start of with the primary scene
            _renderReference = _primaryScene;
            _spriteBatch     = new SpriteBatch(GraphicsDevice);
            _sceneChanged    = true;
            _watch           = new Stopwatch();
        }
Пример #3
0
        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);
        }