00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "bxdf.h"
00025 #include "spectrum.h"
00026 #include "spectrumwavelengths.h"
00027 #include "mc.h"
00028 #include "sampling.h"
00029
00030 using namespace lux;
00031
00032
00033 void BRDFToBTDF::f(const TsPack *tspack, const Vector &wo,
00034 const Vector &wi, SWCSpectrum *const f_) const
00035 {
00036 if (etai == etat) {
00037 brdf->f(tspack, wo, otherHemisphere(wi), f_);
00038 return;
00039 }
00040
00041 const bool entering = CosTheta(wo) > 0.f;
00042 float ei = etai, et = etat;
00043
00044 if(cb != 0.f) {
00045
00046 const float w = tspack->swl->SampleSingle();
00047 et += (cb * 1000000.f) / (w * w);
00048 }
00049
00050 if (!entering)
00051 swap(ei, et);
00052
00053 const float eta = ei / et;
00054 Vector H(Normalize(eta * wo + wi));
00055 const float cos1 = Dot(wo, H);
00056 if ((entering && cos1 < 0.f) || (!entering && cos1 > 0.f))
00057 H = -H;
00058 if (H.z < 0.f)
00059 return;
00060 Vector wiR(2.f * cos1 * H - wo);
00061 SWCSpectrum tf(0.f);
00062 brdf->f(tspack, wo, wiR, &tf);
00063 tf *= fabsf(wiR.z / wi.z);
00064 *f_ += tf;
00065 }
00066 bool BRDFToBTDF::Sample_f(const TsPack *tspack, const Vector &wo, Vector *wi,
00067 float u1, float u2, SWCSpectrum *const f_, float *pdf, float *pdfBack,
00068 bool reverse) const
00069 {
00070 if (etai == etat) {
00071 if (!brdf->Sample_f(tspack, wo, wi, u1, u2, f_, pdf, pdfBack, reverse))
00072 return false;
00073 *wi = otherHemisphere(*wi);
00074 return true;
00075 }
00076 if (!brdf->Sample_f(tspack, wo, wi, u1, u2, f_, pdf, pdfBack, reverse))
00077 return false;
00078 Vector H(Normalize(wo + *wi));
00079 if (H.z < 0.f)
00080 H = -H;
00081 const float cosi = Dot(wo, H);
00082
00083 const bool entering = cosi > 0.f;
00084 float ei = etai, et = etat;
00085
00086 if(cb != 0.f) {
00087
00088 const float w = tspack->swl->SampleSingle();
00089 et += (cb * 1000000.f) / (w * w);
00090 }
00091
00092 if (!entering)
00093 swap(ei, et);
00094
00095 const float sini2 = max(0.f, 1.f - cosi * cosi);
00096 const float eta = ei / et;
00097 const float eta2 = eta * eta;
00098 const float sint2 = eta2 * sini2;
00099
00100 if (sint2 > 1.f) {
00101 *pdf = 0.f;
00102 if (pdfBack)
00103 *pdfBack = 0.f;
00104 return false;
00105 }
00106 float cost = sqrtf(max(0.f, 1.f - sint2));
00107 if (entering)
00108 cost = -cost;
00109 float factor = wi->z;
00110 *wi = (cost + eta * cosi) * H - eta * wo;
00111 factor /= wi->z;
00112 if (reverse)
00113 *f_ *= fabsf(factor) * eta2;
00114 else
00115 *f_ *= fabsf(factor);
00116 return true;
00117 }
00118
00119 bool BxDF::Sample_f(const TsPack *tspack, const Vector &wo, Vector *wi,
00120 float u1, float u2, SWCSpectrum *const f_, float *pdf, float *pdfBack,
00121 bool reverse) const
00122 {
00123
00124 *wi = CosineSampleHemisphere(u1, u2);
00125 if (wo.z < 0.f) wi->z *= -1.f;
00126
00127
00128 if (!SameHemisphere(wo, *wi))
00129 return false;
00130 *pdf = Pdf(tspack, wo, *wi);
00131 if (pdfBack)
00132 *pdfBack = Pdf(tspack, *wi, wo);
00133 *f_ = SWCSpectrum(0.f);
00134 if (reverse) {
00135 this->f(tspack, *wi, wo, f_);
00136 }
00137 else
00138 this->f(tspack, wo, *wi, f_);
00139 return true;
00140 }
00141 float BxDF::Pdf(const TsPack *tspack, const Vector &wo, const Vector &wi) const {
00142 return SameHemisphere(wo, wi) ? fabsf(wi.z) * INV_PI : 0.f;
00143 }
00144 float BRDFToBTDF::Pdf(const TsPack *tspack, const Vector &wo,
00145 const Vector &wi) const
00146 {
00147 if (etai == etat)
00148 return brdf->Pdf(tspack, wo, otherHemisphere(wi));
00149
00150 const bool entering = CosTheta(wo) > 0.f;
00151 float ei = etai, et = etat;
00152
00153 if(cb != 0.f) {
00154
00155 const float w = tspack->swl->SampleSingle();
00156 et += (cb * 1000000.f) / (w * w);
00157 }
00158
00159 if (!entering)
00160 swap(ei, et);
00161
00162 const float eta = ei / et;
00163 Vector H(Normalize(eta * wo + wi));
00164 const float cos1 = Dot(wo, H);
00165 if ((entering && cos1 < 0.f) || (!entering && cos1 > 0.f))
00166 H = -H;
00167 if (H.z < 0.f)
00168 return 0.f;
00169 return brdf->Pdf(tspack, wo, 2.f * Dot(wo, H) * H - wo);
00170 }
00171
00172 SWCSpectrum BxDF::rho(const TsPack *tspack, const Vector &w, int nSamples,
00173 float *samples) const {
00174 if (!samples) {
00175 samples =
00176 (float *)alloca(2 * nSamples * sizeof(float));
00177 LatinHypercube(tspack, samples, nSamples, 2);
00178 }
00179 SWCSpectrum r(0.f);
00180 for (int i = 0; i < nSamples; ++i) {
00181
00182 Vector wi;
00183 float pdf = 0.f;
00184 SWCSpectrum f_(0.f);
00185 if (Sample_f(tspack, w, &wi, samples[2*i], samples[2*i+1], &f_, &pdf) && pdf > 0.f)
00186 r.AddWeighted(fabsf(wi.z) / pdf, f_);
00187 }
00188 return r / nSamples;
00189 }
00190 SWCSpectrum BxDF::rho(const TsPack *tspack, int nSamples, float *samples) const {
00191 if (!samples) {
00192 samples =
00193 (float *)alloca(4 * nSamples * sizeof(float));
00194 LatinHypercube(tspack, samples, nSamples, 4);
00195 }
00196 SWCSpectrum r(0.f);
00197 for (int i = 0; i < nSamples; ++i) {
00198
00199 Vector wo, wi;
00200 wo = UniformSampleHemisphere(samples[4*i], samples[4*i+1]);
00201 float pdf_o = INV_TWOPI, pdf_i = 0.f;
00202 SWCSpectrum f_(0.f);
00203 if (Sample_f(tspack, wo, &wi, samples[4*i+2], samples[4*i+3], &f_, &pdf_i) && pdf_i > 0.f)
00204 r.AddWeighted(fabsf(wi.z * wo.z) / (pdf_o * pdf_i), f_);
00205 }
00206 return r / (M_PI*nSamples);
00207 }
00208 float BxDF::Weight(const TsPack *tspack, const Vector &wo) const
00209 {
00210 return 1.f;
00211 }
00212 BSDF::BSDF(const DifferentialGeometry &dg, const Normal &ngeom, float e)
00213 : dgShading(dg), eta(e)
00214 {
00215 ng = ngeom;
00216 nn = dgShading.nn;
00217 sn = Normalize(dgShading.dpdu);
00218 tn = Cross(nn, sn);
00219 compParams = NULL;
00220 }
00221 bool SingleBSDF::Sample_f(const TsPack *tspack, const Vector &woW, Vector *wiW,
00222 float u1, float u2, float u3, SWCSpectrum *const f_, float *pdf,
00223 BxDFType flags, BxDFType *sampledType, float *pdfBack,
00224 bool reverse) const
00225 {
00226 BOOST_ASSERT(bxdf);
00227 if (bxdf->MatchesFlags(flags)) {
00228
00229 Vector wi;
00230 if (bxdf->Sample_f(tspack, WorldToLocal(woW), &wi, u1, u2, f_,
00231 pdf, pdfBack, reverse)) {
00232 if (sampledType)
00233 *sampledType = bxdf->type;
00234 *wiW = LocalToWorld(wi);
00235 const float sideTest = Dot(*wiW, ng) * Dot(woW, ng);
00236 if (sideTest > 0.f) {
00237
00238 if (bxdf->type & BSDF_TRANSMISSION)
00239 return false;
00240 } else if (sideTest < 0.f) {
00241
00242 if (bxdf->type & BSDF_REFLECTION)
00243 return false;
00244 } else
00245 return false;
00246 return true;
00247 }
00248 }
00249 *pdf = 0.f;
00250 if (pdfBack)
00251 *pdfBack = 0.f;
00252 return false;
00253 }
00254 float SingleBSDF::Pdf(const TsPack *tspack, const Vector &woW,
00255 const Vector &wiW, BxDFType flags) const
00256 {
00257 if (!bxdf->MatchesFlags(flags))
00258 return 0.f;
00259 return bxdf->Pdf(tspack, WorldToLocal(woW), WorldToLocal(wiW));
00260 }
00261
00262 SWCSpectrum SingleBSDF::f(const TsPack *tspack, const Vector &woW,
00263 const Vector &wiW, BxDFType flags) const
00264 {
00265 const float sideTest = Dot(wiW, ng) * Dot(woW, ng);
00266 if (sideTest > 0.f)
00267
00268 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00269 else if (sideTest < 0.f)
00270
00271 flags = BxDFType(flags & ~BSDF_REFLECTION);
00272 else
00273 flags = static_cast<BxDFType>(0);
00274 if (!bxdf->MatchesFlags(flags))
00275 return SWCSpectrum(0.f);
00276 SWCSpectrum f_(0.f);
00277 bxdf->f(tspack, WorldToLocal(woW), WorldToLocal(wiW), &f_);
00278 return f_;
00279 }
00280 SWCSpectrum SingleBSDF::rho(const TsPack *tspack, BxDFType flags) const
00281 {
00282 if (!bxdf->MatchesFlags(flags))
00283 return SWCSpectrum(0.f);
00284 return bxdf->rho(tspack);
00285 }
00286 SWCSpectrum SingleBSDF::rho(const TsPack *tspack, const Vector &woW,
00287 BxDFType flags) const
00288 {
00289 if (!bxdf->MatchesFlags(flags))
00290 return SWCSpectrum(0.f);
00291 return bxdf->rho(tspack, WorldToLocal(woW));
00292 }
00293 MultiBSDF::MultiBSDF(const DifferentialGeometry &dg, const Normal &ngeom,
00294 float e) : BSDF(dg, ngeom, e)
00295 {
00296 nBxDFs = 0;
00297 }
00298 bool MultiBSDF::Sample_f(const TsPack *tspack, const Vector &woW, Vector *wiW,
00299 float u1, float u2, float u3, SWCSpectrum *const f_, float *pdf,
00300 BxDFType flags, BxDFType *sampledType, float *pdfBack,
00301 bool reverse) const
00302 {
00303 float weights[MAX_BxDFS];
00304
00305 Vector wo(WorldToLocal(woW));
00306 u_int matchingComps = 0;
00307 float totalWeight = 0.f;
00308 for (int i = 0; i < nBxDFs; ++i) {
00309 if (bxdfs[i]->MatchesFlags(flags)) {
00310 weights[i] = bxdfs[i]->Weight(tspack, wo);
00311 totalWeight += weights[i];
00312 ++matchingComps;
00313 } else
00314 weights[i] = 0.f;
00315 }
00316 if (matchingComps == 0 || !(totalWeight > 0.f)) {
00317 *pdf = 0.f;
00318 if (pdfBack)
00319 *pdfBack = 0.f;
00320 return false;
00321 }
00322 u3 *= totalWeight;
00323 int which = 0;
00324 for (int i = 0; i < nBxDFs; ++i) {
00325 if (weights[i] > 0.f) {
00326 which = i;
00327 u3 -= weights[i];
00328 if (u3 < 0.f) {
00329 break;
00330 }
00331 }
00332 }
00333 BxDF *bxdf = bxdfs[which];
00334 BOOST_ASSERT(bxdf);
00335
00336 Vector wi;
00337 *pdf = 0.f;
00338 if (pdfBack)
00339 *pdfBack = 0.f;
00340 if (!bxdf->Sample_f(tspack, wo, &wi, u1, u2, f_, pdf, pdfBack, reverse))
00341 return false;
00342 if (sampledType) *sampledType = bxdf->type;
00343 *wiW = LocalToWorld(wi);
00344 *pdf *= weights[which];
00345 float totalWeightR = bxdfs[which]->Weight(tspack, wi);
00346 if (pdfBack)
00347 *pdfBack *= totalWeightR;
00348
00349
00350 const float sideTest = Dot(*wiW, ng) * Dot(woW, ng);
00351 BxDFType flags2;
00352 if (sideTest > 0.f)
00353
00354 flags2 = BxDFType(flags & ~BSDF_TRANSMISSION);
00355 else if (sideTest < 0.f)
00356
00357 flags2 = BxDFType(flags & ~BSDF_REFLECTION);
00358 else
00359 return false;
00360 if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) {
00361 if (!bxdf->MatchesFlags(flags2))
00362 *f_ = SWCSpectrum(0.f);
00363 for (int i = 0; i < nBxDFs; ++i) {
00364 if (i== which)
00365 continue;
00366 if (bxdfs[i]->MatchesFlags(flags2)) {
00367 if (reverse)
00368 bxdfs[i]->f(tspack, wi, wo, f_);
00369 else
00370 bxdfs[i]->f(tspack, wo, wi, f_);
00371 }
00372 if (bxdfs[i]->MatchesFlags(flags)) {
00373 *pdf += bxdfs[i]->Pdf(tspack, wo, wi) *
00374 weights[i];
00375 if (pdfBack) {
00376 const float weightR = bxdfs[i]->Weight(tspack, wi);
00377 *pdfBack += bxdfs[i]->Pdf(tspack, wi, wo) *
00378 weightR;
00379 totalWeightR += weightR;
00380 }
00381 }
00382 }
00383 }
00384 *pdf /= totalWeight;
00385 if (pdfBack)
00386 *pdfBack /= totalWeightR;
00387 return true;
00388 }
00389 float MultiBSDF::Pdf(const TsPack *tspack, const Vector &woW, const Vector &wiW,
00390 BxDFType flags) const
00391 {
00392 Vector wo(WorldToLocal(woW)), wi(WorldToLocal(wiW));
00393 float pdf = 0.f;
00394 float totalWeight = 0.f;
00395 for (int i = 0; i < nBxDFs; ++i)
00396 if (bxdfs[i]->MatchesFlags(flags)) {
00397 float weight = bxdfs[i]->Weight(tspack, wo);
00398 pdf += bxdfs[i]->Pdf(tspack, wo, wi) * weight;
00399 totalWeight += weight;
00400 }
00401 return totalWeight > 0.f ? pdf / totalWeight : 0.f;
00402 }
00403
00404 SWCSpectrum MultiBSDF::f(const TsPack *tspack, const Vector &woW,
00405 const Vector &wiW, BxDFType flags) const
00406 {
00407 const float sideTest = Dot(wiW, ng) * Dot(woW, ng);
00408 if (sideTest > 0.f)
00409
00410 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00411 else if (sideTest < 0.f)
00412
00413 flags = BxDFType(flags & ~BSDF_REFLECTION);
00414 else
00415 flags = static_cast<BxDFType>(0);
00416 Vector wi(WorldToLocal(wiW)), wo(WorldToLocal(woW));
00417 SWCSpectrum f_(0.f);
00418 for (int i = 0; i < nBxDFs; ++i)
00419 if (bxdfs[i]->MatchesFlags(flags))
00420 bxdfs[i]->f(tspack, wo, wi, &f_);
00421 return f_;
00422 }
00423 SWCSpectrum MultiBSDF::rho(const TsPack *tspack, BxDFType flags) const
00424 {
00425 SWCSpectrum ret(0.f);
00426 for (int i = 0; i < nBxDFs; ++i)
00427 if (bxdfs[i]->MatchesFlags(flags))
00428 ret += bxdfs[i]->rho(tspack);
00429 return ret;
00430 }
00431 SWCSpectrum MultiBSDF::rho(const TsPack *tspack, const Vector &woW,
00432 BxDFType flags) const
00433 {
00434 Vector wo(WorldToLocal(woW));
00435 SWCSpectrum ret(0.f);
00436 for (int i = 0; i < nBxDFs; ++i)
00437 if (bxdfs[i]->MatchesFlags(flags))
00438 ret += bxdfs[i]->rho(tspack, wo);
00439 return ret;
00440 }
00441
00442 MixBSDF::MixBSDF(const DifferentialGeometry &dgs, const Normal &ngeom) :
00443 BSDF(dgs, ngeom, 1.f), totalWeight(0.f)
00444 {
00445 nBSDFs = 0;
00446 }
00447 bool MixBSDF::Sample_f(const TsPack *tspack, const Vector &wo, Vector *wi,
00448 float u1, float u2, float u3, SWCSpectrum *const f_, float *pdf,
00449 BxDFType flags, BxDFType *sampledType, float *pdfBack,
00450 bool reverse) const
00451 {
00452 u3 *= totalWeight;
00453 int which = -1;
00454 for (int i = 0; i < nBSDFs; ++i) {
00455 if (u3 < weights[i]) {
00456 which = i;
00457 break;
00458 }
00459 u3 -= weights[i];
00460 }
00461 if (which < 0)
00462 return false;
00463 if (!bsdfs[which]->Sample_f(tspack,
00464 wo, wi, u1, u2, u3 / weights[which], f_, pdf, flags,
00465 sampledType, pdfBack, reverse))
00466 return false;
00467
00468
00469
00470
00471
00472
00473
00474
00475 if (reverse)
00476 *f_ *= weights[which] * AbsDot(*wi, bsdfs[which]->nn) /
00477 AbsDot(*wi, nn);
00478 else
00479 *f_ *= weights[which] * AbsDot(wo, bsdfs[which]->nn) /
00480 AbsDot(wo, nn);
00481 *pdf *= weights[which];
00482 if (pdfBack)
00483 *pdfBack *= weights[which];
00484 for (int i = 0; i < nBSDFs; ++i) {
00485 if (i == which)
00486 continue;
00487 BSDF *bsdf = bsdfs[i];
00488
00489 if (reverse)
00490 f_->AddWeighted(weights[i] * AbsDot(*wi, bsdfs[i]->nn) /
00491 AbsDot(*wi, nn),
00492 bsdf->f(tspack, *wi, wo, flags));
00493 else
00494 f_->AddWeighted(weights[i] * AbsDot(wo, bsdfs[i]->nn) /
00495 AbsDot(wo, nn),
00496 bsdf->f(tspack, wo, *wi, flags));
00497 *pdf += weights[i] * bsdf->Pdf(tspack, wo, *wi, flags);
00498 if (pdfBack)
00499 *pdfBack += weights[i] * bsdf->Pdf(tspack, *wi, wo, flags);
00500 }
00501 *f_ /= totalWeight;
00502 *pdf /= totalWeight;
00503 if (pdfBack)
00504 *pdfBack /= totalWeight;
00505 return true;
00506 }
00507 float MixBSDF::Pdf(const TsPack *tspack, const Vector &wo, const Vector &wi,
00508 BxDFType flags) const
00509 {
00510 float pdf = 0.f;
00511 for (int i = 0; i < nBSDFs; ++i)
00512 pdf += weights[i] * bsdfs[i]->Pdf(tspack, wo, wi, flags);
00513 return pdf / totalWeight;
00514 }
00515 SWCSpectrum MixBSDF::f(const TsPack *tspack, const Vector &woW,
00516 const Vector &wiW, BxDFType flags) const
00517 {
00518 SWCSpectrum ff(0.f);
00519 for (int i = 0; i < nBSDFs; ++i) {
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 ff.AddWeighted(weights[i] * AbsDot(woW, bsdfs[i]->nn) /
00530 AbsDot(woW, nn), bsdfs[i]->f(tspack, woW, wiW, flags));
00531 }
00532 return ff / totalWeight;
00533 }
00534 SWCSpectrum MixBSDF::rho(const TsPack *tspack, BxDFType flags) const
00535 {
00536 SWCSpectrum ret(0.f);
00537 for (int i = 0; i < nBSDFs; ++i)
00538 ret.AddWeighted(weights[i], bsdfs[i]->rho(tspack, flags));
00539 ret /= totalWeight;
00540 return ret;
00541 }
00542 SWCSpectrum MixBSDF::rho(const TsPack *tspack, const Vector &wo,
00543 BxDFType flags) const
00544 {
00545 SWCSpectrum ret(0.f);
00546 for (int i = 0; i < nBSDFs; ++i)
00547 ret.AddWeighted(weights[i], bsdfs[i]->rho(tspack, wo, flags));
00548 ret /= totalWeight;
00549 return ret;
00550 }