Float MicrofacetDistribution::Pdf(const Vector3f &wo, const Vector3f &wh) const { if (sampleVisibleArea) return D(wh) * G1(wo) * AbsDot(wo, wh) / AbsCosTheta(wo); else return D(wh) * AbsCosTheta(wh); }
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 Microfacet::G(const Vector &wo, const Vector &wi, const Vector &wh) const { float NdotWh = AbsCosTheta(wh); //半角和法线之间的cos值 相当于是点乘 float NdotWo = AbsCosTheta(wo); //出射方向与法线 float NdotWi = AbsCosTheta(wi); //入射方向与法线 float WodotWh = AbsDot(wh, wo); //出射和半角向量之间的点乘 return min(1.0f, min((2.f * NdotWh * NdotWo / WodotWh), (2.f * NdotWh * NdotWi / WodotWh))); }
Spectrum MicrofacetReflection::f(const Vector3f &wo, const Vector3f &wi) const { Float cosThetaO = AbsCosTheta(wo), cosThetaI = AbsCosTheta(wi); Vector3f wh = wi + wo; // Handle degenerate cases for microfacet reflection if (cosThetaI == 0 || cosThetaO == 0) return Spectrum(0.); if (wh.x == 0 && wh.y == 0 && wh.z == 0) return Spectrum(0.); wh = Normalize(wh); Spectrum F = fresnel->Evaluate(Dot(wi, wh)); return R * distribution->D(wh) * distribution->G(wo, wi) * F / (4 * cosThetaI * cosThetaO); }
RGBColour BxDF::Rho(int p_nSamples, const float* p_samples1, const float* p_samples2) const{ RGBColour r = 0.; for (int i = 0; i < p_nSamples; ++i){ /* Estimate one term of p_hd */ Vector3 wo,wi; wo = MonteCarlo::UniformSampleHemisphere(p_samples1[2 * i], p_samples1[2 * i + 1]); float pdf_o = Maths::InvPiTwo, pdf_i = 0.f; RGBColour f = Sample_F(wo, wi, p_samples2[2 * i], p_samples2[2 * i + 1], pdf_i); if (pdf_i > 0.) r += f * AbsCosTheta(wi) * AbsCosTheta(wo) / (pdf_o * pdf_i); } return r / float(Maths::Pi * p_nSamples); }
Spectrum BxDF::rho(int nSamples, const Point2f *u1, const Point2f *u2) const { Spectrum r(0.f); for (int i = 0; i < nSamples; ++i) { // Estimate one term of $\rho_\roman{hh}$ Vector3f wo, wi; wo = UniformSampleHemisphere(u1[i]); Float pdfo = UniformHemispherePdf(), pdfi = 0; Spectrum f = Sample_f(wo, &wi, u2[i], &pdfi); if (pdfi > 0) r += f * AbsCosTheta(wi) * AbsCosTheta(wo) / (pdfo * pdfi); } return r / (Pi * nSamples); }
Spectrum FresnelBlend::f(const Vector3f &wo, const Vector3f &wi) const { auto pow5 = [](Float v) { return (v * v) * (v * v) * v; }; Spectrum diffuse = (28.f / (23.f * Pi)) * Rd * (Spectrum(1.f) - Rs) * (1 - pow5(1 - .5f * AbsCosTheta(wi))) * (1 - pow5(1 - .5f * AbsCosTheta(wo))); Vector3f wh = wi + wo; if (wh.x == 0 && wh.y == 0 && wh.z == 0) return Spectrum(0); wh = Normalize(wh); Spectrum specular = distribution->D(wh) / (4 * AbsDot(wi, wh) * std::max(AbsCosTheta(wi), AbsCosTheta(wo))) * SchlickFresnel(Dot(wi, wh)); return diffuse + specular; }
//这里使用的就是Torrance-Sparrow Modle的公式 RGB Microfacet::f(const Vector &wo, const Vector &wi) const { float cosO = AbsCosTheta(wo); if (cosO == 0) return RGB(0); float cosI = AbsCosTheta(wi); if (cosI == 0) return RGB(0); Vector wh = wi + wo; if (wh.x == 0 && wh.y == 0 && wh.z == 0) return RGB(0); wh = Normalize(wh); float cosH = Dot(wi, wh); RGB F = mFresnel->Evaluate(cosH); return mR * F * mDistribution->D(wh) * G(wo, wi, wh) / (4.0f * cosO * cosI); }
struct Spectrum SpecularReflection_cc_Sample_f(struct const_Vector wo, struct Vector *wi, float u1, float u2, float *pdf) { // Compute perfect specular reflection direction *wi = make_Vector(-wo.x, -wo.y, wo.z); *pdf = 1.f; struct Spectrum tmp1 = multiply(fresnel_arrow_Evaluate(CosTheta(wo)), make_Spectrum(R)); return div(tmp1, make_Spectrum(AbsCosTheta(*wi))); }
Spectrum KajiyaKay::f(const Vector3f &wo, const Vector3f &wi) const { Spectrum diffuse(0.f), specular(0.f); if (!Ks.IsBlack()) { // Compute specular Kajiya-Kay term Vector3f wh = wi + wo; if (!(wh.x == 0 && wh.y == 0 && wh.z == 0)) { wh = Normalize(wh); #if 0 Float cosThetaH = Dot(wo, wh); Float sinThetaH = std::sqrt(std::max((Float)0, (Float)1 - cosThetaH * cosThetaH)); Float cosThetaO = CosTheta(wo), sinThetaO = SinTheta(wo); Float spec = std::pow(cosThetao * cosThetah + sinThetaO * sinThetaH, exponent); #else Float tdoth = wh.x; Float spec = std::pow( std::sqrt(std::max((Float)0, (Float)1 - tdoth * tdoth)), exponent); #endif specular = spec * Ks; } } // Compute diffuse Kajiya-Kay term diffuse = Kd * std::sqrt(std::max((Float)0., (Float)1. - wi.x * wi.x)); return (InvPi / AbsCosTheta(wi)) * (diffuse + specular); }
struct Spectrum SpecularReflection_cc_Sample_f(const_Vector wo, Vector *wi, float u1, float u2, float *pdf) { // return 0;// mgr // return 1;//mgr // Compute perfect specular reflection direction *wi = make_Vector(-wo.x, -wo.y, wo.z); *pdf = 1.f; return make_Spectrum(fresnel__Evaluate(CosTheta(wo)) * R / AbsCosTheta(*wi)); }
Spectrum SpecularReflection::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &sample, Float *pdf, BxDFType *sampledType) const { // Compute perfect specular reflection direction *wi = Vector3f(-wo.x, -wo.y, wo.z); *pdf = 1; return fresnel->Evaluate(CosTheta(*wi)) * R / AbsCosTheta(*wi); }
Spectrum Heitz::f(const Vector &woInput, const Vector &wiInput) const { // In PBRT's implementation, woInput and wiInput is not guaranteed to be at the same side of the shading normal // We inverse them if woInput is on the other side. // Note: because BSDF::f() determines BSDF_REFLECTION and BSDF_TRANSMISSION using ng (geometric normal) instead // of nn (shading normal), it's possible that woInput and wiInput has opposite sign of z-axis. Therefore, // we determine if the shading normal is at the opposite side using woInput (viewing direction) only: we // always make the viewing direction from the +Z side Vector wo = woInput, wi = wiInput; if (wo.z < 0.f) { // Reverse side wo = -wo; wi = -wi; } float cosThetaO = CosTheta(wo), absCosThetaI = AbsCosTheta(wi); Assert(cosThetaO >= 0.f); if (cosThetaO < sSmallValue || absCosThetaI < sSmallValue) { return Spectrum(0.f); } Vector wh = wi + wo; if (wh.x == 0. && wh.y == 0. && wh.z == 0.) { return Spectrum(0.f); } wh = Normalize(wh); float i_dot_h = Dot(wi, wh); Spectrum F = fresnel->Evaluate(i_dot_h); // Specular/glossy component float spec = mDistribution.D(wh) * mDistribution.G(wo, wi, wh) / (4.f * cosThetaO * absCosThetaI); // Diffuse component Spectrum Fdiff = Spectrum(1.f) - fresnel->Evaluate(cosThetaO); float diff = wi.z > 0.f ? INV_PI : 0.f; // TODO: test //F = Spectrum(1.f); // Note wi is possible to be at lower hemisphere, so we need to use // AbsCosTheta() //return R * (F * spec + (Spectrum(1.f) - F) * diff); return R * (F * spec + Fdiff * diff); // TODO: test /*float Dval = mDistribution.D(wh), Gval = mDistribution.G(wo, wi, wh); Spectrum val = R * Dval * Gval * F / (4.f * cosThetaO * absCosThetaI); if (isinf(val.y()) || val.y() < -sSmallValue) { fprintf(stderr, "invalid value\n"); } return val;*/ }
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; }
RGBColour BxDF::Rho(const Vector3& p_w, int p_nSamples, const float* p_samples) const{ RGBColour r = 0.; for (int i = 0; i < p_nSamples; ++i){ /* Estimate one term of p_hd */ Vector3 wi; float pdf = 0.f; RGBColour f = Sample_F(p_w, wi, p_samples[2 * i], p_samples[2 * i + 1], pdf); if (pdf > 0.) r += f * AbsCosTheta(wi) / pdf; } return r / float(p_nSamples); }
Spectrum BxDF::rho(const Vector3f &w, int nSamples, const Point2f *u) const { Spectrum r(0.); for (int i = 0; i < nSamples; ++i) { // Estimate one term of $\rho_\roman{hd}$ Vector3f wi; Float pdf = 0; Spectrum f = Sample_f(w, &wi, u[i], &pdf); if (pdf > 0) r += f * AbsCosTheta(wi) / pdf; } return r / nSamples; }
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; } }
//复制自PBRT float Anisotropic::Pdf(const Vector &wo, const Vector &wi) const { Vector wh = Normalize(wo + wi); 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)) * M_INV_TWO_PI * powf(costhetah, e); anisotropic_pdf = d / (4.f * Dot(wo, wh)); } return anisotropic_pdf; }
Spectrum OrenNayar::f(const Vector3f &wo, const Vector3f &wi) const { Float sinThetaI = SinTheta(wi); Float sinThetaO = SinTheta(wo); // Compute cosine term of Oren-Nayar model Float maxCos = 0; if (sinThetaI > 1e-4 && sinThetaO > 1e-4) { Float sinPhiI = SinPhi(wi), cosPhiI = CosPhi(wi); Float sinPhiO = SinPhi(wo), cosPhiO = CosPhi(wo); Float dCos = cosPhiI * cosPhiO + sinPhiI * sinPhiO; maxCos = std::max((Float)0, dCos); } // Compute sine and tangent terms of Oren-Nayar model Float sinAlpha, tanBeta; if (AbsCosTheta(wi) > AbsCosTheta(wo)) { sinAlpha = sinThetaO; tanBeta = sinThetaI / AbsCosTheta(wi); } else { sinAlpha = sinThetaI; tanBeta = sinThetaO / AbsCosTheta(wo); } return R * InvPi * (A + B * maxCos * sinAlpha * tanBeta); }
Spectrum SpecularTransmission::Sample_f(const Vector3f &wo, Vector3f *wi, const Point2f &sample, Float *pdf, BxDFType *sampledType) const { // 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; *pdf = 1; Spectrum ft = T * (Spectrum(1.) - fresnel.Evaluate(CosTheta(*wi))); // Account for non-symmetry with transmission to different medium if (mode == TransportMode::Radiance) ft *= (etaI * etaI) / (etaT * etaT); return ft / AbsCosTheta(*wi); }
RGB SpecularTransmission::Sample_f(const Vector& wo, Vector* wi, float u1, float u2, float *pdf) const { bool entering = CosTheta(wo) > 0.; float ei = mEtaI, et = mEtaT; if (!entering) //判断wo是从外面射入还是从内部射出 swap(ei, et); //根据Snell's law 计算折射方向 float sini2 = SinTheta2(wo); float eta = ei / et; float sint2 = eta * eta * sini2; if (sint2 >= 1.) return 0.; //所有的光线全部反射,所以没有折射 float cost = sqrtf(max(0.f, 1.f - sint2)); if (entering) cost = -cost; //设置符号 float sintOverSini = eta; *wi = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, cost); *pdf = 1.f; RGB F = mFresnel.Evaluate(CosTheta(wo)); //计算反射系数 return (ei * ei) / (et * et) * (RGB(1.0f) - F) * mScale / AbsCosTheta(*wi); }
//复制自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; }
Float BxDF::Pdf(const Vector3f &wo, const Vector3f &wi) const { return SameHemisphere(wo, wi) ? AbsCosTheta(wi) * InvPi : 0; }
RGB SpecularReflection::Sample_f(const Vector& wo, Vector* wi, float u1, float u2, float *pdf) const { *wi = Vector(-wo.x, -wo.y, wo.z); //反射向量 *pdf = 1.f; //概率分布为1 return mFresnel->Evaluate(CosTheta(wo)) * mScale / AbsCosTheta(*wi); //镜面反射的brdf公式 }
Float LambertianTransmission::Pdf(const Vector3f &wo, const Vector3f &wi) const { return !SameHemisphere(wo, wi) ? AbsCosTheta(wi) * InvPi : 0; }
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))); }