예제 #1
0
        public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming)
        {
            var   entering = CosTheta(ref leaving) > 0;
            float ei, et;

            if (entering)
            {
                ei = IndexOfRefractionIncident;
                et = IndexOfRefractionTransmitted;
            }
            else
            {
                et = IndexOfRefractionIncident;
                ei = IndexOfRefractionTransmitted;
            }
            var sinIncidentSquared = SinThetaSquared(ref leaving);
            var eta = ei / et;
            var sinTransmittedSquared = eta * eta * sinIncidentSquared;
            var cosTransmitted        = (float)Math.Sqrt(1 - sinTransmittedSquared);

            if (entering)
            {
                cosTransmitted = -cosTransmitted;
            }
            var sinTOversinI = eta;

            incoming = new Vector3(sinTOversinI * -leaving.X, sinTOversinI * -leaving.Y, cosTransmitted);
            if (sinTransmittedSquared >= 1)
            {
                return(SampledSpectrum.Black());
            }
            var f = _fresnel.Evaluate(CosTheta(ref leaving));

            return((new SampledSpectrum(1) - f) * _s / AbsCosTheta(ref incoming) * (et * et) / (ei * ei));
        }
예제 #2
0
        public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample, ref Intersection i)
        {
            var spectrum    = SampledSpectrum.Black();
            var lights      = scene.Lights;
            var bsdfAtPoint = i.GetBSDF();
            // we want to get the radiance coming from the surface to us, but the ray comes from us
            // to the surface
            var leaving = -ray.Direction;

            foreach (var light in lights)
            {
                Vector3          incoming;
                VisibilityTester visibilityTester;
                var lightSpectrum = light.Sample(ref i.Point, scene, out incoming, out visibilityTester);
                // We compute the BSDF value only if the light is not black and it is not occluded. Note that it is important
                // for the occlusion test to be after the test for black spectrum, because checking for intersection is an
                // expansive operation.
                if (!lightSpectrum.IsBlack() && !visibilityTester.Occluded())
                {
                    var cosangle = Math.Abs(Vector3.Dot(incoming, i.NormalVector));
                    // we get the light coming to us from transmission + reflection
                    var bsdf = bsdfAtPoint.F(incoming, leaving, BxDF.BxDFType.All);
                    // we scale the light by the incident angle of light on the surface and by the distribution
                    // function from light to us and we add it to the spectrum
                    spectrum += bsdf * lightSpectrum * cosangle;
                }
            }
            if (ray.Depth + 1 < MaxDepth)
            {
                spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref i);
                spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref i);
            }
            return(spectrum);
        }
예제 #3
0
        /// <summary>
        ///     Choose an incoming direction on the view from a BxDF matching a type
        ///     and returns its contribution
        /// </summary>
        /// <param name="leaving">the vector leaving the surface</param>
        /// <param name="incoming">the vector arriving at the surface, the function will set it</param>
        /// <param name="type">the type of scattering</param>
        /// <returns></returns>
        public SampledSpectrum Sample(Vector3 leaving, ref Vector3 incoming, BxDF.BxDFType type)
        {
            /* we randomly choose a BxDF that matches the type */
            var matchingBxDFs = _bxdfs.Where(f => type.HasFlag(f.Type)).ToList(); // the list of bxdf matching the type

            if (matchingBxDFs.Count == 0)
            {
                return(SampledSpectrum.Black());
            }
            // random selection over matching bxdfs
            var bxdf =
                matchingBxDFs.ElementAt(Math.Min((int)(StaticRandom.NextFloat() * matchingBxDFs.Count), matchingBxDFs.Count - 1));
            var     leavingLocal = WorldToLocal(ref leaving);
            Vector3 incomingLocal;
            // we sample the chosen bxdf
            var spectrum = bxdf.Sample(leavingLocal, out incomingLocal);

            // we transform the incoming ray returned by the sampling to world space
            incoming = LocalToWorld(ref incomingLocal);
            // is the reflection is not specular, we add contribution from other bxdfs of the same type
            if (!bxdf.Type.HasFlag(BxDF.BxDFType.Reflection))
            {
                spectrum = _bxdfs.Where(b => type.HasFlag(b.Type))
                           .Aggregate(spectrum, (current, b) => current + b.F(incomingLocal, leavingLocal));
            }
            return(spectrum);
        }
