Float fresnel(Float cosThetaI, Float etaExt, Float etaInt) { Float etaI = etaExt, etaT = etaInt; /* Swap the indices of refraction if the interaction starts at the inside of the object */ if (cosThetaI < 0.0f) std::swap(etaI, etaT); /* Using Snell's law, calculate the sine of the angle between the transmitted ray and the surface normal */ Float sinThetaT = etaI / etaT * std::sqrt(std::max((Float) 0.0f, 1.0f - cosThetaI*cosThetaI)); if (sinThetaT > 1.0f) return 1.0f; /* Total internal reflection! */ Float cosThetaT = std::sqrt(1.0f - sinThetaT*sinThetaT); /* Finally compute the reflection coefficient */ return fresnelDielectric(std::abs(cosThetaI), cosThetaT, etaI, etaT); }
Float microfacet(Float mu_o, Float mu_i, std::complex<Float> eta_, Float alpha, Float phi_d) { Float sinThetaI = math::safe_sqrt(1-mu_i*mu_i), sinThetaO = math::safe_sqrt(1-mu_o*mu_o), cosPhi = std::cos(phi_d), sinPhi = std::sin(phi_d); Vector wi(-sinThetaI, 0, -mu_i); Vector wo(sinThetaO*cosPhi, sinThetaO*sinPhi, mu_o); bool reflect = -mu_i*mu_o > 0; if (mu_o == 0 || mu_i == 0) return 0.f; bool conductor = eta_.imag() != 0.0f; if (conductor && !reflect) return 0.0f; std::complex<Float> eta = (-mu_i > 0 || conductor) ? eta_ : std::complex<Float>(1) / eta_; Vector H = (wi + wo * (reflect ? 1.0f : eta.real())).normalized(); H *= math::signum(Frame::cosTheta(H)); Float cosThetaH2 = Frame::cosTheta2(H), exponent = -Frame::tanTheta2(H) / (alpha*alpha), D = std::exp(exponent) / (math::Pi * alpha*alpha * cosThetaH2*cosThetaH2), F = !conductor ? fresnelDielectric(wi.dot(H), eta_.real()) : fresnelConductor(std::abs(wi.dot(H)), eta), G = smithG1(wi, H, alpha) * smithG1(wo, H, alpha); if (reflect) { return F * D * G / (4.0f * std::abs(mu_i*mu_o)); } else { Float sqrtDenom = wi.dot(H) + eta.real() * wo.dot(H); return std::abs(((1 - F) * D * G * eta.real() * eta.real() * wi.dot(H) * wo.dot(H)) / (mu_i*mu_o * sqrtDenom * sqrtDenom)); } }
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const { bool sampleReflection = (bRec.typeMask & EDeltaReflection) && (bRec.component == -1 || bRec.component == 0); bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) && (bRec.component == -1 || bRec.component == 1); if (!sampleTransmission && !sampleReflection) return Spectrum(0.0f); Float cosThetaI = Frame::cosTheta(bRec.wi), etaI = m_extIOR, etaT = m_intIOR; bool entering = cosThetaI > 0.0f; /* Determine the respective indices of refraction */ if (!entering) std::swap(etaI, etaT); /* Using Snell's law, calculate the squared sine of the angle between the normal and the transmitted ray */ Float eta = etaI / etaT, sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi); Float Fr, cosThetaT = 0; if (sinThetaTSqr >= 1.0f) { /* Total internal reflection */ Fr = 1.0f; } else { cosThetaT = std::sqrt(1.0f - sinThetaTSqr); /* Compute the Fresnel refletance */ Fr = fresnelDielectric(std::abs(cosThetaI), cosThetaT, etaI, etaT); if (entering) cosThetaT = -cosThetaT; } /* Calculate the refracted/reflected vectors+coefficients */ if (sampleTransmission && sampleReflection) { /* Importance sample according to the reflectance/transmittance */ if (sample.x <= Fr) { bRec.sampledComponent = 0; bRec.sampledType = EDeltaReflection; bRec.wo = reflect(bRec.wi); pdf = Fr * std::abs(Frame::cosTheta(bRec.wo)); return m_specularReflectance->getValue(bRec.its) * Fr; } else { bRec.sampledComponent = 1; bRec.sampledType = EDeltaTransmission; /* Given cos(N, transmittedRay), compute the transmitted direction */ bRec.wo = refract(bRec.wi, eta, cosThetaT); pdf = (1-Fr) * std::abs(Frame::cosTheta(bRec.wo)); /* When transporting radiance, account for the solid angle change at boundaries with different indices of refraction. */ return m_specularTransmittance->getValue(bRec.its) * (1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1); } } else if (sampleReflection) { bRec.sampledComponent = 0; bRec.sampledType = EDeltaReflection; bRec.wo = reflect(bRec.wi); pdf = std::abs(Frame::cosTheta(bRec.wo)); return m_specularReflectance->getValue(bRec.its) * Fr; } else { bRec.sampledComponent = 1; bRec.sampledType = EDeltaTransmission; if (Fr == 1.0f) /* Total internal reflection */ return Spectrum(0.0f); bRec.wo = refract(bRec.wi, eta, cosThetaT); pdf = std::abs(Frame::cosTheta(bRec.wo)); /* When transporting radiance, account for the solid angle change at boundaries with different indices of refraction. */ return m_specularTransmittance->getValue(bRec.its) * ((1-Fr) * (bRec.quantity == ERadiance ? (eta*eta) : (Float) 1)); } }