Spectrum FresnelSpecular::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &u, Float *pdf, BxDFType *sampledType) const { Float F = FrDielectric(CosTheta(wo), etaA, etaB); if (u[0] < F) { // Compute specular reflection for _FresnelSpecular_ // Compute perfect specular reflection direction *wi = Vector3f(-wo.x, -wo.y, wo.z); if (sampledType) *sampledType = BxDFType(BSDF_SPECULAR | BSDF_REFLECTION); *pdf = F; return F * R / AbsCosTheta(*wi); } else { // Compute specular transmission for _FresnelSpecular_ // Figure out which $\eta$ is incident and which is transmitted bool entering = CosTheta(wo) > 0; Float etaI = entering ? etaA : etaB; Float etaT = entering ? etaB : etaA; // Compute ray direction for specular transmission if (!Refract(wo, Faceforward(Normal3f(0, 0, 1), wo), etaI / etaT, wi)) return 0; Spectrum ft = T * (1 - F); // Account for non-symmetry with transmission to different medium if (mode == TransportMode::Radiance) ft *= (etaI * etaI) / (etaT * etaT); if (sampledType) *sampledType = BxDFType(BSDF_SPECULAR | BSDF_TRANSMISSION); *pdf = 1 - F; return ft / AbsCosTheta(*wi); } }
Float BeamDiffusionSS(Float sigma_s, Float sigma_a, Float g, Float eta, Float r) { // Compute material parameters and minimum $t$ below the critical angle Float sigma_t = sigma_a + sigma_s, rho = sigma_s / sigma_t; Float tCrit = r * std::sqrt(eta * eta - 1); Float Ess = 0; const int nSamples = 100; for (int i = 0; i < nSamples; ++i) { // Evaluate single scattering integrand and add to _Ess_ Float ti = tCrit - std::log(1 - (i + .5f) / nSamples) / sigma_t; // Determine length $d$ of connecting segment and $\cos\theta_\roman{o}$ Float d = std::sqrt(r * r + ti * ti); Float cosThetaO = ti / d; // Add contribution of single scattering at depth $t$ Ess += rho * std::exp(-sigma_t * (d + tCrit)) / (d * d) * PhaseHG(cosThetaO, g) * (1 - FrDielectric(-cosThetaO, 1, eta)) * std::abs(cosThetaO); } return Ess / nSamples; }
Spectrum FresnelDielectric::Evaluate(Float cosThetaI) const { return FrDielectric(cosThetaI, etaI, etaT); }