// commented, dpl 10 august 2005 Spectrum Lafortune::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const { u_int comp = RandomUInt() % (nLobes+1); if (comp == nLobes) { // Cosine-sample the hemisphere, flipping the direction if necessary *wi = CosineSampleHemisphere(u1, u2); if (wo.z < 0.) wi->z *= -1.f; } else { // Sample lobe _comp_ for Lafortune BRDF float xlum = x[comp].y(); float ylum = y[comp].y(); float zlum = z[comp].y(); float costheta = powf(u1, 1.f / (.8f * exponent[comp].y() + 1)); float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta)); float phi = u2 * 2.f * M_PI; Vector lobeCenter = Normalize(Vector(xlum * wo.x, ylum * wo.y, zlum * wo.z)); Vector lobeX, lobeY; CoordinateSystem(lobeCenter, &lobeX, &lobeY); *wi = SphericalDirection(sintheta, costheta, phi, lobeX, lobeY, lobeCenter); } if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); *pdf = Pdf(wo, *wi); return f(wo, *wi); }
Vector3f TrowbridgeReitzDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const { Vector3f wh; if (!sampleVisibleArea) { Float cosTheta = 0, phi = (2 * Pi) * u[1]; if (alphax == alphay) { Float tanTheta2 = alphax * alphax * u[0] / (1.0f - u[0]); cosTheta = 1 / std::sqrt(1 + tanTheta2); } else { phi = std::atan(alphay / alphax * std::tan(2 * Pi * u[1] + .5f * Pi)); if (u[1] > .5f) phi += Pi; Float sinPhi = std::sin(phi), cosPhi = std::cos(phi); const Float alphax2 = alphax * alphax, alphay2 = alphay * alphay; const Float alpha2 = 1 / (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2); Float tanTheta2 = alpha2 * u[0] / (1 - u[0]); cosTheta = 1 / std::sqrt(1 + tanTheta2); } Float sinTheta = std::sqrt(std::max((Float)0., (Float)1. - cosTheta * cosTheta)); wh = SphericalDirection(sinTheta, cosTheta, phi); if (!SameHemisphere(wo, wh)) wh = -wh; } else { bool flip = wo.z < 0; wh = TrowbridgeReitzSample(flip ? -wo : wo, alphax, alphay, u[0], u[1]); if (flip) wh = -wh; } return wh; }
float BxDF::PDF(const Vector3& p_wo, const Vector3& p_wi) const { bool temp = SameHemisphere(p_wo, p_wi); if (temp){ return AbsCosTheta(p_wi) * Maths::InvPi; } return 0.0f; //return SameHemisphere(p_wo, p_wi) ? AbsCosTheta(p_wi) * Maths::InvPi : 0.f; }
Spectrum MicrofacetReflection::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &u, Float *pdf, BxDFType *sampledType) const { // Sample microfacet orientation $\wh$ and reflected direction $\wi$ Vector3f wh = distribution->Sample_wh(wo, u); *wi = Reflect(wo, wh); if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); // Compute PDF of _wi_ for microfacet reflection *pdf = distribution->Pdf(wo, wh) / (4 * Dot(wo, wh)); return f(wo, *wi); }
float Heitz::Pdf(const Vector &wo, const Vector &wi) const { // TODO: for test if (mUseUniformSampling) { return SameHemisphere(wo, wi) ? AbsCosTheta(wi) * INV_PI : 0.f; } else { float pdfSpec = 0.f; if (wo.z < 0.f) { // Reverse side pdfSpec = mDistribution.Pdf(-wo, -wi); } else { pdfSpec = mDistribution.Pdf(wo, wi); } float pdfDiff = SameHemisphere(wo, wi) ? AbsCosTheta(wi) * INV_PI : 0.f; // TODO: what percentage between diffuse and specular? Currently use 50% return (pdfDiff + pdfSpec) * 0.5f; } }
Float MicrofacetTransmission::Pdf(const Vector3f &wo, const Vector3f &wi) const { if (SameHemisphere(wo, wi)) return 0; // Compute $\wh$ from $\wo$ and $\wi$ for microfacet transmission Float eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB); Vector3f wh = Normalize(wo + wi * eta); // Compute change of variables _dwh\_dwi_ for microfacet transmission Float sqrtDenom = Dot(wo, wh) + eta * Dot(wi, wh); Float dwh_dwi = std::abs((eta * eta * Dot(wi, wh)) / (sqrtDenom * sqrtDenom)); return distribution->Pdf(wo, wh) * dwh_dwi; }
float Lafortune::Pdf(const Vector &wo, const Vector &wi) const { if (!SameHemisphere(wo, wi)) return 0.f; float pdfSum = fabsf(wi.z) * INV_PI; for (u_int i = 0; i < nLobes; ++i) { float xlum = x[i].y(); float ylum = y[i].y(); float zlum = z[i].y(); Vector lobeCenter = Normalize(Vector(wo.x * xlum, wo.y * ylum, wo.z * zlum)); float e = .8f * exponent[i].y(); pdfSum += (e + 1.f) * powf(max(0.f, Dot(wi, lobeCenter)), e); } return pdfSum / (1.f + nLobes); }
// commented, dpl 10 august 2005 Spectrum FresnelBlend::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const { if (u1 < .5) { u1 = 2.f * u1; // Cosine-sample the hemisphere, flipping the direction if necessary *wi = CosineSampleHemisphere(u1, u2); if (wo.z < 0.) wi->z *= -1.f; } else { u1 = 2.f * (u1 - .5f); distribution->Sample_f(wo, wi, u1, u2, pdf); if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); } *pdf = Pdf(wo, *wi); return f(wo, *wi); }
void SampleBlinn(const Vector &wo, Vector *wi, float u1, float u2, float *pdf, float exponent) { // Compute sampled half-angle vector $\wh$ for Blinn distribution float costheta = powf(u1, 1.f / (exponent+1)); float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta)); float phi = u2 * 2.f * M_PI; Vector wh = SphericalDirection(sintheta, costheta, phi); if (!SameHemisphere(wo, wh)) wh = -wh; // Compute incident direction by reflecting about $\wh$ *wi = -wo + 2.f * Dot(wo, wh) * wh; // Compute PDF for $\wi$ from Blinn distribution float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) / (2.f * M_PI * 4.f * Dot(wo, wh)); if (Dot(wo, wh) < 0.f) blinn_pdf = 0.f; *pdf = blinn_pdf; }
Spectrum FresnelBlend::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &uOrig, Float *pdf, BxDFType *sampledType) const { Point2f u = uOrig; if (u[0] < .5) { u[0] = 2 * u[0]; // Cosine-sample the hemisphere, flipping the direction if necessary *wi = CosineSampleHemisphere(u); if (wo.z < 0) wi->z *= -1; } else { u[0] = 2 * (u[0] - .5f); // Sample microfacet orientation $\wh$ and reflected direction $\wi$ Vector3f wh = distribution->Sample_wh(wo, u); *wi = Reflect(wo, wh); if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); } *pdf = Pdf(wo, *wi); return f(wo, *wi); }
Vector3f BeckmannDistribution::Sample_wh(const Vector3f &wo, const Point2f &u) const { if (!sampleVisibleArea) { // Sample full distribution of normals for Beckmann distribution // Compute $\tan^2 \theta$ and $\phi$ for Beckmann distribution sample Float tan2Theta, phi; if (alphax == alphay) { Float logSample = std::log(u[0]); if (std::isinf(logSample)) logSample = 0; tan2Theta = -alphax * alphax * logSample; phi = u[1] * 2 * Pi; } else { // Compute _tan2Theta_ and _phi_ for anisotropic Beckmann // distribution Float logSample = std::log(u[0]); if (std::isinf(logSample)) logSample = 0; phi = std::atan(alphay / alphax * std::tan(2 * Pi * u[1] + 0.5f * Pi)); if (u[1] > 0.5f) phi += Pi; Float sinPhi = std::sin(phi), cosPhi = std::cos(phi); Float alphax2 = alphax * alphax, alphay2 = alphay * alphay; tan2Theta = -logSample / (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2); } // Map sampled Beckmann angles to normal direction _wh_ Float cosTheta = 1 / std::sqrt(1 + tan2Theta); Float sinTheta = std::sqrt(std::max((Float)0, 1 - cosTheta * cosTheta)); Vector3f wh = SphericalDirection(sinTheta, cosTheta, phi); if (!SameHemisphere(wo, wh)) wh = -wh; return wh; } else { // Sample visible area of normals with Beckmann distribution Vector3f wh; bool flip = wo.z < 0; wh = BeckmannSample(flip ? -wo : wo, alphax, alphay, u[0], u[1]); if (flip) wh = -wh; return wh; } }
//复制自PBRT void Anisotropic::Sample_f(const Vector3f &wo, Vector3f *wi, Float u1, Float u2, Float *pdf) const { Float phi, costheta; if (u1 < .25f) { sampleFirstQuadrant(4.f * u1, u2, &phi, &costheta); } else if (u1 < .5f) { u1 = 4.f * (.5f - u1); sampleFirstQuadrant(u1, u2, &phi, &costheta); phi = Pi - phi; } else if (u1 < .75f) { u1 = 4.f * (u1 - .5f); sampleFirstQuadrant(u1, u2, &phi, &costheta); phi += Pi; } else { u1 = 4.f * (1.f - u1); sampleFirstQuadrant(u1, u2, &phi, &costheta); phi = 2.f * Pi - phi; } Float sintheta = sqrtf(std::max(0.f, 1.f - costheta * costheta)); Vector3f wh = SphericalDirection(sintheta, costheta, phi); if (!SameHemisphere(wo, wh)) wh = -wh; // Compute incident direction by reflecting about $\wh$ *wi = -wo + 2.f * Dot(wo, wh) * wh; // Compute PDF for $\wi$ from anisotropic distribution Float costhetah = AbsCosTheta(wh); Float ds = 1.f - costhetah * costhetah; Float anisotropic_pdf = 0.f; if (ds > 0.f && Dot(wo, wh) > 0.f) { Float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds; Float d = sqrtf((ex + 1.f) * (ey + 1.f)) * InvTwoPi * powf(costhetah, e); anisotropic_pdf = d / (4.f * Dot(wo, wh)); } *pdf = anisotropic_pdf; }
// BxDF Method Definitions bool BxDF::SampleF(const SpectrumWavelengths &sw, const Vector &wo, Vector *wi, float u1, float u2, SWCSpectrum *const f, float *pdf, float *pdfBack, bool reverse) const { // Cosine-sample the hemisphere, flipping the direction if necessary *wi = CosineSampleHemisphere(u1, u2); if (wo.z < 0.f) wi->z = -(wi->z); // wi may be in the tangent plane, which will // fail the SameHemisphere test in Pdf() if (!SameHemisphere(wo, *wi)) return false; *pdf = Pdf(sw, wo, *wi); if (pdfBack) *pdfBack = Pdf(sw, *wi, wo); *f = SWCSpectrum(0.f); if (reverse) F(sw, *wi, wo, f); else F(sw, wo, *wi, f); *f /= *pdf; return true; }
Spectrum MicrofacetTransmission::f(const Vector3f &wo, const Vector3f &wi) const { if (SameHemisphere(wo, wi)) return 0; // transmission only Float cosThetaO = CosTheta(wo); Float cosThetaI = CosTheta(wi); if (cosThetaI == 0 || cosThetaO == 0) return Spectrum(0); // Compute $\wh$ from $\wo$ and $\wi$ for microfacet transmission Float eta = CosTheta(wo) > 0 ? (etaB / etaA) : (etaA / etaB); Vector3f wh = Normalize(wo + wi * eta); if (wh.z < 0) wh = -wh; Spectrum F = fresnel.Evaluate(Dot(wo, wh)); Float sqrtDenom = Dot(wo, wh) + eta * Dot(wi, wh); Float factor = (mode == TransportMode::Radiance) ? (1 / eta) : 1; return (Spectrum(1.f) - F) * T * std::abs(distribution->D(wh) * distribution->G(wo, wi) * eta * eta * AbsDot(wi, wh) * AbsDot(wo, wh) * factor * factor / (cosThetaI * cosThetaO * sqrtDenom * sqrtDenom)); }
Float BxDF::Pdf(const Vector3f &wo, const Vector3f &wi) const { return SameHemisphere(wo, wi) ? AbsCosTheta(wi) * InvPi : 0; }
float BxDF::Pdf(const Vector &wo, const Vector &wi) const { return SameHemisphere(wo, wi) ? fabsf(wi.z) * INV_PI : 0.f; }
float BxDF::Pdf(const SpectrumWavelengths &sw, const Vector &wo, const Vector &wi) const { return SameHemisphere(wo, wi) ? fabsf(wi.z) * INV_PI : 0.f; }
Float FresnelBlend::Pdf(const Vector3f &wo, const Vector3f &wi) const { if (!SameHemisphere(wo, wi)) return 0; Vector3f wh = Normalize(wo + wi); Float pdf_wh = distribution->Pdf(wo, wh); return .5f * (AbsCosTheta(wi) * InvPi + pdf_wh / (4 * Dot(wo, wh))); }
Spectrum Microfacet::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf) const { distribution->Sample_f(wo, wi, u1, u2, pdf); if (!SameHemisphere(wo, *wi)) return Spectrum(0.f); return f(wo, *wi); }
float Microfacet::Pdf(const Vector &wo, const Vector &wi) const { if (!SameHemisphere(wo, wi)) return 0.f; return distribution->Pdf(wo, wi); }
Float MicrofacetReflection::Pdf(const Vector3f &wo, const Vector3f &wi) const { if (!SameHemisphere(wo, wi)) return 0; Vector3f wh = Normalize(wo + wi); return distribution->Pdf(wo, wh) / (4 * Dot(wo, wh)); }
float FresnelBlend::Pdf(const Vector &wo, const Vector &wi) const { if (!SameHemisphere(wo, wi)) return 0.f; return .5f * (fabsf(wi.z) * INV_PI + distribution->Pdf(wo, wi)); }
// the pdf for the sampled direction float Bxdf::Pdf( const Vector& wo , const Vector& wi ) const { if( !SameHemisphere( wo , wi ) ) return 0.0f; return fabs(CosHemispherePdf( wi )); }
Float LambertianTransmission::Pdf(const Vector3f &wo, const Vector3f &wi) const { return !SameHemisphere(wo, wi) ? AbsCosTheta(wi) * InvPi : 0; }