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); }
/// <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); }
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))); }
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); }
public BxDF FirstMatch(BxDF.BxDFType type = BxDF.BxDFType.All) { return(bxdfs.FirstOrDefault(b => b.Matches(type))); }
public int NumComponents(BxDF.BxDFType type = BxDF.BxDFType.All) { return(bxdfs.Count(b => b.Matches(type))); }