Example #1
0
        public Spectrum f(Vector3 <float> woWorld, Vector3 <float> wiWorld, BxDF.BxDFType type = BxDF.BxDFType.All)
        {
            // Transform the incident and outgoing directions to local BSDF space
            var wo = WorldToLocal(woWorld);
            var wi = WorldToLocal(wiWorld);

            var f = Spectrum.Zero;

            // Evaluate each BxDF
            var reflect = Vector3 <float> .Dot(wiWorld, ng) * Vector3 <float> .Dot(woWorld, ng) > 0;

            foreach (var bxdf in bxdfs)
            {
                // Two possibilities:
                //   - wo and wi lie in the same hemisphere: only evaluate reflection
                //   - wo and wi lie in different hemispheres: only evaluate transmission
                if (bxdf.Matches(type) && (
                        reflect && (bxdf.Type & BxDF.BxDFType.Reflection) > 0 ||
                        !reflect && (bxdf.Type & BxDF.BxDFType.Transmission) > 0))
                {
                    f += bxdf.f(wo, wi);
                }
            }

            return(f);
        }
Example #2
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);
        }
Example #3
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)));
        }
Example #4
0
        public Spectrum Sample_f(Vector3 <float> woWorld, out Vector3 <float> wiWorld, Point2 <float> u, out float pdf, BxDF.BxDFType type, out BxDF.BxDFType sampledType)
        {
            // Check that there are matching BxDFs
            var matchingBxdfs = bxdfs.Count(b => b.Matches(type));

            if (matchingBxdfs == 0)
            {
                pdf         = 0;
                sampledType = 0;
                wiWorld     = Vector3 <float> .Zero;
                return(Spectrum.Zero);
            }

            // Randomly pick a matching BxDF with the first dimension of the sample
            var n          = (int)Math.Min(Math.Floor(u.X * matchingBxdfs), matchingBxdfs - 1);
            var pickedBxdf = bxdfs.Where(b => b.Matches(type)).Skip(n).First();

            sampledType = pickedBxdf.Type;

            // Remap the sample to [0,1]
            u.X = u.X * matchingBxdfs - n;

            // Sample an incoming direction from the BxDF
            var wo = WorldToLocal(woWorld);
            var f  = pickedBxdf.Sample_f(wo, out Vector3 <float> wi, u, out pdf, out sampledType);

            wiWorld = LocalToWorld(wi);

            if (pdf == 0)
            {
                return(Spectrum.Zero);
            }

            // Compute overall PDF with matching BxDFs
            if ((pickedBxdf.Type & BxDFType.Specular) == 0 && matchingBxdfs > 1)
            {
                foreach (var b in bxdfs.Where(b => b != pickedBxdf && b.Matches(type)))
                {
                    pdf += b.Pdf(wo, wi);
                }
            }

            if (matchingBxdfs > 1)
            {
                pdf /= matchingBxdfs;
            }

            // Compute the BDSF value for the sampled incoming direction
            if ((pickedBxdf.Type & BxDFType.Specular) == 0 && matchingBxdfs > 1)
            {
                var reflect = Vector3 <float> .Dot(wiWorld, ng) * Vector3 <float> .Dot(woWorld, ng) > 0;

                foreach (var bxdf in bxdfs)
                {
                    if (bxdf.Matches(type) && (
                            reflect && (bxdf.Type & BxDFType.Reflection) > 0 ||
                            !reflect && (bxdf.Type & BxDFType.Transmission) > 0))
                    {
                        f += bxdf.f(wo, wi);
                    }
                }
            }

            return(f);
        }
Example #5
0
 public BxDF FirstMatch(BxDF.BxDFType type = BxDF.BxDFType.All)
 {
     return(bxdfs.FirstOrDefault(b => b.Matches(type)));
 }
Example #6
0
 public int NumComponents(BxDF.BxDFType type = BxDF.BxDFType.All)
 {
     return(bxdfs.Count(b => b.Matches(type)));
 }