Пример #1
0
        /// <summary> Sample the <paramref name="scene"/> with a <paramref name="sample"/> returning a color found </summary>
        /// <param name="scene">The <see cref="IScene"/> to sample </param>
        /// <param name="ray">The <see cref="Ir4"/> to trace through the <paramref name="scene"/> </param>
        /// <param name="spectrum">The throughput <see cref="ISpectrum"/></param>
        /// <param name="recursionDepth">The depth of recursion</param>
        /// <returns>The color found for the <see cref="ISample"/></returns>
        public ISpectrum Sample(IScene scene, IRay ray, ISpectrum spectrum, int recursionDepth)
        {
            if (spectrum.Equals(ISpectrum.Black))
            {
                return(ISpectrum.Black);
            }

            /// Russian Roulette
            float throughput = 1f;

            if (recursionDepth >= GauranteedRecursionDepth)
            {
                if (Utils.ThreadRandom.NextSingle() < RussianRouletteChance)
                {
                    return(ISpectrum.Black);
                }
                else
                {
                    throughput = 1f / RussianRouletteChance;
                }
            }

            /// Sample Distance
            IDistanceQuery?distanceQuery = scene.Trace(ray, spectrum);

            if (distanceQuery is null)
            {
                return(ISpectrum.Black);
            }
            Position1 distance = distanceQuery.DistanceDistribution.Sample(Utils.ThreadRandom);

            if (distance == Position1.PositiveInfinity)
            {
                return(ISpectrum.Black);
            }

            /// Sample Primitive
            IProbabilityDistribution <IPrimitive>?primitives = distanceQuery.TryGetPrimitives(distance);

            if (primitives is null)
            {
                throw new InvalidOperationException("Distance was sampled but no primitive was found");
            }
            IPrimitive primitive = primitives.Sample(Utils.ThreadRandom);

            /// Get Intersection Position
            Position3 position = primitive.Material.DensityProfile.GetPosition(ray, distance, primitive.Shape);

            /// Sample Material Orientation
            IProbabilityDistribution <Normal3>?orientations = primitive.Material.OrientationProfile.GetOrientations(position, ray.Direction, primitive.Shape);

            if (orientations is null)
            {
                return(ISpectrum.Black);
            }
            Normal3 orientation = orientations.Sample(Utils.ThreadRandom);

            /// Get Direct Illumination
            ISpectrum directIllumination = RGBColors.Black;

            if (primitive.Material.EmittanceProfile.IsEmitting)
            {
                directIllumination = primitive.Material.EmittanceProfile.GetEmittance(position, orientation, -ray.Direction);
            }

            /// Get Indirect Illumination
            ISpectrum indirectIllumination = RGBColors.Black;

            if (!primitive.Material.AbsorptionProfile.IsBlackBody)
            {
                /// Sample Direction
                IProbabilityDistribution <Normal3> directions = primitive.Material.ReflectionProfile.GetDirections(ray.Direction, position, orientation, spectrum);
                Normal3 direction = directions.Sample(Utils.ThreadRandom);

                /// Get Albedo
                ISpectrum albedo = primitive.Material.AbsorptionProfile.GetAlbedo(position, orientation, -direction);

                /// Get Ray
                IRay raySample = primitive.Material.DensityProfile.GetRay(position, orientation, direction);

                /// Sample Indirect Illumination
                indirectIllumination = albedo * Sample(scene, raySample, spectrum * albedo, recursionDepth + 1);
            }

            /// Light Throughput Calculation
            return((directIllumination + indirectIllumination) * throughput);
        }