Update from 1st printing final book source

No functional changes; just some variable renamings and changes in comments
that correspond to fragment names that were edited.
This commit is contained in:
Matt Pharr 2023-01-03 11:27:01 -08:00
parent 38ed0fe429
commit 20673d2d8a
18 changed files with 112 additions and 108 deletions

View file

@ -312,7 +312,7 @@ SampledSpectrum HairBxDF::f(Vector3f wo, Vector3f wi, TransportMode mode) const
Float cosTheta_i = SafeSqrt(1 - Sqr(sinTheta_i));
Float phi_i = std::atan2(wi.z, wi.y);
// Compute $\cos \thetat$ for refracted ray
// Compute $\cos\,\thetat$ for refracted ray
Float sinTheta_t = sinTheta_o / eta;
Float cosTheta_t = SafeSqrt(1 - Sqr(sinTheta_t));
@ -329,8 +329,9 @@ SampledSpectrum HairBxDF::f(Vector3f wo, Vector3f wi, TransportMode mode) const
Float phi = phi_i - phi_o;
pstd::array<SampledSpectrum, pMax + 1> ap = Ap(cosTheta_o, eta, h, T);
SampledSpectrum fsum(0.);
for (int p = 0; p < pMax; ++p) {
// Compute $\sin \thetao$ and $\cos \thetao$ terms accounting for scales
// Compute $\sin\,\thetao$ and $\cos\,\thetao$ terms accounting for scales
Float sinThetap_o, cosThetap_o;
if (p == 0) {
sinThetap_o = sinTheta_o * cos2kAlpha[1] - cosTheta_o * sin2kAlpha[1];
@ -348,7 +349,7 @@ SampledSpectrum HairBxDF::f(Vector3f wo, Vector3f wi, TransportMode mode) const
cosThetap_o = cosTheta_o;
}
// Handle out-of-range $\cos \thetao$ from scale adjustment
// Handle out-of-range $\cos\,\thetao$ from scale adjustment
cosThetap_o = std::abs(cosThetap_o);
fsum += Mp(cosTheta_i, cosThetap_o, sinTheta_i, sinThetap_o, v[p]) * ap[p] *
@ -367,7 +368,7 @@ SampledSpectrum HairBxDF::f(Vector3f wo, Vector3f wi, TransportMode mode) const
pstd::array<Float, HairBxDF::pMax + 1> HairBxDF::ApPDF(Float cosTheta_o) const {
// Initialize array of $A_p$ values for _cosTheta_o_
Float sinTheta_o = SafeSqrt(1 - Sqr(cosTheta_o));
// Compute $\cos \thetat$ for refracted ray
// Compute $\cos\,\thetat$ for refracted ray
Float sinTheta_t = sinTheta_o / eta;
Float cosTheta_t = SafeSqrt(1 - Sqr(sinTheta_t));
@ -406,7 +407,7 @@ pstd::optional<BSDFSample> HairBxDF::Sample_f(Vector3f wo, Float uc, Point2f u,
pstd::array<Float, pMax + 1> apPDF = ApPDF(cosTheta_o);
int p = SampleDiscrete(apPDF, uc, nullptr, &uc);
// Compute $\sin \thetao$ and $\cos \thetao$ terms accounting for scales
// Compute $\sin\,\thetao$ and $\cos\,\thetao$ terms accounting for scales
Float sinThetap_o, cosThetap_o;
if (p == 0) {
sinThetap_o = sinTheta_o * cos2kAlpha[1] - cosTheta_o * sin2kAlpha[1];
@ -424,7 +425,7 @@ pstd::optional<BSDFSample> HairBxDF::Sample_f(Vector3f wo, Float uc, Point2f u,
cosThetap_o = cosTheta_o;
}
// Handle out-of-range $\cos \thetao$ from scale adjustment
// Handle out-of-range $\cos\,\thetao$ from scale adjustment
cosThetap_o = std::abs(cosThetap_o);
// Sample $M_p$ to compute $\thetai$
@ -455,7 +456,7 @@ pstd::optional<BSDFSample> HairBxDF::Sample_f(Vector3f wo, Float uc, Point2f u,
// Compute PDF for sampled hair scattering direction _wi_
Float pdf = 0;
for (int p = 0; p < pMax; ++p) {
// Compute $\sin \thetao$ and $\cos \thetao$ terms accounting for scales
// Compute $\sin\,\thetao$ and $\cos\,\thetao$ terms accounting for scales
Float sinThetap_o, cosThetap_o;
if (p == 0) {
sinThetap_o = sinTheta_o * cos2kAlpha[1] - cosTheta_o * sin2kAlpha[1];
@ -473,10 +474,10 @@ pstd::optional<BSDFSample> HairBxDF::Sample_f(Vector3f wo, Float uc, Point2f u,
cosThetap_o = cosTheta_o;
}
// Handle out-of-range $\cos \thetao$ from scale adjustment
// Handle out-of-range $\cos\,\thetao$ from scale adjustment
cosThetap_o = std::abs(cosThetap_o);
// Handle out-of-range $\cos \thetao$ from scale adjustment
// Handle out-of-range $\cos\,\thetao$ from scale adjustment
cosThetap_o = std::abs(cosThetap_o);
pdf += Mp(cosTheta_i, cosThetap_o, sinTheta_i, sinThetap_o, v[p]) * apPDF[p] *
@ -515,7 +516,7 @@ Float HairBxDF::PDF(Vector3f wo, Vector3f wi, TransportMode mode,
Float phi = phi_i - phi_o;
Float pdf = 0;
for (int p = 0; p < pMax; ++p) {
// Compute $\sin \thetao$ and $\cos \thetao$ terms accounting for scales
// Compute $\sin\,\thetao$ and $\cos\,\thetao$ terms accounting for scales
Float sinThetap_o, cosThetap_o;
if (p == 0) {
sinThetap_o = sinTheta_o * cos2kAlpha[1] - cosTheta_o * sin2kAlpha[1];
@ -533,7 +534,7 @@ Float HairBxDF::PDF(Vector3f wo, Vector3f wi, TransportMode mode,
cosThetap_o = cosTheta_o;
}
// Handle out-of-range $\cos \thetao$ from scale adjustment
// Handle out-of-range $\cos\,\thetao$ from scale adjustment
cosThetap_o = std::abs(cosThetap_o);
pdf += Mp(cosTheta_i, cosThetap_o, sinTheta_i, sinThetap_o, v[p]) * apPDF[p] *
@ -1010,7 +1011,7 @@ SampledSpectrum MeasuredBxDF::f(Vector3f wo, Vector3f wi, TransportMode mode) co
return SampledSpectrum(0);
wm = Normalize(wm);
// Map $\wo$ and $\wm$ to the unit square $[0, 1]^2$
// Map $\wo$ and $\wm$ to the unit square $[0,\,1]^2$
Float theta_o = SphericalTheta(wo), phi_o = std::atan2(wo.y, wo.x);
Float theta_m = SphericalTheta(wm), phi_m = std::atan2(wm.y, wm.x);
Point2f u_wo(theta2u(theta_o), phi2u(phi_o));

View file

@ -477,7 +477,7 @@ class LayeredBxDF {
SampledSpectrum f(Vector3f wo, Vector3f wi, TransportMode mode) const {
SampledSpectrum f(0.);
// Estimate _LayeredBxDF_ value _f_ using random sampling
// Set _wi_ and _wi_ for layered BSDF evaluation
// Set _wo_ and _wi_ for layered BSDF evaluation
if (twoSided && wo.z < 0) {
wo = -wo;
wi = -wi;
@ -539,7 +539,7 @@ class LayeredBxDF {
PBRT_DBG("beta: %f %f %f %f, w: %f %f %f, f: %f %f %f %f\n", beta[0],
beta[1], beta[2], beta[3], w.x, w.y, w.z, f[0], f[1], f[2],
f[3]);
// Possibly terminate layered BSDF random walk with Russian Roulette
// Possibly terminate layered BSDF random walk with Russian roulette
if (depth > 3 && beta.MaxComponentValue() < 0.25f) {
Float q = std::max<Float>(0, 1 - beta.MaxComponentValue());
if (r() < q)
@ -778,7 +778,7 @@ class LayeredBxDF {
Float PDF(Vector3f wo, Vector3f wi, TransportMode mode,
BxDFReflTransFlags sampleFlags = BxDFReflTransFlags::All) const {
CHECK(sampleFlags == BxDFReflTransFlags::All); // for now
// Set _wi_ and _wi_ for layered BSDF evaluation
// Set _wo_ and _wi_ for layered BSDF evaluation
if (twoSided && wo.z < 0) {
wo = -wo;
wi = -wi;

View file

@ -272,6 +272,7 @@ class ProjectiveCamera : public CameraBase {
cameraFromRaster = Inverse(screenFromCamera) * screenFromRaster;
}
protected:
// ProjectiveCamera Protected Members
Transform screenFromCamera, cameraFromRaster;
Transform rasterFromScreen, screenFromRaster;

View file

@ -290,7 +290,7 @@ BVHBuildNode *BVHAggregate::buildRecursive(ThreadLocal<Allocator> &threadAllocat
// Compute costs for splitting after each bucket
constexpr int nSplits = nBuckets - 1;
float costs[nSplits] = {};
Float costs[nSplits] = {};
// Partially initialize _costs_ using a forward scan over splits
int countBelow = 0;
Bounds3f boundBelow;
@ -300,7 +300,7 @@ BVHBuildNode *BVHAggregate::buildRecursive(ThreadLocal<Allocator> &threadAllocat
costs[i] += countBelow * boundBelow.SurfaceArea();
}
// Finish initializing _costs_ using a backwards scan over splits
// Finish initializing _costs_ using a backward scan over splits
int countAbove = 0;
Bounds3f boundAbove;
for (int i = nSplits; i >= 1; --i) {

View file

@ -146,7 +146,7 @@ void ImageTileIntegrator::Render() {
Film film = camera.GetFilm();
DisplayDynamic(film.GetFilename(), Point2i(pixelBounds.Diagonal()),
{"R", "G", "B"},
[&](Bounds2i b, pstd::span<pstd::span<float>> displayValue) {
[&](Bounds2i b, pstd::span<pstd::span<Float>> displayValue) {
int index = 0;
for (Point2i p : b) {
RGB rgb = film.GetPixelRGB(pixelBounds.pMin + p,
@ -521,7 +521,7 @@ void LightPathIntegrator::EvaluatePixelSample(Point2i pPixel, int sampleIndex,
if (!sampledLight)
return;
Light light = sampledLight->light;
Float lightPDF = sampledLight->p;
Float p_l = sampledLight->p;
// Sample point on light source for light path
Float time = camera.SampleTime(sampler.Get1D());
@ -544,7 +544,7 @@ void LightPathIntegrator::EvaluatePixelSample(Point2i pPixel, int sampleIndex,
// Compute visible light's path contribution and add to film
SampledSpectrum L = Le *
DistanceSquared(cs->pRef.p(), cs->pLens.p()) *
cs->Wi / (lightPDF * pdf * cs->pdf);
cs->Wi / (p_l * pdf * cs->pdf);
camera.GetFilm().AddSplat(cs->pRaster, L, lambda);
}
}
@ -556,7 +556,7 @@ void LightPathIntegrator::EvaluatePixelSample(Point2i pPixel, int sampleIndex,
// Initialize light path ray and weighted path throughput _beta_
RayDifferential ray(les->ray);
SampledSpectrum beta =
les->L * les->AbsCosTheta(ray.d) / (lightPDF * les->pdfPos * les->pdfDir);
les->L * les->AbsCosTheta(ray.d) / (p_l * les->pdfPos * les->pdfDir);
while (true) {
// Intersect light path ray with scene
@ -634,7 +634,7 @@ SampledSpectrum PathIntegrator::Li(RayDifferential ray, SampledWavelengths &lamb
SampledSpectrum L(0.f), beta(1.f);
int depth = 0;
Float bsdfPDF, etaScale = 1;
Float p_b, etaScale = 1;
bool specularBounce = false, anyNonSpecularBounces = false;
LightSampleContext prevIntrCtx;
@ -651,9 +651,9 @@ SampledSpectrum PathIntegrator::Li(RayDifferential ray, SampledWavelengths &lamb
L += beta * Le;
else {
// Compute MIS weight for infinite light
Float lightPDF = lightSampler.PMF(prevIntrCtx, light) *
light.PDF_Li(prevIntrCtx, ray.d, true);
Float w_b = PowerHeuristic(1, bsdfPDF, 1, lightPDF);
Float p_l = lightSampler.PMF(prevIntrCtx, light) *
light.PDF_Li(prevIntrCtx, ray.d, true);
Float w_b = PowerHeuristic(1, p_b, 1, p_l);
L += beta * w_b * Le;
}
@ -669,9 +669,9 @@ SampledSpectrum PathIntegrator::Li(RayDifferential ray, SampledWavelengths &lamb
else {
// Compute MIS weight for area light
Light areaLight(si->intr.areaLight);
Float lightPDF = lightSampler.PMF(prevIntrCtx, areaLight) *
areaLight.PDF_Li(prevIntrCtx, ray.d, true);
Float w_l = PowerHeuristic(1, bsdfPDF, 1, lightPDF);
Float p_l = lightSampler.PMF(prevIntrCtx, areaLight) *
areaLight.PDF_Li(prevIntrCtx, ray.d, true);
Float w_l = PowerHeuristic(1, p_b, 1, p_l);
L += beta * w_l * Le;
}
@ -739,7 +739,7 @@ SampledSpectrum PathIntegrator::Li(RayDifferential ray, SampledWavelengths &lamb
break;
// Update path state variables after surface scattering
beta *= bs->f * AbsDot(bs->wi, isect.shading.n) / bs->pdf;
bsdfPDF = bs->pdfIsProportional ? bsdf.PDF(wo, bs->wi) : bs->pdf;
p_b = bs->pdfIsProportional ? bsdf.PDF(wo, bs->wi) : bs->pdf;
DCHECK(!IsInf(beta.y(lambda)));
specularBounce = bs->IsSpecular();
anyNonSpecularBounces |= !bs->IsSpecular();
@ -899,7 +899,7 @@ SampledSpectrum SimpleVolPathIntegrator::Li(RayDifferential ray,
return false;
} else {
// Handle null scattering event for medium sample
// Handle null-scattering event for medium sample
uMode = rng.Uniform<Float>();
return true;
}
@ -1024,18 +1024,18 @@ SampledSpectrum VolPathIntegrator::Li(RayDifferential ray, SampledWavelengths &l
return false;
}
// Update _beta_ and _r_u_ for real scattering event
// Update _beta_ and _r_u_ for real-scattering event
Float pdf = T_maj[0] * mp.sigma_s[0];
beta *= T_maj * mp.sigma_s / pdf;
r_u *= T_maj * mp.sigma_s / pdf;
if (beta && r_u) {
// Sample direct lighting at volume scattering event
// Sample direct lighting at volume-scattering event
MediumInteraction intr(p, -ray.d, ray.time, ray.medium,
mp.phase);
L += SampleLd(intr, nullptr, lambda, sampler, beta, r_u);
// Sample new direction at real scattering event
// Sample new direction at real-scattering event
Point2f u = sampler.Get2D();
pstd::optional<PhaseFunctionSample> ps =
intr.phase.Sample_p(-ray.d, u);
@ -1088,9 +1088,9 @@ SampledSpectrum VolPathIntegrator::Li(RayDifferential ray, SampledWavelengths &l
L += beta * Le / r_u.Average();
else {
// Add infinite light contribution using both PDFs with MIS
Float lightPDF = lightSampler.PMF(prevIntrContext, light) *
light.PDF_Li(prevIntrContext, ray.d, true);
r_l *= lightPDF;
Float p_l = lightSampler.PMF(prevIntrContext, light) *
light.PDF_Li(prevIntrContext, ray.d, true);
r_l *= p_l;
L += beta * Le / (r_u + r_l).Average();
}
}
@ -1106,9 +1106,9 @@ SampledSpectrum VolPathIntegrator::Li(RayDifferential ray, SampledWavelengths &l
else {
// Add surface light contribution using both PDFs with MIS
Light areaLight(isect.areaLight);
Float lightPDF = lightSampler.PMF(prevIntrContext, areaLight) *
areaLight.PDF_Li(prevIntrContext, ray.d, true);
r_l *= lightPDF;
Float p_l = lightSampler.PMF(prevIntrContext, areaLight) *
areaLight.PDF_Li(prevIntrContext, ray.d, true);
r_l *= p_l;
L += beta * Le / (r_u + r_l).Average();
}
}
@ -1304,7 +1304,7 @@ SampledSpectrum VolPathIntegrator::SampleLd(const Interaction &intr, const BSDF
pstd::optional<LightLiSample> ls = light.SampleLi(ctx, uLight, lambda, true);
if (!ls || !ls->L || ls->pdf == 0)
return SampledSpectrum(0.f);
Float lightPDF = sampledLight->p * ls->pdf;
Float p_l = sampledLight->p * ls->pdf;
// Evaluate BSDF or phase function for light sample direction
Float scatterPDF;
@ -1383,7 +1383,7 @@ SampledSpectrum VolPathIntegrator::SampleLd(const Interaction &intr, const BSDF
lightRay = si->intr.SpawnRayTo(ls->pLight);
}
// Return path contribution function estimate for direct lighting
r_l *= r_p * lightPDF;
r_l *= r_p * p_l;
r_u *= r_p * scatterPDF;
if (IsDeltaLight(light.Type()))
return beta * f_hat * T_ray * ls->L / r_l.Average();
@ -1934,12 +1934,12 @@ int GenerateLightSubpath(const Integrator &integrator, SampledWavelengths &lambd
RayDifferential ray(les->ray);
// Generate first vertex of light subpath
Float lightPDF = lightSamplePDF * les->pdfPos;
path[0] = les->intr ? Vertex::CreateLight(light, *les->intr, les->L, lightPDF)
: Vertex::CreateLight(light, ray, les->L, lightPDF);
Float p_l = lightSamplePDF * les->pdfPos;
path[0] = les->intr ? Vertex::CreateLight(light, *les->intr, les->L, p_l)
: Vertex::CreateLight(light, ray, les->L, p_l);
// Follow light subpath random walk
SampledSpectrum beta = les->L * les->AbsCosTheta(ray.d) / (lightPDF * les->pdfDir);
SampledSpectrum beta = les->L * les->AbsCosTheta(ray.d) / (p_l * les->pdfDir);
PBRT_DBG("%s\n",
StringPrintf(
"Starting light subpath. Ray: %s, Le %s, beta %s, pdfPos %f, pdfDir %f",
@ -2363,7 +2363,7 @@ SampledSpectrum ConnectBDPT(const Integrator &integrator, SampledWavelengths &la
if (sampledLight) {
Light light = sampledLight->light;
Float lightPDF = sampledLight->p;
Float p_l = sampledLight->p;
LightSampleContext ctx;
if (pt.IsOnSurface()) {
@ -2383,7 +2383,7 @@ SampledSpectrum ConnectBDPT(const Integrator &integrator, SampledWavelengths &la
if (lightWeight && lightWeight->L && lightWeight->pdf > 0) {
EndpointInteraction ei(light, lightWeight->pLight);
sampled = Vertex::CreateLight(
ei, lightWeight->L / (lightWeight->pdf * lightPDF), 0);
ei, lightWeight->L / (lightWeight->pdf * p_l), 0);
sampled.pdfFwd = sampled.PDFLightOrigin(integrator.infiniteLights, pt,
lightSampler);
L = pt.beta * pt.f(sampled, TransportMode::Radiance) * sampled.beta;
@ -2877,7 +2877,7 @@ void SPPMIntegrator::Render() {
// Follow camera ray path until a visible point is created
SPPMPixel &pixel = pixels[pPixel];
Float etaScale = 1, bsdfPDF;
Float etaScale = 1, p_b;
bool specularBounce = true, haveSetVisiblePoint = false;
LightSampleContext prevIntrCtx;
int depth = 0;
@ -2894,9 +2894,9 @@ void SPPMIntegrator::Render() {
L += beta * Le;
else {
// Compute MIS weight for infinite light
Float lightPDF = lightSampler.PMF(prevIntrCtx, light) *
light.PDF_Li(prevIntrCtx, ray.d, true);
Float w_b = PowerHeuristic(1, bsdfPDF, 1, lightPDF);
Float p_l = lightSampler.PMF(prevIntrCtx, light) *
light.PDF_Li(prevIntrCtx, ray.d, true);
Float w_b = PowerHeuristic(1, p_b, 1, p_l);
L += beta * w_b * Le;
}
@ -2928,9 +2928,9 @@ void SPPMIntegrator::Render() {
else {
// Compute MIS weight for area light
Light areaLight(si->intr.areaLight);
Float lightPDF = lightSampler.PMF(prevIntrCtx, areaLight) *
areaLight.PDF_Li(prevIntrCtx, ray.d, true);
Float w_l = PowerHeuristic(1, bsdfPDF, 1, lightPDF);
Float p_l = lightSampler.PMF(prevIntrCtx, areaLight) *
areaLight.PDF_Li(prevIntrCtx, ray.d, true);
Float w_l = PowerHeuristic(1, p_b, 1, p_l);
L += beta * w_l * Le;
}
@ -2966,7 +2966,7 @@ void SPPMIntegrator::Render() {
etaScale *= Sqr(bs->eta);
beta *= bs->f * AbsDot(bs->wi, isect.shading.n) / bs->pdf;
bsdfPDF = bs->pdfIsProportional ? bsdf.PDF(wo, bs->wi) : bs->pdf;
p_b = bs->pdfIsProportional ? bsdf.PDF(wo, bs->wi) : bs->pdf;
SampledSpectrum rrBeta = beta * etaScale;
if (rrBeta.MaxComponentValue() < 1) {
@ -3079,7 +3079,7 @@ void SPPMIntegrator::Render() {
if (!sampledLight)
continue;
Light light = sampledLight->light;
Float lightPDF = sampledLight->p;
Float p_l = sampledLight->p;
// Compute sample values for photon ray leaving light source
Point2f uLight0 = Sample2D();
@ -3094,7 +3094,7 @@ void SPPMIntegrator::Render() {
continue;
RayDifferential photonRay = RayDifferential(les->ray);
SampledSpectrum beta = (les->AbsCosTheta(photonRay.d) * les->L) /
(lightPDF * les->pdfPos * les->pdfDir);
(p_l * les->pdfPos * les->pdfDir);
if (!beta)
continue;

View file

@ -62,7 +62,7 @@ class Integrator {
std::vector<Light> infiniteLights;
protected:
// Integrator Private Methods
// Integrator Protected Methods
Integrator(Primitive aggregate, std::vector<Light> lights)
: aggregate(aggregate), lights(lights) {
// Integrator constructor implementation

View file

@ -133,11 +133,11 @@ Float LightBounds::Importance(Point3f p, Normal3f n) const {
cosTheta_w = std::abs(cosTheta_w);
Float sinTheta_w = SafeSqrt(1 - Sqr(cosTheta_w));
// Compute $\cos \theta_\roman{b}$ for reference point
// Compute $\cos\,\theta_\roman{\+b}$ for reference point
Float cosTheta_b = BoundSubtendedDirections(bounds, p).cosTheta;
Float sinTheta_b = SafeSqrt(1 - Sqr(cosTheta_b));
// Compute $\cos \theta'$ and test against $\cos \theta_\roman{e}$
// Compute $\cos\,\theta'$ and test against $\cos\,\theta_\roman{e}$
Float sinTheta_o = SafeSqrt(1 - Sqr(cosTheta_o));
Float cosTheta_x = cosSubClamped(sinTheta_w, cosTheta_w, sinTheta_o, cosTheta_o);
Float sinTheta_x = sinSubClamped(sinTheta_w, cosTheta_w, sinTheta_o, cosTheta_o);
@ -148,7 +148,7 @@ Float LightBounds::Importance(Point3f p, Normal3f n) const {
// Return final importance at reference point
Float importance = phi * cosThetap / d2;
DCHECK_GE(importance, -1e-3);
// Account for $\cos \theta_\roman{i}$ in importance at surfaces
// Account for $\cos\theta_\roman{i}$ in importance at surfaces
if (n != Normal3f(0, 0, 0)) {
Float cosTheta_i = AbsDot(wi, n);
Float sinTheta_i = SafeSqrt(1 - Sqr(cosTheta_i));
@ -1260,7 +1260,7 @@ Float PortalImageInfiniteLight::PDF_Li(LightSampleContext ctx, Vector3f w,
// Return PDF for sampling $(u,v)$ from reference point
pstd::optional<Bounds2f> b = ImageBounds(ctx.p());
if (!b)
return {};
return 0;
Float pdf = distribution.PDF(*uv, *b);
return pdf / duv_dw;
}

View file

@ -69,9 +69,9 @@ class PowerLightSampler {
pstd::optional<SampledLight> Sample(Float u) const {
if (!aliasTable.size())
return {};
Float pdf;
int lightIndex = aliasTable.Sample(u, &pdf);
return SampledLight{lights[lightIndex], pdf};
Float pmf;
int lightIndex = aliasTable.Sample(u, &pmf);
return SampledLight{lights[lightIndex], pmf};
}
PBRT_CPU_GPU
@ -172,11 +172,11 @@ class CompactLightBounds {
cosTheta_w = std::abs(cosTheta_w);
Float sinTheta_w = SafeSqrt(1 - Sqr(cosTheta_w));
// Compute $\cos \theta_\roman{b}$ for reference point
// Compute $\cos\,\theta_\roman{\+b}$ for reference point
Float cosTheta_b = BoundSubtendedDirections(bounds, p).cosTheta;
Float sinTheta_b = SafeSqrt(1 - Sqr(cosTheta_b));
// Compute $\cos \theta'$ and test against $\cos \theta_\roman{e}$
// Compute $\cos\,\theta'$ and test against $\cos\,\theta_\roman{e}$
Float sinTheta_o = SafeSqrt(1 - Sqr(cosTheta_o));
Float cosTheta_x = cosSubClamped(sinTheta_w, cosTheta_w, sinTheta_o, cosTheta_o);
Float sinTheta_x = sinSubClamped(sinTheta_w, cosTheta_w, sinTheta_o, cosTheta_o);
@ -187,7 +187,7 @@ class CompactLightBounds {
// Return final importance at reference point
Float importance = phi * cosThetap / d2;
DCHECK_GE(importance, -1e-3);
// Account for $\cos \theta_\roman{i}$ in importance at surfaces
// Account for $\cos\theta_\roman{i}$ in importance at surfaces
if (n != Normal3f(0, 0, 0)) {
Float cosTheta_i = AbsDot(wi, n);
Float sinTheta_i = SafeSqrt(1 - Sqr(cosTheta_i));
@ -273,8 +273,8 @@ class BVHLightSampler {
u /= pInfinite;
int index =
std::min<int>(u * infiniteLights.size(), infiniteLights.size() - 1);
Float pdf = pInfinite / infiniteLights.size();
return SampledLight{infiniteLights[index], pdf};
Float pmf = pInfinite / infiniteLights.size();
return SampledLight{infiniteLights[index], pmf};
} else {
// Traverse light BVH to sample light
@ -285,7 +285,7 @@ class BVHLightSampler {
Normal3f n = ctx.ns;
u = std::min<Float>((u - pInfinite) / (1 - pInfinite), OneMinusEpsilon);
int nodeIndex = 0;
Float pdf = 1 - pInfinite;
Float pmf = 1 - pInfinite;
while (true) {
// Process light BVH node for light sampling
@ -301,9 +301,9 @@ class BVHLightSampler {
return {};
// Randomly sample light BVH child node
Float nodePDF;
int child = SampleDiscrete(ci, u, &nodePDF, &u);
pdf *= nodePDF;
Float nodePMF;
int child = SampleDiscrete(ci, u, &nodePMF, &u);
pmf *= nodePMF;
nodeIndex = (child == 0) ? (nodeIndex + 1) : node.childOrLightIndex;
} else {
@ -312,7 +312,7 @@ class BVHLightSampler {
DCHECK_GT(node.lightBounds.Importance(p, n, allLightBounds), 0);
if (nodeIndex > 0 ||
node.lightBounds.Importance(p, n, allLightBounds) > 0)
return SampledLight{lights[node.childOrLightIndex], pdf};
return SampledLight{lights[node.childOrLightIndex], pmf};
return {};
}
}
@ -321,11 +321,11 @@ class BVHLightSampler {
PBRT_CPU_GPU
Float PMF(const LightSampleContext &ctx, Light light) const {
// Handle infinite _light_ PDF computation
// Handle infinite _light_ PMF computation
if (!lightToBitTrail.HasKey(light))
return 1.f / (infiniteLights.size() + (nodes.empty() ? 0 : 1));
// Initialize local variables for BVH traversal for PDF computation
// Initialize local variables for BVH traversal for PMF computation
uint32_t bitTrail = lightToBitTrail[light];
Point3f p = ctx.p();
Normal3f n = ctx.ns;
@ -333,23 +333,23 @@ class BVHLightSampler {
Float pInfinite = Float(infiniteLights.size()) /
Float(infiniteLights.size() + (nodes.empty() ? 0 : 1));
Float pdf = 1 - pInfinite;
Float pmf = 1 - pInfinite;
int nodeIndex = 0;
// Compute light's PDF by walking down tree nodes to the light
// Compute light's PMF by walking down tree nodes to the light
while (true) {
const LightBVHNode *node = &nodes[nodeIndex];
if (node->isLeaf) {
DCHECK_EQ(light, lights[node->childOrLightIndex]);
return pdf;
return pmf;
}
// Compute child importances and update PDF for current node
// Compute child importances and update PMF for current node
const LightBVHNode *child0 = &nodes[nodeIndex + 1];
const LightBVHNode *child1 = &nodes[node->childOrLightIndex];
Float ci[2] = {child0->lightBounds.Importance(p, n, allLightBounds),
child1->lightBounds.Importance(p, n, allLightBounds)};
DCHECK_GT(ci[bitTrail & 1], 0);
pdf *= ci[bitTrail & 1] / (ci[0] + ci[1]);
pmf *= ci[bitTrail & 1] / (ci[0] + ci[1]);
// Use _bitTrail_ to find next node index and update its value
nodeIndex = (bitTrail & 1) ? node->childOrLightIndex : (nodeIndex + 1);

View file

@ -186,7 +186,7 @@ class PaddedSobolSampler {
int dim = dimension;
dimension += 2;
// Return randomized 2D Sobol' sample
// Return randomized 2D Sobol\+$'$ sample
return Point2f(SampleDimension(0, index, uint32_t(hash)),
SampleDimension(1, index, hash >> 32));
}
@ -258,7 +258,7 @@ class ZSobolSampler {
Float Get1D() {
uint64_t sampleIndex = GetSampleIndex();
++dimension;
// Generate 1D Sobol$'$ sample at _sampleIndex_
// Generate 1D Sobol\+$'$ sample at _sampleIndex_
uint32_t sampleHash = Hash(dimension, seed);
if (randomize == RandomizeStrategy::None)
return SobolSample(sampleIndex, 0, NoRandomizer());
@ -274,7 +274,7 @@ class ZSobolSampler {
Point2f Get2D() {
uint64_t sampleIndex = GetSampleIndex();
dimension += 2;
// Generate 2D Sobol sample at _sampleIndex_
// Generate 2D Sobol\+$'$ sample at _sampleIndex_
uint64_t bits = Hash(dimension, seed);
uint32_t sampleHash[2] = {uint32_t(bits), uint32_t(bits >> 32)};
if (randomize == RandomizeStrategy::None)
@ -334,7 +334,7 @@ class ZSobolSampler {
bool pow2Samples = log2SamplesPerPixel & 1;
int lastDigit = pow2Samples ? 1 : 0;
for (int i = nBase4Digits - 1; i >= lastDigit; --i) {
// Randomly permute $i$th base 4 digit in _mortonIndex_
// Randomly permute $i$th base-4 digit in _mortonIndex_
int digitShift = 2 * i - (pow2Samples ? 1 : 0);
int digit = (mortonIndex >> digitShift) & 3;
// Choose permutation _p_ to use for _digit_
@ -525,7 +525,7 @@ class SobolSampler {
Point2f GetPixel2D() {
Point2f u(SobolSample(sobolIndex, 0, NoRandomizer()),
SobolSample(sobolIndex, 1, NoRandomizer()));
// Remap Sobol$'$ dimensions used for pixel samples
// Remap Sobol\+$'$ dimensions used for pixel samples
for (int dim = 0; dim < 2; ++dim) {
DCHECK_RARE(1e-7, u[dim] * scale - pixel[dim] < 0);
DCHECK_RARE(1e-7, u[dim] * scale - pixel[dim] > 1);
@ -542,11 +542,11 @@ class SobolSampler {
// SobolSampler Private Methods
PBRT_CPU_GPU
Float SampleDimension(int dimension) const {
// Return un-randomized Sobol$'$ sample if appropriate
// Return un-randomized Sobol\+$'$ sample if appropriate
if (randomize == RandomizeStrategy::None)
return SobolSample(sobolIndex, dimension, NoRandomizer());
// Return randomized Sobol$'$ sample using _randomize_
// Return randomized Sobol\+$'$ sample using _randomize_
uint32_t hash = Hash(dimension, seed);
if (randomize == RandomizeStrategy::PermuteDigits)
return SobolSample(sobolIndex, dimension, BinaryPermuteScrambler(hash));

View file

@ -211,7 +211,7 @@ pstd::optional<TriangleIntersection> IntersectTriangle(const Ray &ray, Float tMa
Float e1 = DifferenceOfProducts(p2t.x, p0t.y, p2t.y, p0t.x);
Float e2 = DifferenceOfProducts(p0t.x, p1t.y, p0t.y, p1t.x);
// Fall back to double precision test at triangle edges
// Fall back to double-precision test at triangle edges
if (sizeof(Float) == sizeof(float) && (e0 == 0.0f || e1 == 0.0f || e2 == 0.0f)) {
double p2txp1ty = (double)p2t.x * (double)p1t.y;
double p2typ1tx = (double)p2t.y * (double)p1t.x;
@ -677,6 +677,7 @@ bool Curve::RecursiveIntersect(const Ray &ray, Float tMax, pstd::span<const Poin
Point3f pc =
EvaluateCubicBezier(pstd::span<const Point3f>(cp), Clamp(w, 0, 1), &dpcdw);
Float ptCurveDist2 = Sqr(pc.x) + Sqr(pc.y);
if (ptCurveDist2 > Sqr(hitWidth) * 0.25f)
return false;
if (pc.z < 0 || pc.z > rayLength * tMax)
@ -1284,9 +1285,9 @@ pstd::optional<ShapeSample> BilinearPatch::Sample(const ShapeSampleContext &ctx,
}
// Sample direction to rectangular bilinear patch
Float pdf = 1;
// Warp uniform sample _u_ to account for incident $\cos \theta$ factor
// Warp uniform sample _u_ to account for incident $\cos\theta$ factor
if (ctx.ns != Normal3f(0, 0, 0)) {
// Compute $\cos \theta$ weights for rectangle seen from reference point
// Compute $\cos\theta$ weights for rectangle seen from reference point
pstd::array<Float, 4> w =
pstd::array<Float, 4>{std::max<Float>(0.01, AbsDot(v00, ctx.ns)),
std::max<Float>(0.01, AbsDot(v10, ctx.ns)),
@ -1355,7 +1356,7 @@ Float BilinearPatch::PDF(const ShapeSampleContext &ctx, Vector3f wi) const {
// Return PDF for sample in spherical rectangle
Float pdf = 1 / SphericalQuadArea(v00, v10, v11, v01);
if (ctx.ns != Normal3f(0, 0, 0)) {
// Compute $\cos \theta$ weights for rectangle seen from reference point
// Compute $\cos\theta$ weights for rectangle seen from reference point
pstd::array<Float, 4> w =
pstd::array<Float, 4>{std::max<Float>(0.01, AbsDot(v00, ctx.ns)),
std::max<Float>(0.01, AbsDot(v10, ctx.ns)),

View file

@ -313,7 +313,7 @@ class Sphere {
}
// Sample sphere uniformly inside subtended cone
// Compute quantities related the $\theta_\roman{max}$ for cone
// Compute quantities related to the $\theta_\roman{max}$ for cone
Float sinThetaMax = radius / Distance(ctx.p(), pCenter);
Float sin2ThetaMax = Sqr(sinThetaMax);
Float cosThetaMax = SafeSqrt(1 - sin2ThetaMax);
@ -511,6 +511,7 @@ class Disk {
Point3f pObj(pd.x * radius, pd.y * radius, height);
Point3fi pi = (*renderFromObject)(Point3fi(pObj));
Normal3f n = Normalize((*renderFromObject)(Normal3f(0, 0, 1)));
if (reverseOrientation)
n *= -1;
// Compute $(u,v)$ for sampled point on disk
@ -1079,7 +1080,7 @@ class Triangle {
// Apply warp product sampling for cosine factor at reference point
Float pdf = 1;
if (ctx.ns != Normal3f(0, 0, 0)) {
// Compute $\cos \theta$-based weights _w_ at sample domain corners
// Compute $\cos\theta$-based weights _w_ at sample domain corners
Point3f rp = ctx.p();
Vector3f wi[3] = {Normalize(p0 - rp), Normalize(p1 - rp), Normalize(p2 - rp)};
pstd::array<Float, 4> w =
@ -1104,7 +1105,7 @@ class Triangle {
Point3f pAbsSum = Abs(b[0] * p0) + Abs(b[1] * p1) + Abs((1 - b[0] - b[1]) * p2);
Vector3f pError = Vector3f(gamma(6) * pAbsSum);
// Return _ShapeSample_ for uniform solid angle sampled point on triangle
// Return _ShapeSample_ for solid angle sampled point on triangle
Point3f p = b[0] * p0 + b[1] * p1 + b[2] * p2;
// Compute surface normal for sampled point on triangle
Normal3f n = Normalize(Normal3f(Cross(p1 - p0, p2 - p0)));
@ -1149,7 +1150,7 @@ class Triangle {
}
Float pdf = 1 / solidAngle;
// Adjust PDF for warp product sampling of triangle $\cos \theta$ factor
// Adjust PDF for warp product sampling of triangle $\cos\theta$ factor
if (ctx.ns != Normal3f(0, 0, 0)) {
// Get triangle vertices in _p0_, _p1_, and _p2_
const TriangleMesh *mesh = GetMesh();
@ -1157,7 +1158,7 @@ class Triangle {
Point3f p0 = mesh->p[v[0]], p1 = mesh->p[v[1]], p2 = mesh->p[v[2]];
Point2f u = InvertSphericalTriangleSample({p0, p1, p2}, ctx.p(), wi);
// Compute $\cos \theta$-based weights _w_ at sample domain corners
// Compute $\cos\theta$-based weights _w_ at sample domain corners
Point3f rp = ctx.p();
Vector3f wi[3] = {Normalize(p0 - rp), Normalize(p1 - rp), Normalize(p2 - rp)};
pstd::array<Float, 4> w =

View file

@ -117,7 +117,7 @@ class SphericalMapping {
PBRT_CPU_GPU
TexCoord2D Map(TextureEvalContext ctx) const {
Point3f pt = textureFromRender(ctx.p);
// Compute $\partial s/\partial \pt{}$ and $\partial t/\partial \pt{}$ for
// Compute $\partial\,s/\partial\,\pt{}$ and $\partial\,t/\partial\,\pt{}$ for
// spherical mapping
Float x2y2 = Sqr(pt.x) + Sqr(pt.y);
Float sqrtx2y2 = std::sqrt(x2y2);

View file

@ -32,7 +32,7 @@ class BufferCache {
// BufferCache Public Methods
const T *LookupOrAdd(pstd::span<const T> buf, Allocator alloc) {
++nBufferCacheLookups;
// Return pointer to data if _buf_ contents is already in the cache
// Return pointer to data if _buf_ contents are already in the cache
Buffer lookupBuffer(buf.data(), buf.size());
int shardIndex = uint32_t(lookupBuffer.hash) >> (32 - logShards);
DCHECK(shardIndex >= 0 && shardIndex < nShards);

View file

@ -168,13 +168,13 @@ template <typename R>
PBRT_CPU_GPU inline Float SobolSample(int64_t a, int dimension, R randomizer) {
DCHECK_LT(dimension, NSobolDimensions);
DCHECK(a >= 0 && a < (1ull << SobolMatrixSize));
// Compute initial Sobol sample _v_ using generator matrices
// Compute initial Sobol\+$'$ sample _v_ using generator matrices
uint32_t v = 0;
for (int i = dimension * SobolMatrixSize; a != 0; a >>= 1, i++)
if (a & 1)
v ^= SobolMatrices32[i];
// Randomize Sobol sample and return floating-point value
// Randomize Sobol\+$'$ sample and return floating-point value
v = randomizer(v);
return std::min(v * 0x1p-32f, FloatOneMinusEpsilon);
}

View file

@ -306,7 +306,7 @@ Vector3f EqualAreaSquareToSphere(Point2f p) {
// Find $z$ coordinate for spherical direction
Float z = pstd::copysign(1 - Sqr(r), signedDistance);
// Compute $\cos \phi$ and $\sin \phi$ for original quadrant and return vector
// Compute $\cos\phi$ and $\sin\phi$ for original quadrant and return vector
Float cosPhi = pstd::copysign(std::cos(phi), u);
Float sinPhi = pstd::copysign(std::sin(phi), v);
return Vector3f(cosPhi * r * SafeSqrt(2 - Sqr(r)), sinPhi * r * SafeSqrt(2 - Sqr(r)),

View file

@ -338,7 +338,7 @@ PBRT_CPU_GPU inline constexpr Float EvaluatePolynomial(Float t, C c, Args... cRe
// http://www.plunk.org/~hatch/rightway.html
PBRT_CPU_GPU inline Float SinXOverX(Float x) {
if (1 + x * x == 1)
if (1 - x * x == 1)
return 1;
return std::sin(x) / x;
}

View file

@ -59,7 +59,7 @@ pstd::array<Float, 3> SampleSphericalTriangle(const pstd::array<Point3f, 3> &v,
*pdf = (A <= 0) ? 0 : 1 / A;
}
// Find $\cos \beta'$ for point along _b_ for sampled area
// Find $\cos\beta'$ for point along _b_ for sampled area
Float cosAlpha = std::cos(alpha), sinAlpha = std::sin(alpha);
Float sinPhi = std::sin(Ap_pi) * cosAlpha - std::cos(Ap_pi) * sinAlpha;
Float cosPhi = std::cos(Ap_pi) * cosAlpha + std::sin(Ap_pi) * sinAlpha;
@ -345,7 +345,7 @@ Point2f InvertSphericalRectangleSample(Point3f pRef, Point3f s, Vector3f ex, Vec
}
Vector3f SampleHenyeyGreenstein(Vector3f wo, Float g, Point2f u, Float *pdf) {
// Compute $\cos \theta$ for Henyey--Greenstein sample
// Compute $\cos\theta$ for Henyey--Greenstein sample
Float cosTheta;
if (std::abs(g) < 1e-3f)
cosTheta = 1 - 2 * u[0];
@ -576,7 +576,7 @@ AliasTable::AliasTable(pstd::span<const Float> weights, Allocator alloc)
// Process under and over work item together
while (!under.empty() && !over.empty()) {
// Remove an item from each alias table work list
// Remove items _un_ and _ov_ from the alias table work lists
Outcome un = under.back(), ov = over.back();
under.pop_back();
over.pop_back();

View file

@ -132,7 +132,7 @@ class Transform {
PBRT_CPU_GPU
Point3fi operator()(const Point3fi &p) const {
Float x = Float(p.x), y = Float(p.y), z = Float(p.z);
// Compute transformed coordinates from point _x_, _y_, and _z_
// Compute transformed coordinates from point _(x, y, z)_
Float xp = (m[0][0] * x + m[0][1] * y) + (m[0][2] * z + m[0][3]);
Float yp = (m[1][0] * x + m[1][1] * y) + (m[1][2] * z + m[1][3]);
Float zp = (m[2][0] * x + m[2][1] * y) + (m[2][2] * z + m[2][3]);