00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdafx.h"
00027 #include "reflection.h"
00028 #include "spectrum.h"
00029 #include "sampler.h"
00030 #include "montecarlo.h"
00031 #include <stdarg.h>
00032
00033
00034 struct IrregIsoProc {
00035
00036 IrregIsoProc() { sumWeights = 0.f; nFound = 0; }
00037 void operator()(const Point &p, const IrregIsotropicBRDFSample &sample,
00038 float d2, float &maxDist2) {
00039 float weight = expf(-100.f * d2);
00040 v += weight * sample.v;
00041 sumWeights += weight;
00042 ++nFound;
00043 }
00044 Spectrum v;
00045 float sumWeights;
00046 int nFound;
00047 };
00048
00049
00050
00051
00052 Spectrum FrDiel(float cosi, float cost, const Spectrum &etai,
00053 const Spectrum &etat) {
00054 Spectrum Rparl = ((etat * cosi) - (etai * cost)) /
00055 ((etat * cosi) + (etai * cost));
00056 Spectrum Rperp = ((etai * cosi) - (etat * cost)) /
00057 ((etai * cosi) + (etat * cost));
00058 return (Rparl*Rparl + Rperp*Rperp) / 2.f;
00059 }
00060
00061
00062 Spectrum FrCond(float cosi, const Spectrum &eta, const Spectrum &k) {
00063 Spectrum tmp = (eta*eta + k*k) * cosi*cosi;
00064 Spectrum Rparl2 = (tmp - (2.f * eta * cosi) + 1) /
00065 (tmp + (2.f * eta * cosi) + 1);
00066 Spectrum tmp_f = eta*eta + k*k;
00067 Spectrum Rperp2 =
00068 (tmp_f - (2.f * eta * cosi) + cosi*cosi) /
00069 (tmp_f + (2.f * eta * cosi) + cosi*cosi);
00070 return (Rparl2 + Rperp2) / 2.f;
00071 }
00072
00073
00074
00075
00076 Spectrum BRDFToBTDF::f(const Vector &wo, const Vector &wi) const {
00077 return brdf->f(wo, otherHemisphere(wi));
00078 }
00079
00080
00081 Spectrum BRDFToBTDF::Sample_f(const Vector &wo, Vector *wi,
00082 float u1, float u2, float *pdf) const {
00083 Spectrum f = brdf->Sample_f(wo, wi, u1, u2, pdf);
00084 *wi = otherHemisphere(*wi);
00085 return f;
00086 }
00087
00088
00089 Spectrum ScaledBxDF::f(const Vector &wo, const Vector &wi) const {
00090 return s * bxdf->f(wo, wi);
00091 }
00092
00093
00094 Spectrum ScaledBxDF::Sample_f(const Vector &wo, Vector *wi,
00095 float u1, float u2, float *pdf) const {
00096 Spectrum f = bxdf->Sample_f(wo, wi, u1, u2, pdf);
00097 return s * f;
00098 }
00099
00100
00101 Fresnel::~Fresnel() { }
00102 Spectrum FresnelConductor::Evaluate(float cosi) const {
00103 return FrCond(fabsf(cosi), eta, k);
00104 }
00105
00106
00107 Spectrum FresnelDielectric::Evaluate(float cosi) const {
00108
00109 cosi = Clamp(cosi, -1.f, 1.f);
00110
00111
00112 bool entering = cosi > 0.;
00113 float ei = eta_i, et = eta_t;
00114 if (!entering)
00115 swap(ei, et);
00116
00117
00118 float sint = ei/et * sqrtf(max(0.f, 1.f - cosi*cosi));
00119 if (sint >= 1.) {
00120
00121 return 1.;
00122 }
00123 else {
00124 float cost = sqrtf(max(0.f, 1.f - sint*sint));
00125 return FrDiel(fabsf(cosi), cost, ei, et);
00126 }
00127 }
00128
00129
00130 Spectrum SpecularReflection::Sample_f(const Vector &wo,
00131 Vector *wi, float u1, float u2, float *pdf) const {
00132
00133 *wi = Vector(-wo.x, -wo.y, wo.z);
00134 *pdf = 1.f;
00135 return fresnel->Evaluate(CosTheta(wo)) * R / AbsCosTheta(*wi);
00136 }
00137
00138
00139 Spectrum SpecularTransmission::Sample_f(const Vector &wo,
00140 Vector *wi, float u1, float u2, float *pdf) const {
00141
00142 bool entering = CosTheta(wo) > 0.;
00143 float ei = etai, et = etat;
00144 if (!entering)
00145 swap(ei, et);
00146
00147
00148 float sini2 = SinTheta2(wo);
00149 float eta = ei / et;
00150 float sint2 = eta * eta * sini2;
00151
00152
00153 if (sint2 >= 1.) return 0.;
00154 float cost = sqrtf(max(0.f, 1.f - sint2));
00155 if (entering) cost = -cost;
00156 float sintOverSini = eta;
00157 *wi = Vector(sintOverSini * -wo.x, sintOverSini * -wo.y, cost);
00158 *pdf = 1.f;
00159 Spectrum F = fresnel.Evaluate(CosTheta(wo));
00160 return (Spectrum(1.)-F) * T /
00161 AbsCosTheta(*wi);
00162 }
00163
00164
00165 Spectrum Lambertian::f(const Vector &wo, const Vector &wi) const {
00166 return R * INV_PI;
00167 }
00168
00169
00170 Spectrum OrenNayar::f(const Vector &wo, const Vector &wi) const {
00171 float sinthetai = SinTheta(wi);
00172 float sinthetao = SinTheta(wo);
00173
00174 float maxcos = 0.f;
00175 if (sinthetai > 1e-4 && sinthetao > 1e-4) {
00176 float sinphii = SinPhi(wi), cosphii = CosPhi(wi);
00177 float sinphio = SinPhi(wo), cosphio = CosPhi(wo);
00178 float dcos = cosphii * cosphio + sinphii * sinphio;
00179 maxcos = max(0.f, dcos);
00180 }
00181
00182
00183 float sinalpha, tanbeta;
00184 if (AbsCosTheta(wi) > AbsCosTheta(wo)) {
00185 sinalpha = sinthetao;
00186 tanbeta = sinthetai / AbsCosTheta(wi);
00187 }
00188 else {
00189 sinalpha = sinthetai;
00190 tanbeta = sinthetao / AbsCosTheta(wo);
00191 }
00192 return R * INV_PI * (A + B * maxcos * sinalpha * tanbeta);
00193 }
00194
00195
00196 Microfacet::Microfacet(const Spectrum &reflectance, Fresnel *f,
00197 MicrofacetDistribution *d)
00198 : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)),
00199 R(reflectance), distribution(d), fresnel(f) {
00200 }
00201
00202
00203 Spectrum Microfacet::f(const Vector &wo, const Vector &wi) const {
00204 float cosThetaO = AbsCosTheta(wo);
00205 float cosThetaI = AbsCosTheta(wi);
00206 if (cosThetaI == 0.f || cosThetaO == 0.f) return Spectrum(0.f);
00207 Vector wh = wi + wo;
00208 if (wh.x == 0. && wh.y == 0. && wh.z == 0.) return Spectrum(0.f);
00209 wh = Normalize(wh);
00210 float cosThetaH = Dot(wi, wh);
00211 Spectrum F = fresnel->Evaluate(cosThetaH);
00212 return R * distribution->D(wh) * G(wo, wi, wh) * F /
00213 (4.f * cosThetaI * cosThetaO);
00214 }
00215
00216
00217 FresnelBlend::FresnelBlend(const Spectrum &d, const Spectrum &s,
00218 MicrofacetDistribution *dist)
00219 : BxDF(BxDFType(BSDF_REFLECTION | BSDF_GLOSSY)), Rd(d), Rs(s) {
00220 distribution = dist;
00221 }
00222
00223
00224 Spectrum FresnelBlend::f(const Vector &wo, const Vector &wi) const {
00225 Spectrum diffuse = (28.f/(23.f*M_PI)) * Rd *
00226 (Spectrum(1.f) - Rs) *
00227 (1.f - powf(1.f - .5f * AbsCosTheta(wi), 5)) *
00228 (1.f - powf(1.f - .5f * AbsCosTheta(wo), 5));
00229 Vector wh = wi + wo;
00230 if (wh.x == 0. && wh.y == 0. && wh.z == 0.) return Spectrum(0.f);
00231 wh = Normalize(wh);
00232 Spectrum specular = distribution->D(wh) /
00233 (4.f * AbsDot(wi, wh) * max(AbsCosTheta(wi), AbsCosTheta(wo))) *
00234 SchlickFresnel(Dot(wi, wh));
00235 return diffuse + specular;
00236 }
00237
00238
00239 Point BRDFRemap(const Vector &wo, const Vector &wi) {
00240 float cosi = CosTheta(wi), coso = CosTheta(wo);
00241 float sini = SinTheta(wi), sino = SinTheta(wo);
00242 float phii = SphericalPhi(wi), phio = SphericalPhi(wo);
00243 float dphi = phii - phio;
00244 if (dphi < 0.) dphi += 2.f * M_PI;
00245 if (dphi > 2.f * M_PI) dphi -= 2.f * M_PI;
00246 if (dphi > M_PI) dphi = 2.f * M_PI - dphi;
00247 return Point(sini * sino, dphi / M_PI, cosi * coso);
00248 }
00249
00250
00251 Spectrum IrregIsotropicBRDF::f(const Vector &wo,
00252 const Vector &wi) const {
00253 Point m = BRDFRemap(wo, wi);
00254 float lastMaxDist2 = .001f;
00255 while (true) {
00256
00257 IrregIsoProc proc;
00258 float maxDist2 = lastMaxDist2;
00259 isoBRDFData->Lookup(m, proc, maxDist2);
00260 if (proc.nFound > 2 || lastMaxDist2 > 1.5f)
00261 return proc.v.Clamp() / proc.sumWeights;
00262 lastMaxDist2 *= 2.f;
00263 }
00264 }
00265
00266
00267 Spectrum RegularHalfangleBRDF::f(const Vector &wo,
00268 const Vector &wi) const {
00269
00270 Vector wh = wi + wo;
00271 if (wh.x == 0.f && wh.y == 0.f && wh.z == 0.f) return Spectrum (0.f);
00272 wh = Normalize(wh);
00273 float whTheta = SphericalTheta(wh);
00274 float whCosPhi = CosPhi(wh), whSinPhi = SinPhi(wh);
00275 float whCosTheta = CosTheta(wh), whSinTheta = SinTheta(wh);
00276 Vector whx(whCosPhi * whCosTheta, whSinPhi * whCosTheta, -whSinTheta);
00277 Vector why(-whSinPhi, whCosPhi, 0);
00278 Vector wd(Dot(wi, whx), Dot(wi, why), Dot(wi, wh));
00279
00280
00281 float wdTheta = SphericalTheta(wd), wdPhi = SphericalPhi(wd);
00282 if (wdPhi > M_PI) wdPhi -= M_PI;
00283
00284
00285 #define REMAP(V, MAX, COUNT) \
00286 Clamp(int((V) / (MAX) * (COUNT)), 0, (COUNT)-1)
00287 int whThetaIndex = REMAP(sqrtf(max(0.f, whTheta / (M_PI / 2.f))),
00288 1.f, nThetaH);
00289 int wdThetaIndex = REMAP(wdTheta, M_PI / 2.f, nThetaD);
00290 int wdPhiIndex = REMAP(wdPhi, M_PI, nPhiD);
00291 #undef REMAP
00292 int index = wdPhiIndex + nPhiD * (wdThetaIndex + whThetaIndex * nThetaD);
00293 return Spectrum::FromRGB(&brdf[3*index]);
00294 }
00295
00296
00297 Spectrum BxDF::Sample_f(const Vector &wo, Vector *wi,
00298 float u1, float u2, float *pdf) const {
00299
00300 *wi = CosineSampleHemisphere(u1, u2);
00301 if (wo.z < 0.) wi->z *= -1.f;
00302 *pdf = Pdf(wo, *wi);
00303 return f(wo, *wi);
00304 }
00305
00306
00307 float BxDF::Pdf(const Vector &wo, const Vector &wi) const {
00308 return SameHemisphere(wo, wi) ? AbsCosTheta(wi) * INV_PI : 0.f;
00309 }
00310
00311
00312 float BRDFToBTDF::Pdf(const Vector &wo,
00313 const Vector &wi) const {
00314 return brdf->Pdf(wo, -wi);
00315 }
00316
00317
00318 Spectrum Microfacet::Sample_f(const Vector &wo, Vector *wi,
00319 float u1, float u2, float *pdf) const {
00320 distribution->Sample_f(wo, wi, u1, u2, pdf);
00321 if (!SameHemisphere(wo, *wi)) return Spectrum(0.f);
00322 return f(wo, *wi);
00323 }
00324
00325
00326 float Microfacet::Pdf(const Vector &wo, const Vector &wi) const {
00327 if (!SameHemisphere(wo, wi)) return 0.f;
00328 return distribution->Pdf(wo, wi);
00329 }
00330
00331
00332 void Blinn::Sample_f(const Vector &wo, Vector *wi, float u1, float u2,
00333 float *pdf) const {
00334
00335 float costheta = powf(u1, 1.f / (exponent+1));
00336 float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
00337 float phi = u2 * 2.f * M_PI;
00338 Vector wh = SphericalDirection(sintheta, costheta, phi);
00339 if (!SameHemisphere(wo, wh)) wh = -wh;
00340
00341
00342 *wi = -wo + 2.f * Dot(wo, wh) * wh;
00343
00344
00345 float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) /
00346 (2.f * M_PI * 4.f * Dot(wo, wh));
00347 if (Dot(wo, wh) <= 0.f) blinn_pdf = 0.f;
00348 *pdf = blinn_pdf;
00349 }
00350
00351
00352 float Blinn::Pdf(const Vector &wo, const Vector &wi) const {
00353 Vector wh = Normalize(wo + wi);
00354 float costheta = AbsCosTheta(wh);
00355
00356 float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) /
00357 (2.f * M_PI * 4.f * Dot(wo, wh));
00358 if (Dot(wo, wh) <= 0.f) blinn_pdf = 0.f;
00359 return blinn_pdf;
00360 }
00361
00362
00363 void Anisotropic::Sample_f(const Vector &wo, Vector *wi,
00364 float u1, float u2, float *pdf) const {
00365
00366 float phi, costheta;
00367 if (u1 < .25f) {
00368 sampleFirstQuadrant(4.f * u1, u2, &phi, &costheta);
00369 } else if (u1 < .5f) {
00370 u1 = 4.f * (.5f - u1);
00371 sampleFirstQuadrant(u1, u2, &phi, &costheta);
00372 phi = M_PI - phi;
00373 } else if (u1 < .75f) {
00374 u1 = 4.f * (u1 - .5f);
00375 sampleFirstQuadrant(u1, u2, &phi, &costheta);
00376 phi += M_PI;
00377 } else {
00378 u1 = 4.f * (1.f - u1);
00379 sampleFirstQuadrant(u1, u2, &phi, &costheta);
00380 phi = 2.f * M_PI - phi;
00381 }
00382 float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
00383 Vector wh = SphericalDirection(sintheta, costheta, phi);
00384 if (!SameHemisphere(wo, wh)) wh = -wh;
00385
00386
00387 *wi = -wo + 2.f * Dot(wo, wh) * wh;
00388
00389
00390 float costhetah = AbsCosTheta(wh);
00391 float ds = 1.f - costhetah * costhetah;
00392 float anisotropic_pdf = 0.f;
00393 if (ds > 0.f && Dot(wo, wh) > 0.f) {
00394 float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds;
00395 float d = sqrtf((ex+1.f) * (ey+1.f)) * INV_TWOPI *
00396 powf(costhetah, e);
00397 anisotropic_pdf = d / (4.f * Dot(wo, wh));
00398 }
00399 *pdf = anisotropic_pdf;
00400 }
00401
00402
00403 void Anisotropic::sampleFirstQuadrant(float u1, float u2,
00404 float *phi, float *costheta) const {
00405 if (ex == ey)
00406 *phi = M_PI * u1 * 0.5f;
00407 else
00408 *phi = atanf(sqrtf((ex+1.f) / (ey+1.f)) *
00409 tanf(M_PI * u1 * 0.5f));
00410 float cosphi = cosf(*phi), sinphi = sinf(*phi);
00411 *costheta = powf(u2, 1.f/(ex * cosphi * cosphi +
00412 ey * sinphi * sinphi + 1));
00413 }
00414
00415
00416 float Anisotropic::Pdf(const Vector &wo, const Vector &wi) const {
00417 Vector wh = Normalize(wo + wi);
00418
00419 float costhetah = AbsCosTheta(wh);
00420 float ds = 1.f - costhetah * costhetah;
00421 float anisotropic_pdf = 0.f;
00422 if (ds > 0.f && Dot(wo, wh) > 0.f) {
00423 float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds;
00424 float d = sqrtf((ex+1.f) * (ey+1.f)) * INV_TWOPI *
00425 powf(costhetah, e);
00426 anisotropic_pdf = d / (4.f * Dot(wo, wh));
00427 }
00428 return anisotropic_pdf;
00429 }
00430
00431
00432 Spectrum FresnelBlend::Sample_f(const Vector &wo, Vector *wi,
00433 float u1, float u2, float *pdf) const {
00434 if (u1 < .5) {
00435 u1 = 2.f * u1;
00436
00437 *wi = CosineSampleHemisphere(u1, u2);
00438 if (wo.z < 0.) wi->z *= -1.f;
00439 }
00440 else {
00441 u1 = 2.f * (u1 - .5f);
00442 distribution->Sample_f(wo, wi, u1, u2, pdf);
00443 if (!SameHemisphere(wo, *wi)) return Spectrum(0.f);
00444 }
00445 *pdf = Pdf(wo, *wi);
00446 return f(wo, *wi);
00447 }
00448
00449
00450 float FresnelBlend::Pdf(const Vector &wo, const Vector &wi) const {
00451 if (!SameHemisphere(wo, wi)) return 0.f;
00452 return .5f * (AbsCosTheta(wi) * INV_PI + distribution->Pdf(wo, wi));
00453 }
00454
00455
00456 Spectrum BxDF::rho(const Vector &w, int nSamples,
00457 const float *samples) const {
00458 Spectrum r = 0.;
00459 for (int i = 0; i < nSamples; ++i) {
00460
00461 Vector wi;
00462 float pdf = 0.f;
00463 Spectrum f = Sample_f(w, &wi, samples[2*i], samples[2*i+1], &pdf);
00464 if (pdf > 0.) r += f * AbsCosTheta(wi) / pdf;
00465 }
00466 return r / float(nSamples);
00467 }
00468
00469
00470 Spectrum BxDF::rho(int nSamples, const float *samples1,
00471 const float *samples2) const {
00472 Spectrum r = 0.;
00473 for (int i = 0; i < nSamples; ++i) {
00474
00475 Vector wo, wi;
00476 wo = UniformSampleHemisphere(samples1[2*i], samples1[2*i+1]);
00477 float pdf_o = INV_TWOPI, pdf_i = 0.f;
00478 Spectrum f = Sample_f(wo, &wi, samples2[2*i], samples2[2*i+1], &pdf_i);
00479 if (pdf_i > 0.)
00480 r += f * AbsCosTheta(wi) * AbsCosTheta(wo) / (pdf_o * pdf_i);
00481 }
00482 return r / (M_PI*nSamples);
00483 }
00484
00485
00486
00487
00488 BSDFSampleOffsets::BSDFSampleOffsets(int count, Sample *sample) {
00489 nSamples = count;
00490 componentOffset = sample->Add1D(nSamples);
00491 dirOffset = sample->Add2D(nSamples);
00492 }
00493
00494
00495 BSDFSample::BSDFSample(const Sample *sample,
00496 const BSDFSampleOffsets &offsets, uint32_t n) {
00497 Assert(n < sample->n2D[offsets.dirOffset]);
00498 Assert(n < sample->n1D[offsets.componentOffset]);
00499 uDir[0] = sample->twoD[offsets.dirOffset][2*n];
00500 uDir[1] = sample->twoD[offsets.dirOffset][2*n+1];
00501 uComponent = sample->oneD[offsets.componentOffset][n];
00502 Assert(uDir[0] >= 0.f && uDir[0] < 1.f);
00503 Assert(uDir[1] >= 0.f && uDir[1] < 1.f);
00504 Assert(uComponent >= 0.f && uComponent < 1.f);
00505 }
00506
00507
00508 Spectrum BSDF::Sample_f(const Vector &woW, Vector *wiW,
00509 const BSDFSample &bsdfSample, float *pdf,
00510 BxDFType flags, BxDFType *sampledType) const {
00511 PBRT_STARTED_BSDF_SAMPLE();
00512
00513 int matchingComps = NumComponents(flags);
00514 if (matchingComps == 0) {
00515 *pdf = 0.f;
00516 if (sampledType) *sampledType = BxDFType(0);
00517 PBRT_FINISHED_BSDF_SAMPLE();
00518 return Spectrum(0.f);
00519 }
00520 int which = min(Floor2Int(bsdfSample.uComponent * matchingComps),
00521 matchingComps-1);
00522 BxDF *bxdf = NULL;
00523 int count = which;
00524 for (int i = 0; i < nBxDFs; ++i)
00525 if (bxdfs[i]->MatchesFlags(flags) && count-- == 0) {
00526 bxdf = bxdfs[i];
00527 break;
00528 }
00529 Assert(bxdf);
00530
00531
00532 Vector wo = WorldToLocal(woW);
00533 Vector wi;
00534 *pdf = 0.f;
00535 Spectrum f = bxdf->Sample_f(wo, &wi, bsdfSample.uDir[0],
00536 bsdfSample.uDir[1], pdf);
00537 if (*pdf == 0.f)
00538 {
00539 if (sampledType) *sampledType = BxDFType(0);
00540 PBRT_FINISHED_BSDF_SAMPLE();
00541 return 0.f;
00542 }
00543 if (sampledType) *sampledType = bxdf->type;
00544 *wiW = LocalToWorld(wi);
00545
00546
00547 if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1)
00548 for (int i = 0; i < nBxDFs; ++i)
00549 if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(flags))
00550 *pdf += bxdfs[i]->Pdf(wo, wi);
00551 if (matchingComps > 1) *pdf /= matchingComps;
00552
00553
00554 if (!(bxdf->type & BSDF_SPECULAR)) {
00555 f = 0.;
00556 if (Dot(*wiW, ng) * Dot(woW, ng) > 0)
00557 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00558 else
00559 flags = BxDFType(flags & ~BSDF_REFLECTION);
00560 for (int i = 0; i < nBxDFs; ++i)
00561 if (bxdfs[i]->MatchesFlags(flags))
00562 f += bxdfs[i]->f(wo, wi);
00563 }
00564 PBRT_FINISHED_BSDF_SAMPLE();
00565 return f;
00566 }
00567
00568
00569 float BSDF::Pdf(const Vector &woW, const Vector &wiW,
00570 BxDFType flags) const {
00571 if (nBxDFs == 0.) return 0.;
00572 PBRT_STARTED_BSDF_PDF();
00573 Vector wo = WorldToLocal(woW), wi = WorldToLocal(wiW);
00574 float pdf = 0.f;
00575 int matchingComps = 0;
00576 for (int i = 0; i < nBxDFs; ++i)
00577 if (bxdfs[i]->MatchesFlags(flags)) {
00578 ++matchingComps;
00579 pdf += bxdfs[i]->Pdf(wo, wi);
00580 }
00581 float v = matchingComps > 0 ? pdf / matchingComps : 0.f;
00582 PBRT_FINISHED_BSDF_PDF();
00583 return v;
00584 }
00585
00586
00587 BSDF::BSDF(const DifferentialGeometry &dg, const Normal &ngeom,
00588 float e)
00589 : dgShading(dg), eta(e) {
00590 ng = ngeom;
00591 nn = dgShading.nn;
00592 sn = Normalize(dgShading.dpdu);
00593 tn = Cross(nn, sn);
00594 nBxDFs = 0;
00595 }
00596
00597
00598 Spectrum BSDF::f(const Vector &woW, const Vector &wiW,
00599 BxDFType flags) const {
00600 PBRT_STARTED_BSDF_EVAL();
00601 Vector wi = WorldToLocal(wiW), wo = WorldToLocal(woW);
00602 if (Dot(wiW, ng) * Dot(woW, ng) > 0)
00603 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00604 else
00605 flags = BxDFType(flags & ~BSDF_REFLECTION);
00606 Spectrum f = 0.;
00607 for (int i = 0; i < nBxDFs; ++i)
00608 if (bxdfs[i]->MatchesFlags(flags))
00609 f += bxdfs[i]->f(wo, wi);
00610 PBRT_FINISHED_BSDF_EVAL();
00611 return f;
00612 }
00613
00614
00615 Spectrum BSDF::rho(RNG &rng, BxDFType flags, int sqrtSamples) const {
00616 int nSamples = sqrtSamples * sqrtSamples;
00617 float *s1 = ALLOCA(float, 2 * nSamples);
00618 StratifiedSample2D(s1, sqrtSamples, sqrtSamples, rng);
00619 float *s2 = ALLOCA(float, 2 * nSamples);
00620 StratifiedSample2D(s2, sqrtSamples, sqrtSamples, rng);
00621
00622 Spectrum ret(0.);
00623 for (int i = 0; i < nBxDFs; ++i)
00624 if (bxdfs[i]->MatchesFlags(flags))
00625 ret += bxdfs[i]->rho(nSamples, s1, s2);
00626 return ret;
00627 }
00628
00629
00630 Spectrum BSDF::rho(const Vector &wo, RNG &rng, BxDFType flags,
00631 int sqrtSamples) const {
00632 int nSamples = sqrtSamples * sqrtSamples;
00633 float *s1 = ALLOCA(float, 2 * nSamples);
00634 StratifiedSample2D(s1, sqrtSamples, sqrtSamples, rng);
00635 Spectrum ret(0.);
00636 for (int i = 0; i < nBxDFs; ++i)
00637 if (bxdfs[i]->MatchesFlags(flags))
00638 ret += bxdfs[i]->rho(wo, nSamples, s1);
00639 return ret;
00640 }
00641
00642