提交 6dd33255 编写于 作者: M Matt Pharr

Update from book source. No functional changes.

上级 282a5cb4
......@@ -145,8 +145,7 @@ static __forceinline__ __device__ void ProcessClosestIntersection(
EnqueueWorkAfterIntersection(r, rayMedium, optixGetRayTmax(), intr, params.mediumSampleQueue,
params.nextRayQueue, params.hitAreaLightQueue,
params.basicEvalMaterialQueue,
params.universalEvalMaterialQueue,
getPayload<ClosestHitContext>()->mediumInterface);
params.universalEvalMaterialQueue);
}
static __forceinline__ __device__ Transform getWorldFromInstance() {
......
......@@ -1108,27 +1108,31 @@ class BasicTextureEvaluator {
PBRT_CPU_GPU
bool CanEvaluate(std::initializer_list<FloatTexture> ftex,
std::initializer_list<SpectrumTexture> stex) const {
for (auto f : ftex)
// Return _false_ if any _FloatTexture_s cannot be evaluated
for (FloatTexture f : ftex)
if (f && !f.Is<FloatConstantTexture>() && !f.Is<FloatImageTexture>() &&
!f.Is<GPUFloatPtexTexture>() && !f.Is<GPUFloatImageTexture>())
return false;
for (auto s : stex)
// Return _false_ if any _SpectrumTexture_s cannot be evaluated
for (SpectrumTexture s : stex)
if (s && !s.Is<SpectrumConstantTexture>() && !s.Is<SpectrumImageTexture>() &&
!s.Is<GPUSpectrumPtexTexture>() && !s.Is<GPUSpectrumImageTexture>())
return false;
return true;
}
PBRT_CPU_GPU
Float operator()(FloatTexture tex, TextureEvalContext ctx) {
if (FloatConstantTexture *fcTex = tex.CastOrNullptr<FloatConstantTexture>())
return fcTex->Evaluate(ctx);
else if (FloatImageTexture *fiTex = tex.CastOrNullptr<FloatImageTexture>())
return fiTex->Evaluate(ctx);
else if (GPUFloatImageTexture *gfiTex = tex.CastOrNullptr<GPUFloatImageTexture>())
return gfiTex->Evaluate(ctx);
else if (GPUFloatPtexTexture *fPtex = tex.CastOrNullptr<GPUFloatPtexTexture>())
return fPtex->Evaluate(ctx);
if (tex.Is<FloatConstantTexture>())
return tex.Cast<FloatConstantTexture>()->Evaluate(ctx);
else if (tex.Is<FloatImageTexture>())
return tex.Cast<FloatImageTexture>()->Evaluate(ctx);
else if (tex.Is<GPUFloatImageTexture>())
return tex.Cast<GPUFloatImageTexture>()->Evaluate(ctx);
else if (tex.Is<GPUFloatPtexTexture>())
return tex.Cast<GPUFloatPtexTexture>()->Evaluate(ctx);
else {
if (tex)
LOG_FATAL("BasicTextureEvaluator::operator() called with %s", tex);
......@@ -1139,16 +1143,14 @@ class BasicTextureEvaluator {
PBRT_CPU_GPU
SampledSpectrum operator()(SpectrumTexture tex, TextureEvalContext ctx,
SampledWavelengths lambda) {
if (SpectrumConstantTexture *sc = tex.CastOrNullptr<SpectrumConstantTexture>())
return sc->Evaluate(ctx, lambda);
else if (SpectrumImageTexture *siTex = tex.CastOrNullptr<SpectrumImageTexture>())
return siTex->Evaluate(ctx, lambda);
else if (GPUSpectrumImageTexture *gsiTex =
tex.CastOrNullptr<GPUSpectrumImageTexture>())
return gsiTex->Evaluate(ctx, lambda);
else if (GPUSpectrumPtexTexture *sPtex =
tex.CastOrNullptr<GPUSpectrumPtexTexture>())
return sPtex->Evaluate(ctx, lambda);
if (tex.Is<SpectrumConstantTexture>())
return tex.Cast<SpectrumConstantTexture>()->Evaluate(ctx, lambda);
else if (tex.Is<SpectrumImageTexture>())
return tex.Cast<SpectrumImageTexture>()->Evaluate(ctx, lambda);
else if (tex.Is<GPUSpectrumImageTexture>())
return tex.Cast<GPUSpectrumImageTexture>()->Evaluate(ctx, lambda);
else if (tex.Is<GPUSpectrumPtexTexture>())
return tex.Cast<GPUSpectrumPtexTexture>()->Evaluate(ctx, lambda);
else {
if (tex)
LOG_FATAL("BasicTextureEvaluator::operator() called with %s", tex);
......
......@@ -42,26 +42,20 @@ void CPUAggregate::IntersectClosest(int maxRays, const RayQueue *rayQueue,
ParallelFor(0, rayQueue->Size(), [=](int index) {
const RayWorkItem r = (*rayQueue)[index];
// Intersect _r_'s ray with the scene and enqueue resulting work
pstd::optional<ShapeIntersection> si = aggregate.Intersect(r.ray, Infinity);
pstd::optional<ShapeIntersection> si = aggregate.Intersect(r.ray);
if (!si)
EnqueueWorkAfterMiss(r, mediumSampleQueue, escapedRayQueue);
else {
// Process queued ray intersected a surface
const SurfaceInteraction &intr = si->intr;
Float tHit = Distance(r.ray.o, intr.p()) / Length(r.ray.d);
MediumInterface mi = intr.mediumInterface ? *intr.mediumInterface
: MediumInterface(r.ray.medium);
else
// FIXME? Second arg r.ray.medium doesn't match OptiX path
EnqueueWorkAfterIntersection(r, r.ray.medium, tHit, si->intr,
mediumSampleQueue, nextRayQueue,
hitAreaLightQueue, basicEvalMaterialQueue,
universalEvalMaterialQueue, mi);
}
EnqueueWorkAfterIntersection(
r, r.ray.medium, si->tHit, si->intr, mediumSampleQueue, nextRayQueue,
hitAreaLightQueue, basicEvalMaterialQueue, universalEvalMaterialQueue);
});
}
void CPUAggregate::IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const {
// Intersect shadow rays from _shadowRayQueue_ in parallel
ParallelFor(0, shadowRayQueue->Size(), [=](int index) {
const ShadowRayWorkItem w = (*shadowRayQueue)[index];
bool hit = aggregate.IntersectP(w.ray, w.tMax);
......
......@@ -28,9 +28,11 @@ void WavefrontPathIntegrator::UpdateFilm() {
SampledWavelengths lambda = pixelSampleState.lambda[pixelIndex];
Float filterWeight = pixelSampleState.filterWeight[pixelIndex];
if (initializeVisibleSurface) {
// Call _Film::AddSample()_ with _VisibleSurface_ for pixel sample
VisibleSurface visibleSurface =
pixelSampleState.visibleSurface[pixelIndex];
film.AddSample(pPixel, Lw, lambda, &visibleSurface, filterWeight);
} else
film.AddSample(pPixel, Lw, lambda, nullptr, filterWeight);
});
......
......@@ -491,7 +491,7 @@ Float WavefrontPathIntegrator::Render() {
for (int sampleIndex = firstSampleIndex; sampleIndex < lastSampleIndex;
++sampleIndex) {
CheckCallbackScope _([&]() {
return StringPrintf("Wavefrontrendering failed at sample %d. Debug with "
return StringPrintf("Wavefront rendering failed at sample %d. Debug with "
"\"--debugstart %d\"\n",
sampleIndex, sampleIndex);
});
......@@ -622,11 +622,10 @@ Float WavefrontPathIntegrator::Render() {
void WavefrontPathIntegrator::HandleEscapedRays() {
if (!escapedRayQueue)
return;
ForAllQueued(
"Handle escaped rays", escapedRayQueue, maxQueueSize,
PBRT_CPU_GPU_LAMBDA(const EscapedRayWorkItem w) {
// Update pixel radiance for escaped ray
// Compute weighted radiance for escaped ray
SampledSpectrum L(0.f);
for (const auto &light : *infiniteLights) {
if (SampledSpectrum Le = light.Le(Ray(w.rayo, w.rayd), w.lambda); Le) {
......@@ -652,6 +651,8 @@ void WavefrontPathIntegrator::HandleEscapedRays() {
}
}
}
// Update pixel radiance if ray's radiance is non-zero
if (L) {
PBRT_DBG("Added L %f %f %f %f for escaped ray pixel index %d\n", L[0],
L[1], L[2], L[3], w.pixelIndex);
......
......@@ -45,7 +45,6 @@ class WavefrontAggregate {
virtual void IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const = 0;
virtual void IntersectShadowTr(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const = 0;
......@@ -77,19 +76,10 @@ class WavefrontPathIntegrator {
void HandleEmissiveIntersection();
void EvaluateMaterialsAndBSDFs(int wavefrontDepth);
template <typename Mtl>
template <typename ConcreteMaterial>
void EvaluateMaterialAndBSDF(int wavefrontDepth);
template <typename Mtl, typename TextureEvaluator>
void EvaluateMaterialAndBSDF(TextureEvaluator texEval, MaterialEvalQueue *evalQueue,
int wavefrontDepth);
void SampleDirect(int wavefrontDepth);
template <typename BxDF>
void SampleDirect(int wavefrontDepth);
void SampleIndirect(int wavefrontDepth);
template <typename BxDF>
void SampleIndirect(int wavefrontDepth);
template <typename ConcreteMaterial, typename TextureEvaluator>
void EvaluateMaterialAndBSDF(MaterialEvalQueue *evalQueue, int wavefrontDepth);
void UpdateFilm();
......
......@@ -28,11 +28,32 @@ inline PBRT_CPU_GPU void EnqueueWorkAfterMiss(RayWorkItem r,
}
}
inline PBRT_CPU_GPU void RecordShadowRayIntersection(
const ShadowRayWorkItem w, SOA<PixelSampleState> *pixelSampleState,
bool foundIntersection) {
if (foundIntersection) {
PBRT_DBG("Shadow ray was occluded\n");
return;
}
SampledSpectrum Ld = w.Ld / (w.uniPathPDF + w.lightPathPDF).Average();
PBRT_DBG("Unoccluded shadow ray. Final Ld %f %f %f %f "
"(sr.Ld %f %f %f %f uniPathPDF %f %f %f %f lightPathPDF %f %f %f %f)\n",
Ld[0], Ld[1], Ld[2], Ld[3], w.Ld[0], w.Ld[1], w.Ld[2], w.Ld[3],
w.uniPathPDF[0], w.uniPathPDF[1], w.uniPathPDF[2], w.uniPathPDF[3],
w.lightPathPDF[0], w.lightPathPDF[1], w.lightPathPDF[2], w.lightPathPDF[3]);
SampledSpectrum Lpixel = pixelSampleState->L[w.pixelIndex];
pixelSampleState->L[w.pixelIndex] = Lpixel + Ld;
}
inline PBRT_CPU_GPU void EnqueueWorkAfterIntersection(
RayWorkItem r, Medium rayMedium, float tMax, SurfaceInteraction intr,
MediumSampleQueue *mediumSampleQueue, RayQueue *nextRayQueue,
HitAreaLightQueue *hitAreaLightQueue, MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue, MediumInterface mediumInterface) {
MaterialEvalQueue *universalEvalMaterialQueue) {
MediumInterface mediumInterface =
intr.mediumInterface ? *intr.mediumInterface : MediumInterface(rayMedium);
if (rayMedium) {
assert(mediumSampleQueue);
PBRT_DBG("Enqueuing into medium sample queue\n");
......@@ -94,7 +115,7 @@ inline PBRT_CPU_GPU void EnqueueWorkAfterIntersection(
// TODO: intr.wo == -ray.d?
hitAreaLightQueue->Push(
HitAreaLightWorkItem{intr.areaLight, intr.p(), intr.n, intr.uv, intr.wo,
r.depth, r.lambda, r.T_hat, r.uniPathPDF, r.lightPathPDF,
r.lambda, r.depth, r.T_hat, r.uniPathPDF, r.lightPathPDF,
r.prevIntrCtx, (int)r.isSpecularBounce, r.pixelIndex});
}
......@@ -115,48 +136,29 @@ inline PBRT_CPU_GPU void EnqueueWorkAfterIntersection(
intr.n,
intr.dpdu,
intr.dpdv,
intr.time,
r.depth,
intr.shading.n,
intr.shading.dpdu,
intr.shading.dpdv,
intr.shading.dndu,
intr.shading.dndv,
intr.uv,
r.depth,
intr.faceIndex,
r.lambda,
r.pixelIndex,
r.anyNonSpecularBounces,
intr.wo,
r.pixelIndex,
r.T_hat,
r.uniPathPDF,
r.etaScale,
mediumInterface,
intr.time});
mediumInterface});
};
material.Dispatch(enqueue);
PBRT_DBG("Closest hit found intersection at t %f\n", tMax);
}
inline PBRT_CPU_GPU void RecordShadowRayIntersection(
const ShadowRayWorkItem w, SOA<PixelSampleState> *pixelSampleState,
bool foundIntersection) {
if (foundIntersection) {
PBRT_DBG("Shadow ray was occluded\n");
return;
}
SampledSpectrum Ld = w.Ld / (w.uniPathPDF + w.lightPathPDF).Average();
PBRT_DBG("Unoccluded shadow ray. Final Ld %f %f %f %f "
"(sr.Ld %f %f %f %f uniPathPDF %f %f %f %f lightPathPDF %f %f %f %f)\n",
Ld[0], Ld[1], Ld[2], Ld[3], w.Ld[0], w.Ld[1], w.Ld[2], w.Ld[3],
w.uniPathPDF[0], w.uniPathPDF[1], w.uniPathPDF[2], w.uniPathPDF[3],
w.lightPathPDF[0], w.lightPathPDF[1], w.lightPathPDF[2], w.lightPathPDF[3]);
SampledSpectrum Lpixel = pixelSampleState->L[w.pixelIndex];
pixelSampleState->L[w.pixelIndex] = Lpixel + Ld;
}
struct TransmittanceTraceResult {
bool hit;
Point3f pHit;
......
......@@ -189,7 +189,7 @@ void WavefrontPathIntegrator::SampleMediumInteraction(int wavefrontDepth) {
w.pixelIndex, w.depth);
escapedRayQueue->Push(
EscapedRayWorkItem{ray.o, ray.d, w.depth, lambda, w.pixelIndex,
(int)w.isSpecularBounce, T_hat, uniPathPDF,
T_hat, (int)w.isSpecularBounce, uniPathPDF,
lightPathPDF, w.prevIntrCtx});
}
return;
......@@ -224,7 +224,7 @@ void WavefrontPathIntegrator::SampleMediumInteraction(int wavefrontDepth) {
"depth %d\n",
w.pixelIndex, w.depth);
hitAreaLightQueue->Push(HitAreaLightWorkItem{
w.areaLight, Point3f(w.pi), w.n, w.uv, -ray.d, w.depth, lambda, T_hat,
w.areaLight, Point3f(w.pi), w.n, w.uv, -ray.d, lambda, w.depth, T_hat,
uniPathPDF, lightPathPDF, w.prevIntrCtx, w.isSpecularBounce,
w.pixelIndex});
}
......@@ -242,15 +242,29 @@ void WavefrontPathIntegrator::SampleMediumInteraction(int wavefrontDepth) {
auto enqueue = [=](auto ptr) {
using Material = typename std::remove_reference_t<decltype(*ptr)>;
q->Push<MaterialEvalWorkItem<Material>>(MaterialEvalWorkItem<Material>{
ptr, w.pi, w.n,
w.dpdu, w.dpdv, w.ns,
w.dpdus, w.dpdvs, w.dndus,
w.dndvs, w.uv, w.depth,
w.faceIndex, lambda, w.anyNonSpecularBounces,
-ray.d, w.pixelIndex, T_hat,
uniPathPDF, w.etaScale, w.mediumInterface,
ray.time});
q->Push<MaterialEvalWorkItem<Material>>(
MaterialEvalWorkItem<Material>{ptr,
w.pi,
w.n,
w.dpdu,
w.dpdv,
ray.time,
w.depth,
w.ns,
w.dpdus,
w.dpdvs,
w.dndus,
w.dndvs,
w.uv,
w.faceIndex,
lambda,
w.pixelIndex,
w.anyNonSpecularBounces,
-ray.d,
T_hat,
uniPathPDF,
w.etaScale,
w.mediumInterface});
};
material.Dispatch(enqueue);
});
......@@ -262,15 +276,18 @@ void WavefrontPathIntegrator::SampleMediumInteraction(int wavefrontDepth) {
PhaseFunction::Types());
}
template <typename Phase>
template <typename ConcretePhaseFunction>
void WavefrontPathIntegrator::SampleMediumScattering(int wavefrontDepth) {
RayQueue *currentRayQueue = CurrentRayQueue(wavefrontDepth);
RayQueue *nextRayQueue = NextRayQueue(wavefrontDepth);
std::string desc = std::string("Sample direct/indirect - ") + Phase::Name();
std::string desc =
std::string("Sample direct/indirect - ") + ConcretePhaseFunction::Name();
ForAllQueued(
desc.c_str(), mediumScatterQueue->Get<MediumScatterWorkItem<Phase>>(),
maxQueueSize, PBRT_CPU_GPU_LAMBDA(const MediumScatterWorkItem<Phase> w) {
desc.c_str(),
mediumScatterQueue->Get<MediumScatterWorkItem<ConcretePhaseFunction>>(),
maxQueueSize,
PBRT_CPU_GPU_LAMBDA(const MediumScatterWorkItem<ConcretePhaseFunction> w) {
RaySamples raySamples = pixelSampleState.samples[w.pixelIndex];
Vector3f wo = w.wo;
......@@ -303,8 +320,9 @@ void WavefrontPathIntegrator::SampleMediumScattering(int wavefrontDepth) {
Ray ray(w.p, ls->pLight.p() - w.p, w.time, w.medium);
// Enqueue shadow ray
shadowRayQueue->Push(ray, 1 - ShadowEpsilon, w.lambda, Ld, uniPathPDF,
lightPathPDF, w.pixelIndex);
shadowRayQueue->Push(ShadowRayWorkItem{ray, 1 - ShadowEpsilon,
w.lambda, Ld, uniPathPDF,
lightPathPDF, w.pixelIndex});
PBRT_DBG("Enqueued medium shadow ray depth %d "
"Ld %f %f %f %f uniPathPDF %f %f %f %f "
......
......@@ -53,8 +53,8 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
using BSSRDF = TabulatedBSSRDF;
BSSRDF bssrdf = w.bssrdf;
using BxDF = typename BSSRDF::BxDF;
BxDF bxdf;
using ConcreteBxDF = typename BSSRDF::BxDF;
ConcreteBxDF bxdf;
SubsurfaceInteraction &intr = w.ssi;
BSSRDFSample bssrdfSample = bssrdf.ProbeIntersectionToSample(intr, &bxdf);
......@@ -78,7 +78,8 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
Point2f u = raySamples.indirect.u;
Float uc = raySamples.indirect.uc;
pstd::optional<BSDFSample> bsdfSample = bsdf.Sample_f<BxDF>(wo, uc, u);
pstd::optional<BSDFSample> bsdfSample =
bsdf.Sample_f<ConcreteBxDF>(wo, uc, u);
if (bsdfSample) {
Vector3f wi = bsdfSample->wi;
SampledSpectrum T_hat = T_hatp * bsdfSample->f * AbsDot(wi, intr.ns);
......@@ -86,7 +87,7 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
lightPathPDF = uniPathPDF;
PBRT_DBG("%s f*cos[0] %f bsdfSample->pdf %f f*cos/pdf %f\n",
BxDF::Name(), bsdfSample->f[0] * AbsDot(wi, intr.ns),
ConcreteBxDF::Name(), bsdfSample->f[0] * AbsDot(wi, intr.ns),
bsdfSample->pdf,
bsdfSample->f[0] * AbsDot(wi, intr.ns) / bsdfSample->pdf);
......@@ -165,7 +166,7 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
return;
Vector3f wi = ls->wi;
SampledSpectrum f = bsdf.f<BxDF>(wo, wi);
SampledSpectrum f = bsdf.f<ConcreteBxDF>(wo, wi);
if (!f)
return;
......@@ -180,7 +181,8 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
Float lightPDF = ls->pdf * sampledLight->pdf;
// This causes uniPathPDF to be zero for the shadow ray, so that
// part of MIS just becomes a no-op.
Float bsdfPDF = IsDeltaLight(light.Type()) ? 0.f : bsdf.PDF<BxDF>(wo, wi);
Float bsdfPDF =
IsDeltaLight(light.Type()) ? 0.f : bsdf.PDF<ConcreteBxDF>(wo, wi);
SampledSpectrum lightPathPDF = uniPathPDF * lightPDF;
uniPathPDF *= bsdfPDF;
......@@ -202,8 +204,9 @@ void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
ray.medium = Dot(ray.d, intr.n) > 0 ? w.mediumInterface.outside
: w.mediumInterface.inside;
shadowRayQueue->Push(ray, 1 - ShadowEpsilon, lambda, Ld, uniPathPDF,
lightPathPDF, w.pixelIndex);
shadowRayQueue->Push(ShadowRayWorkItem{ray, 1 - ShadowEpsilon, lambda, Ld,
uniPathPDF, lightPathPDF,
w.pixelIndex});
}
});
......
......@@ -44,10 +44,10 @@ struct EvaluateMaterialCallback {
int wavefrontDepth;
WavefrontPathIntegrator *integrator;
// EvaluateMaterialCallback Public Methods
template <typename Mtl>
template <typename ConcreteMaterial>
void operator()() {
if constexpr (!std::is_same_v<Mtl, MixMaterial>)
integrator->EvaluateMaterialAndBSDF<Mtl>(wavefrontDepth);
if constexpr (!std::is_same_v<ConcreteMaterial, MixMaterial>)
integrator->EvaluateMaterialAndBSDF<ConcreteMaterial>(wavefrontDepth);
}
};
......@@ -56,30 +56,33 @@ void WavefrontPathIntegrator::EvaluateMaterialsAndBSDFs(int wavefrontDepth) {
ForEachType(EvaluateMaterialCallback{wavefrontDepth, this}, Material::Types());
}
template <typename Mtl>
template <typename ConcreteMaterial>
void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(int wavefrontDepth) {
if (haveBasicEvalMaterial[Material::TypeIndex<Mtl>()])
EvaluateMaterialAndBSDF<Mtl>(BasicTextureEvaluator(), basicEvalMaterialQueue,
wavefrontDepth);
if (haveUniversalEvalMaterial[Material::TypeIndex<Mtl>()])
EvaluateMaterialAndBSDF<Mtl>(UniversalTextureEvaluator(),
universalEvalMaterialQueue, wavefrontDepth);
int index = Material::TypeIndex<ConcreteMaterial>();
if (haveBasicEvalMaterial[index])
EvaluateMaterialAndBSDF<ConcreteMaterial, BasicTextureEvaluator>(
basicEvalMaterialQueue, wavefrontDepth);
if (haveUniversalEvalMaterial[index])
EvaluateMaterialAndBSDF<ConcreteMaterial, UniversalTextureEvaluator>(
universalEvalMaterialQueue, wavefrontDepth);
}
template <typename Mtl, typename TextureEvaluator>
void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
MaterialEvalQueue *evalQueue,
template <typename ConcreteMaterial, typename TextureEvaluator>
void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(MaterialEvalQueue *evalQueue,
int wavefrontDepth) {
// Get BSDF for items in _evalQueue_ and sample illumination
// Construct _name_ for material/texture evaluator kernel
std::string name = StringPrintf(
"%s + BxDF Eval (%s tex)", Mtl::Name(),
"%s + BxDF Eval (%s tex)", ConcreteMaterial::Name(),
std::is_same_v<TextureEvaluator, BasicTextureEvaluator> ? "Basic" : "Universal");
RayQueue *nextRayQueue = NextRayQueue(wavefrontDepth);
auto queue = evalQueue->Get<MaterialEvalWorkItem<ConcreteMaterial>>();
ForAllQueued(
name.c_str(), evalQueue->Get<MaterialEvalWorkItem<Mtl>>(), maxQueueSize,
PBRT_CPU_GPU_LAMBDA(const MaterialEvalWorkItem<Mtl> w) {
name.c_str(), queue, maxQueueSize,
PBRT_CPU_GPU_LAMBDA(const MaterialEvalWorkItem<ConcreteMaterial> w) {
// Evaluate material and BSDF for ray intersection
TextureEvaluator texEval;
// Compute differentials for position and $(u,v)$ at intersection point
Vector3f dpdx, dpdy;
Float dudx = 0, dudy = 0, dvdx = 0, dvdy = 0;
......@@ -107,7 +110,7 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
dudy = IsFinite(dudy) ? Clamp(dudy, -1e8f, 1e8f) : 0.f;
dvdy = IsFinite(dvdy) ? Clamp(dvdy, -1e8f, 1e8f) : 0.f;
// Apply bump mapping if material has a displacement texture
// Compute shading normal if bump or normal mapping is being used
Normal3f ns = w.ns;
Vector3f dpdus = w.dpdus;
FloatTexture displacement = w.material->GetDisplacement();
......@@ -126,9 +129,10 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
SampledWavelengths lambda = w.lambda;
MaterialEvalContext ctx =
w.GetMaterialEvalContext(dudx, dudy, dvdx, dvdy, ns, dpdus);
using BxDF = typename Mtl::BxDF;
BxDF bxdf;
using ConcreteBxDF = typename ConcreteMaterial::BxDF;
ConcreteBxDF bxdf;
BSDF bsdf = w.material->GetBSDF(texEval, ctx, lambda, &bxdf);
// Handle terminated secondary wavelengths after BSDF creation
if (lambda.SecondaryTerminated())
pixelSampleState.lambda[w.pixelIndex] = lambda;
......@@ -173,21 +177,22 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
// Sample BSDF and enqueue indirect ray at intersection point
Vector3f wo = w.wo;
RaySamples raySamples = pixelSampleState.samples[w.pixelIndex];
pstd::optional<BSDFSample> bsdfSample =
bsdf.Sample_f<BxDF>(wo, raySamples.indirect.uc, raySamples.indirect.u);
pstd::optional<BSDFSample> bsdfSample = bsdf.Sample_f<ConcreteBxDF>(
wo, raySamples.indirect.uc, raySamples.indirect.u);
if (bsdfSample) {
// Compute updated path throughput and PDFs and enqueue indirect ray
Vector3f wi = bsdfSample->wi;
SampledSpectrum T_hat = w.T_hat * bsdfSample->f * AbsDot(wi, ns);
SampledSpectrum uniPathPDF = w.uniPathPDF, lightPathPDF = w.uniPathPDF;
PBRT_DBG("%s f*cos[0] %f bsdfSample->pdf %f f*cos/pdf %f\n", BxDF::Name(),
bsdfSample->f[0] * AbsDot(wi, ns), bsdfSample->pdf,
PBRT_DBG("%s f*cos[0] %f bsdfSample->pdf %f f*cos/pdf %f\n",
ConcreteBxDF::Name(), bsdfSample->f[0] * AbsDot(wi, ns),
bsdfSample->pdf,
bsdfSample->f[0] * AbsDot(wi, ns) / bsdfSample->pdf);
// Update _uniPathPDF_ based on BSDF sample PDF
if (bsdfSample->pdfIsProportional) {
Float pdf = bsdf.PDF<BxDF>(wo, wi);
Float pdf = bsdf.PDF<ConcreteBxDF>(wo, wi);
T_hat *= pdf / bsdfSample->pdf;
uniPathPDF *= pdf;
} else
......@@ -215,7 +220,7 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
}
if (T_hat) {
// Enqueue ray in BSSRDF or indirect ray queue, as appropriate
// Enqueue ray in indirect ray queue or BSSRDF queue, as appropriate
if (bsdfSample->IsTransmission() &&
w.material->HasSubsurfaceScattering()) {
bssrdfEvalQueue->Push(w.material, lambda, T_hat, uniPathPDF,
......@@ -275,7 +280,7 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
if (!ls || !ls->L || ls->pdf == 0)
return;
Vector3f wi = ls->wi;
SampledSpectrum f = bsdf.f<BxDF>(wo, wi);
SampledSpectrum f = bsdf.f<ConcreteBxDF>(wo, wi);
if (!f)
return;
......@@ -294,7 +299,8 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
Float lightPDF = ls->pdf * sampledLight->pdf;
// This causes uniPathPDF to be zero for the shadow ray, so that
// part of MIS just becomes a no-op.
Float bsdfPDF = IsDeltaLight(light.Type()) ? 0.f : bsdf.PDF<BxDF>(wo, wi);
Float bsdfPDF =
IsDeltaLight(light.Type()) ? 0.f : bsdf.PDF<ConcreteBxDF>(wo, wi);
SampledSpectrum uniPathPDF = w.uniPathPDF * bsdfPDF;
SampledSpectrum lightPathPDF = w.uniPathPDF * lightPDF;
......@@ -306,8 +312,9 @@ void WavefrontPathIntegrator::EvaluateMaterialAndBSDF(TextureEvaluator texEval,
ray.medium = Dot(ray.d, w.n) > 0 ? w.mediumInterface.outside
: w.mediumInterface.inside;
shadowRayQueue->Push(ray, 1 - ShadowEpsilon, lambda, Ld, uniPathPDF,
lightPathPDF, w.pixelIndex);
shadowRayQueue->Push(ShadowRayWorkItem{ray, 1 - ShadowEpsilon, lambda, Ld,
uniPathPDF, lightPathPDF,
w.pixelIndex});
PBRT_DBG(
"w.index %d spawned shadow ray depth %d Ld %f %f %f %f "
......
......@@ -151,8 +151,9 @@ struct EscapedRayWorkItem {
int depth;
SampledWavelengths lambda;
int pixelIndex;
SampledSpectrum T_hat;
int specularBounce;
SampledSpectrum T_hat, uniPathPDF, lightPathPDF;
SampledSpectrum uniPathPDF, lightPathPDF;
LightSampleContext prevIntrCtx;
};
......@@ -164,8 +165,8 @@ struct HitAreaLightWorkItem {
Normal3f n;
Point2f uv;
Vector3f wo;
int depth;
SampledWavelengths lambda;
int depth;
SampledSpectrum T_hat, uniPathPDF, lightPathPDF;
LightSampleContext prevIntrCtx;
int isSpecularBounce;
......@@ -275,7 +276,7 @@ struct MediumScatterWorkItem {
};
// MaterialEvalWorkItem Definition
template <typename Material>
template <typename ConcreteMaterial>
struct MaterialEvalWorkItem {
// MaterialEvalWorkItem Public Methods
PBRT_CPU_GPU
......@@ -317,24 +318,24 @@ struct MaterialEvalWorkItem {
}
// MaterialEvalWorkItem Public Members
const Material *material;
const ConcreteMaterial *material;
Point3fi pi;
Normal3f n;
Vector3f dpdu, dpdv;
Float time;
int depth;
Normal3f ns;
Vector3f dpdus, dpdvs;
Normal3f dndus, dndvs;
Point2f uv;
int depth;
int faceIndex;
SampledWavelengths lambda;
int pixelIndex;
int anyNonSpecularBounces;
Vector3f wo;
int pixelIndex;
SampledSpectrum T_hat, uniPathPDF;
Float etaScale;
MediumInterface mediumInterface;
Float time;
};
#include "wavefront_workitems_soa.h"
......@@ -397,17 +398,7 @@ inline int RayQueue::PushIndirectRay(
}
// ShadowRayQueue Definition
class ShadowRayQueue : public WorkQueue<ShadowRayWorkItem> {
public:
using WorkQueue::WorkQueue;
// ShadowRayQueue Public Methods
PBRT_CPU_GPU
void Push(const Ray &ray, Float tMax, SampledWavelengths lambda, SampledSpectrum Ld,
SampledSpectrum uniPathPDF, SampledSpectrum lightPathPDF, int pixelIndex) {
WorkQueue<ShadowRayWorkItem>::Push(ShadowRayWorkItem{
ray, tMax, lambda, Ld, uniPathPDF, lightPathPDF, pixelIndex});
}
};
using ShadowRayQueue = WorkQueue<ShadowRayWorkItem>;
// EscapedRayQueue Definition
class EscapedRayQueue : public WorkQueue<EscapedRayWorkItem> {
......@@ -423,7 +414,7 @@ class EscapedRayQueue : public WorkQueue<EscapedRayWorkItem> {
inline int EscapedRayQueue::Push(RayWorkItem r) {
return Push(EscapedRayWorkItem{r.ray.o, r.ray.d, r.depth, r.lambda, r.pixelIndex,
(int)r.isSpecularBounce, r.T_hat, r.uniPathPDF,
r.T_hat, (int)r.isSpecularBounce, r.uniPathPDF,
r.lightPathPDF, r.prevIntrCtx});
}
......
......@@ -142,12 +142,12 @@ soa MediumSampleWorkItem {
MediumInterface mediumInterface;
};
soa MediumScatterWorkItem<PhaseFunction> {
soa MediumScatterWorkItem<ConcretePhaseFunction> {
Point3f p;
int depth;
SampledWavelengths lambda;
SampledSpectrum T_hat, uniPathPDF;
const PhaseFunction *phase;
const ConcretePhaseFunction *phase;
Vector3f wo;
Float time;
Float etaScale;
......@@ -155,8 +155,8 @@ soa MediumScatterWorkItem<PhaseFunction> {
int pixelIndex;
};
soa MaterialEvalWorkItem<Material> {
const Material *material;
soa MaterialEvalWorkItem<ConcreteMaterial> {
const ConcreteMaterial *material;
SampledWavelengths lambda;
SampledSpectrum T_hat, uniPathPDF;
Point3fi pi;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册