예제 #4
0
        private SampledSpectrum SampleLights(Scene scene, BSDF bsdf, ref Intersection intersection,
                                             ref Vector3 leaving)
        {
            var lights   = scene.Lights;
            var spectrum = SampledSpectrum.Black();

            foreach (var light in lights)
            {
                var nsamples          = _strategy == LightSamplingStrategy.Multiple ? light.NSamples : 1;
                var lightContribution = SampledSpectrum.Black();
                for (var i = 0; i < nsamples; ++i)
                {
                    Vector3          incoming;
                    VisibilityTester visibilityTester;
                    var lightSpectrum = light.Sample(ref intersection.Point, scene, out incoming, out visibilityTester);
                    if (lightSpectrum.IsBlack() || visibilityTester.Occluded())
                    {
                        continue;
                    }
                    var cosangle = Math.Abs(Vector3.Dot(incoming, intersection.NormalVector));
                    // we get the light coming to us from transmission + reflection
                    var distribution = bsdf.F(incoming, leaving, BxDF.BxDFType.All);
                    // we scale the light by the incident angle of light on the surface and by the distribution
                    // function from light to us and we add it to the spectrum
                    lightContribution += distribution * lightSpectrum * cosangle;
                }
                spectrum += lightContribution / nsamples;
            }
            return(spectrum);
        }
예제 #5
0
        public SampledSpectrum F(Vector3 incoming, Vector3 leaving, BxDF.BxDFType type)
        {
            var s             = SampledSpectrum.Black();
            var incomingLocal = WorldToLocal(ref incoming);
            var leavingLocal  = WorldToLocal(ref leaving);

            return(_bxdfs.Where(bxdf => type.HasFlag(bxdf.Type))
                   .Aggregate(s, (current, bxdf) => current + bxdf.F(incomingLocal, leavingLocal)));
        }
예제 #6
0
        public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample,
                                           ref Intersection intersection)
        {
            var spectrum    = SampledSpectrum.Black();
            var bsdfAtPoint = intersection.GetBSDF();
            var leaving     = -ray.Direction;

            spectrum += SampleLights(scene, bsdfAtPoint, ref intersection, ref leaving);
            if (ray.Depth + 1 < MaxDepth)
            {
                spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref intersection);
                spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref intersection);
            }
            return(spectrum);
        }
예제 #7
0
        public SampledSpectrum SpecularTransmit(Ray ray, Renderer renderer, Sample sample, BSDF bsdf, ref Intersection i)
        {
            var leaving  = -ray.Direction;
            var incoming = new Vector3();
            var f        = bsdf.Sample(leaving, ref incoming, BxDF.BxDFType.Transmission | BxDF.BxDFType.Specular);
            var angle    = Math.Abs(Vector3.Dot(incoming.Normalized(), i.NormalVector));

            if (f.IsBlack() || angle == 0f)
            {
                return(SampledSpectrum.Black());
            }
            var reflectedRay = new Ray(incoming.Normalized(), i.Point, 0.1f, Ray.DefaultEndValue, ray.Depth + 1);
            var li           = renderer.Li(sample, reflectedRay);

            return(f * li * angle);
        }
예제 #8
0
        /// <summary>
        ///     Compute radiance for a sample
        /// </summary>
        /// <param name="sample"></param>
        /// <param name="ray"></param>
        /// <returns></returns>
        public SampledSpectrum Li(Sample sample, Ray ray = null)
        {
            ray = ray ?? Camera.GenerateRay(sample);
            var intersection = new Intersection();
            var spectrum     = SampledSpectrum.Black();

            if (Scene.TryToIntersect(ray, ref intersection))
            {
                spectrum = Integrator.Li(Scene, ray, this, sample, ref intersection);
            }
            else
            {
                spectrum = Scene.Lights.Aggregate(spectrum, (current, light) => current + light.Le(ray));
            }
            return(spectrum);
        }
        /// <summary>
        /// </summary>
        /// <remarks>This function let us choose the incoming vector</remarks>
        /// <param name="leaving"></param>
        /// <param name="incoming"></param>
        /// <returns></returns>
        public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming)
        {
            /* Since we are in the reflection system, rotating the vector by PI radians
             * around the normal consists of negating its x component and its y component */
            incoming = new Vector3(-leaving.X, -leaving.Y, leaving.Z);
            var abscostheta = AbsCosTheta(ref incoming);

            var reflectedLight = SampledSpectrum.Black();

            if (_fresnel != null)
            {
                var reflectedAmount = _fresnel.Evaluate(CosTheta(ref incoming));
                reflectedLight = _spectrum * reflectedAmount / abscostheta;
            }
            else
            {
                reflectedLight = _spectrum * _reflectiveness / abscostheta;
            }
            return(reflectedLight);
        }
 /// <summary>
 /// </summary>
 /// <remarks>
 ///     This function returns nothing since it is nearly impossible to have
 ///     a correct incoming vector (there is only a single incoming vector)
 /// </remarks>
 /// <param name="incoming"></param>
 /// <param name="leaving"></param>
 /// <returns></returns>
 public override SampledSpectrum F(Vector3 incoming, Vector3 leaving)
 {
     return(SampledSpectrum.Black());
 }
예제 #11
0
 /// <summary>
 ///     Return the spectrum of light when ray does not hit anything.
 /// </summary>
 /// <param name="ray">the ray</param>
 /// <returns></returns>
 public virtual SampledSpectrum Le(Ray ray)
 {
     return(SampledSpectrum.Black());
 }