public float Pdf(Vector3 <float> woWorld, Vector3 <float> wiWorld, BxDFType type) { if (!bxdfs.Any()) { return(0); } var wo = WorldToLocal(woWorld); var wi = WorldToLocal(wiWorld); if (wo.Z == 0) { return(0); } var matchingBxdfs = bxdfs.Where(b => b.Matches(type)); var pdf = 0f; foreach (var b in bxdfs) { pdf += b.Pdf(wo, wi); } var count = matchingBxdfs.Count(); return(count > 0 ? pdf / count : 0); }
public int NumComponents(BxDFType flags) { int num = 0; for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i].MatchesFlags (flags)) ++num; return num; }
public void Sample(ref Vector wo, ref Normal N, ref Normal shadeN, float u0, float u1, float u2,float u3, out BsdfSample sample, BxDFType type = BxDFType.AllTypes) { sample = new BsdfSample(); var fl = type; int matchingComps = NumComponents(fl); if (matchingComps == 0) { sample.Pdf = 0f; sample.Wi = Vector.Zero; sample.Spectrum = new RgbSpectrum(0f).ToArray(); } int which = (int)Math.Min((u0 * matchingComps), matchingComps - 1); BxDFBase bxdf = null; int count = which; for (int i = 0; i < Bxdfs.Length; ++i) if (Bxdfs[i].Type.HasFlag(fl)) if (count-- == 0) { bxdf = Bxdfs[i]; break; } Vector wi = new Vector(); var pdf = 0f; bxdf.Sample(ref wo, ref N, ref shadeN, u1, u2, u3, out sample, type); wi = sample.Wi; pdf = sample.Pdf; var sampled = bxdf.Type; if (pdf > 0f && pdf < MathLab.Epsilon) sample.Spectrum = new float[3]{0f,0f,0f}; //if (sampledTy != null) sampledType = bxdf.Type; //wiW = LocalToWorld(wi); if ((!bxdf.Type.HasFlag(BxDFType.Specular)) && matchingComps > 1) { for (int i = 0; i < Bxdfs.Length; ++i) { if (Bxdfs[i] != bxdf && (Bxdfs[i].Type.HasFlag(fl))) pdf += Bxdfs[i].Pdf(ref wo, ref wi, fl); } } if (matchingComps > 1) pdf /= matchingComps; // Compute value of BSDF for sampled direction if (bxdf.Type.HasFlag(BxDFType.Specular)) //if ((bxdf.Type & BxDFType.BSDF_SPECULAR) == 0) { var f = RgbSpectrum.ZeroSpectrum(); if ((Vector.Dot(ref N,ref wi)) * Vector.Dot(ref N, ref wo) > 0f) // ignore BTDFs { fl = fl & ~BxDFType.Transmission; } else // ignore BRDFs fl = (fl & ~BxDFType.Reflection); for (int i = 0; i < Bxdfs.Length; ++i) if ((Bxdfs[i].Type.HasFlag(fl))) f += new RgbSpectrum(Bxdfs[i].Eval(ref wo, ref wi, ref N)); sample.Spectrum = (f/pdf).ToArray(); } }
public Spectrum F(Vector woW, Vector wiW, BxDFType flags) { Vector wi = WorldToLocal (wiW), wo = WorldToLocal (woW); if ((wiW ^ ng) * (woW ^ ng) > 0) flags &= ~BxDFType.BSDF_TRANSMISSION; else flags &= ~BxDFType.BSDF_REFLECTION; Spectrum f = new Spectrum (); for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i].MatchesFlags (flags)) f += bxdfs[i].F (wo, wi); return f; }
public RgbSpectrum F(ref Vector wi, ref Vector wo, ref Normal n, BxDFType type) { var current = type; var result = new RgbSpectrum(); if (((Vector.Dot(ref wi, ref n)*Vector.Dot(ref wo, ref n)) > 0)) { current = type & ~BxDFType.Reflection; } else { current = type & ~BxDFType.Transmission; } for (int index = 0; index < Bxdfs.Length; index++) { if (Bxdfs[index].Type.HasFlag(current)) result += new RgbSpectrum(Bxdfs[index].Eval(ref wo, ref wi, ref n)); } return result; }
public double Pdf(Vector woW, Vector wiW, BxDFType flags) { if (nBxDFs == 0) return 0.0; Vector wo = WorldToLocal (woW), wi = WorldToLocal (wiW); double pdf = 0.0; int matchingComps = 0; for (int i = 0; i < nBxDFs; ++i) { if (bxdfs[i].MatchesFlags (flags)) { ++matchingComps; pdf += bxdfs[i].Pdf (wo, wi); } } return matchingComps > 0 ? pdf / matchingComps : 0.0; }
public bool MatchesFlags(BxDFType flags) { return (this.Type & flags) == this.Type; }
public override Spectrum Sample_f(Vector3 <float> wo, out Vector3 <float> wi, Point2 <float> u, out float pdf, out BxDFType sampledType) { pdf = 0; sampledType = 0; // Sample microfacet orientation and compute the incoming direction var wh = distribution.Sample_wh(wo, u); wi = Reflect(wo, wh); // If the reflected direction is in the opposite hemisphere, no light is reflected if (!MathUtils.SameHemisphere(wo, wi)) { return(Spectrum.Zero); } // Transform the PDF (Pdf() gives the distribution around the half-angle vector // but the integral requires the distribution around the incoming direction) pdf = distribution.Pdf(wo, wh) / (4 * wo.Dot(wh)); return(f(wo, wi)); }
public bool Matches(BxDFType type) { return((Type & type) == Type); }
public bool MatchesFlags(BxDFType flags) { return((type & flags) == type); }
public Spectrum Rho(BxDFType flags) { return Rho (flags, 6); }
public virtual float Pdf(ref Vector wo, ref Vector wi, BxDFType bxDFType) { return MathLab.INVTWOPI; }
public abstract void Sample(ref Vector wo, ref Normal N, ref Normal shadeN, float u0, float u1, float u2,out BsdfSample sample,BxDFType type = BxDFType.AllTypes);
public int NumComponents(BxDFType flags) { var res = Bxdfs.Count(p => MatchesFlags(p.Type, flags)); return res; }
public static bool MatchesFlags(BxDFType obj, BxDFType flags) { return (flags & obj).Equals(flags) || (flags & obj).Equals(obj); }
public override Spectrum Sample_f(Vector3 <float> wo, out Vector3 <float> wi, Point2 <float> sample, out float pdf, out BxDFType type) { // Compute the perfect specular reflection direction // // In polar coordinates: // phi_o = phi_i + pi // theta_o = theta_i wi = new Vector3 <float>(-wo.X, -wo.Y, wo.Z); // Simplified because we are in the BRDF coordinate frame pdf = 1; sample = null; type = 0; // TODO? return(fresnel.Evaluate(CosTheta(wi)) * reflectance * (1.0f / AbsCosTheta(wi))); }
public BxDF(BxDFType T) { type = T; }
public Spectrum Rho(Vector wo, BxDFType flags) { return Rho (wo, flags, 6); }
public BxDF(BxDFType type) { Type = type; }
public Spectrum Rho(Vector wo, BxDFType flags, int sqrtSamples) { int nSamples = sqrtSamples * sqrtSamples; double[] s1 = new double[2 * nSamples]; MonteCarlo.StratifiedSample2D (s1, sqrtSamples, sqrtSamples, true); Spectrum ret = new Spectrum (); for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i].MatchesFlags (flags)) ret += bxdfs[i].Rho (wo, nSamples, s1); return ret; }
// Sample an incoming direction for the given outgoing direction public virtual Spectrum Sample_f(Vector3 <float> wo, out Vector3 <float> wi, Point2 <float> sample, out float pdf, out BxDFType type) { // The default implementation samples the hemisphere with a cosine-weighted distribution wi = MathUtils.CosineSampleHemisphere(sample); // Flip the incoming direction to be in the same hemisphere as the outgoing direction if (wo.Z < 0) { wi.Z *= -1; } // Probability Density Function // - if not on the same hemisphere: 0 // - otherwise: wi . n pdf = Pdf(wo, wi); type = 0; return(f(wo, wi)); }
public Spectrum SampleF(Vector wo, ref Vector wi, BSDFSample bsdfSample, ref double pdf, BxDFType flags) { BxDFType temp = BxDFType.BSDF_ALL; return SampleF (wo, ref wi, bsdfSample, ref pdf, flags, ref temp); }
protected BxDF(BxDFType type) { Type = type; }
public Spectrum SampleF(Vector woW, ref Vector wiW, BSDFSample bsdfSample, ref double pdf, BxDFType flags, ref BxDFType sampledType) { int matchingComps = NumComponents (flags); if (matchingComps == 0) { pdf = 0.0; return new Spectrum (); } int which = Math.Min (Util.Floor2Int (bsdfSample.uComponent * matchingComps), matchingComps - 1); BxDF bxdf = null; int count = which; for (int i = 0; i < nBxDFs; ++i) { if (bxdfs[i].MatchesFlags (flags) && count-- == 0) { bxdf = bxdfs[i]; break; } } Vector wo = WorldToLocal (woW); Vector wi = new Vector (); pdf = 0.0; Spectrum f = bxdf.SampleF (wo, ref wi, bsdfSample.uDir[0], bsdfSample.uDir[1], ref pdf); if (pdf == 0.0) { return new Spectrum (); } sampledType = bxdf.Type; wiW = LocalToWorld (wi); if ((bxdf.Type & BxDFType.BSDF_SPECULAR) == 0 && matchingComps > 1) for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i] != bxdf && bxdfs[i].MatchesFlags (flags)) pdf += bxdfs[i].Pdf (wo, wi); if (matchingComps > 1) pdf /= matchingComps; if ((bxdf.Type & BxDFType.BSDF_SPECULAR) == 0) { f = new Spectrum (); if ((wiW ^ ng) * (woW ^ ng) > 0.0) flags &= ~BxDFType.BSDF_TRANSMISSION; else flags &= ~BxDFType.BSDF_REFLECTION; for (int i = 0; i < nBxDFs; ++i) if (bxdfs[i].MatchesFlags (flags)) f += bxdfs[i].F (wo, wi); } return f; }
public override Spectrum Sample_f(Vector3 <float> wo, out Vector3 <float> wi, Point2 <float> u, out float pdf, out BxDFType sampledType) { pdf = 0; sampledType = 0; // Cosine-sample the hemisphere if (u.X < 0.5f) { u.X *= 2; // Remap the sample to avoid each path to have samples covering only half the range of possible value wi = MathUtils.CosineSampleHemisphere(u); if (wo.Z < 0) { wi.Z = -wi.Z; } } // Sample the microfacet orientation else { u.X = 2 * (u.X - 0.5f); // Remap var wh = distribution.Sample_wh(wo, u); wi = Reflect(wo, wh); if (!MathUtils.SameHemisphere(wo, wi)) { return(Spectrum.Zero); } } pdf = Pdf(wo, wi); return(f(wo, wi)); }
public BxDF(BxDFType type) { this.Type = type; }