mirror of
https://github.com/mmp/pbrt-v4
synced 2026-09-26 16:20:07 +03:00
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:
parent
38ed0fe429
commit
20673d2d8a
18 changed files with 112 additions and 108 deletions
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ class ProjectiveCamera : public CameraBase {
|
|||
cameraFromRaster = Inverse(screenFromCamera) * screenFromRaster;
|
||||
}
|
||||
|
||||
protected:
|
||||
// ProjectiveCamera Protected Members
|
||||
Transform screenFromCamera, cameraFromRaster;
|
||||
Transform rasterFromScreen, screenFromRaster;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue