提交 72b749ed 编写于 作者: M Matt Pharr

Update from book source. No functional changes.

上级 e2c6959f
......@@ -1153,11 +1153,12 @@ OptiXAggregate::ParamBufferState &OptiXAggregate::getParamBuffer(
}
void OptiXAggregate::IntersectClosest(
int maxRays, EscapedRayQueue *escapedRayQueue, HitAreaLightQueue *hitAreaLightQueue,
int maxRays, const RayQueue *rayQueue,
EscapedRayQueue *escapedRayQueue, HitAreaLightQueue *hitAreaLightQueue,
MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue,
RayQueue *rayQueue, RayQueue *nextRayQueue) const {
RayQueue *nextRayQueue) const {
std::pair<cudaEvent_t, cudaEvent_t> events =
GetProfilerEvents("Tracing closest hit rays");
......
......@@ -34,10 +34,10 @@ class OptiXAggregate : public WavefrontAggregate {
Bounds3f Bounds() const { return bounds; }
void IntersectClosest(
int maxRays, EscapedRayQueue *escapedRayQueue,
int maxRays, const RayQueue *rayQueue, EscapedRayQueue *escapedRayQueue,
HitAreaLightQueue *hitAreaLightQueue, MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue, RayQueue *rayQueue, RayQueue *nextRayQueue) const;
MediumSampleQueue *mediumSampleQueue, RayQueue *nextRayQueue) const;
void IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const;
......
......@@ -50,7 +50,7 @@ struct QuadricRecord {
struct RayIntersectParameters {
OptixTraversableHandle traversable;
RayQueue *rayQueue;
const RayQueue *rayQueue;
// closest hit
RayQueue *nextRayQueue;
......
......@@ -1004,7 +1004,7 @@ struct tuple<T, Ts...> : tuple<Ts...> {
};
template <typename... Ts>
tuple(Ts &&...)->tuple<std::decay_t<Ts>...>;
tuple(Ts &&...) -> tuple<std::decay_t<Ts>...>;
template <size_t I, typename T, typename... Ts>
PBRT_CPU_GPU auto &get(tuple<T, Ts...> &t) {
......
......@@ -41,29 +41,6 @@ PBRT_CPU_GPU inline Float HenyeyGreenstein(Float cosTheta, Float g) {
}
// Fresnel Inline Functions
PBRT_CPU_GPU
inline Float FrComplex(Float cosTheta_i, pstd::complex<Float> eta) {
cosTheta_i = Clamp(cosTheta_i, 0, 1);
using Complex = pstd::complex<Float>;
// Compute _cosTheta_t_ using Snell's law
Complex sinTheta_i = pstd::sqrt(1.f - cosTheta_i * cosTheta_i);
Complex sinTheta_t = sinTheta_i / eta;
Complex cosTheta_t = pstd::sqrt(1.f - sinTheta_t * sinTheta_t);
Complex r_parl = (eta * cosTheta_i - cosTheta_t) / (eta * cosTheta_i + cosTheta_t);
Complex r_perp = (eta * cosTheta_t - cosTheta_i) / (eta * cosTheta_t + cosTheta_i);
return (pstd::norm(r_parl) + pstd::norm(r_perp)) * .5f;
}
PBRT_CPU_GPU
inline SampledSpectrum FrComplex(Float cosTheta_i, SampledSpectrum eta,
SampledSpectrum k) {
SampledSpectrum result;
for (int i = 0; i < NSpectrumSamples; ++i)
result[i] = FrComplex(cosTheta_i, pstd::complex<Float>(eta[i], k[i]));
return result;
}
PBRT_CPU_GPU
inline Float FrDielectric(Float cosTheta_i, Float eta) {
cosTheta_i = Clamp(cosTheta_i, -1, 1);
......@@ -88,6 +65,29 @@ inline Float FrDielectric(Float cosTheta_i, Float eta) {
return (r_parl * r_parl + r_perp * r_perp) / 2;
}
PBRT_CPU_GPU
inline Float FrComplex(Float cosTheta_i, pstd::complex<Float> eta) {
cosTheta_i = Clamp(cosTheta_i, 0, 1);
using Complex = pstd::complex<Float>;
// Compute _cosTheta_t_ using Snell's law
Complex sinTheta_i = pstd::sqrt(1.f - cosTheta_i * cosTheta_i);
Complex sinTheta_t = sinTheta_i / eta;
Complex cosTheta_t = pstd::sqrt(1.f - sinTheta_t * sinTheta_t);
Complex r_parl = (eta * cosTheta_i - cosTheta_t) / (eta * cosTheta_i + cosTheta_t);
Complex r_perp = (eta * cosTheta_t - cosTheta_i) / (eta * cosTheta_t + cosTheta_i);
return (pstd::norm(r_parl) + pstd::norm(r_perp)) * .5f;
}
PBRT_CPU_GPU
inline SampledSpectrum FrComplex(Float cosTheta_i, SampledSpectrum eta,
SampledSpectrum k) {
SampledSpectrum result;
for (int i = 0; i < NSpectrumSamples; ++i)
result[i] = FrComplex(cosTheta_i, pstd::complex<Float>(eta[i], k[i]));
return result;
}
// BSSRDF Utility Declarations
PBRT_CPU_GPU
Float FresnelMoment1(Float invEta);
......
......@@ -20,100 +20,101 @@
namespace pbrt {
CPUAggregate::CPUAggregate(ParsedScene &scene, Allocator alloc,
NamedTextures &textures,
const std::map<int, pstd::vector<Light> *> &shapeIndexToAreaLights,
const std::map<std::string, Medium> &media,
const std::map<std::string, pbrt::Material> &namedMaterials,
const std::vector<pbrt::Material> &materials) {
CPUAggregate::CPUAggregate(
ParsedScene &scene, Allocator alloc, NamedTextures &textures,
const std::map<int, pstd::vector<Light> *> &shapeIndexToAreaLights,
const std::map<std::string, Medium> &media,
const std::map<std::string, pbrt::Material> &namedMaterials,
const std::vector<pbrt::Material> &materials) {
aggregate = scene.CreateAggregate(alloc, textures, shapeIndexToAreaLights, media,
namedMaterials, materials);
}
void CPUAggregate::IntersectClosest(int maxRays, EscapedRayQueue *escapedRayQueue,
HitAreaLightQueue *hitAreaLightQueue,
MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue,
RayQueue *rayQueue, RayQueue *nextRayQueue) const {
ParallelFor(0, rayQueue->Size(),
[=](int index) {
const RayWorkItem r = (*rayQueue)[index];
pstd::optional<ShapeIntersection> si = aggregate.Intersect(r.ray, Infinity);
if (!si) {
EnqueueWorkAfterMiss(r, mediumSampleQueue, escapedRayQueue);
} else {
const SurfaceInteraction &intr = si->intr;
Float tHit = Distance(r.ray.o, intr.p()) / Length(r.ray.d);
MediumInterface mediumInterface = intr.mediumInterface ? *intr.mediumInterface :
MediumInterface(r.ray.medium);
EnqueueWorkAfterIntersection(r, r.ray.medium /* FIXME DIFF THAN OPTIX WOT */, tHit,
si->intr, mediumSampleQueue,
nextRayQueue, hitAreaLightQueue,
basicEvalMaterialQueue, universalEvalMaterialQueue,
mediumInterface);
}
});
// CPUAggregate Method Definitions
void CPUAggregate::IntersectClosest(int maxRays, const RayQueue *rayQueue,
EscapedRayQueue *escapedRayQueue,
HitAreaLightQueue *hitAreaLightQueue,
MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue,
RayQueue *nextRayQueue) const {
// _CPUAggregate::IntersectClosest()_ method implementation
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);
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);
// 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);
}
});
}
void CPUAggregate::IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const {
ParallelFor(0, shadowRayQueue->Size(),
[=](int index) {
const ShadowRayWorkItem w = (*shadowRayQueue)[index];
RecordShadowRayIntersection(w, pixelSampleState,
aggregate.IntersectP(w.ray, w.tMax));
});
SOA<PixelSampleState> *pixelSampleState) const {
ParallelFor(0, shadowRayQueue->Size(), [=](int index) {
const ShadowRayWorkItem w = (*shadowRayQueue)[index];
bool hit = aggregate.IntersectP(w.ray, w.tMax);
RecordShadowRayIntersection(w, pixelSampleState, hit);
});
}
void CPUAggregate::IntersectShadowTr(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const {
ParallelFor(0, shadowRayQueue->Size(),
[=](int index) {
const ShadowRayWorkItem w = (*shadowRayQueue)[index];
pstd::optional<ShapeIntersection> si;
TraceTransmittance(w, pixelSampleState,
[&](Ray ray, Float tMax) -> TransmittanceTraceResult {
si = aggregate.Intersect(ray, tMax);
SOA<PixelSampleState> *pixelSampleState) const {
ParallelFor(0, shadowRayQueue->Size(), [=](int index) {
const ShadowRayWorkItem w = (*shadowRayQueue)[index];
pstd::optional<ShapeIntersection> si;
TraceTransmittance(
w, pixelSampleState,
[&](Ray ray, Float tMax) -> TransmittanceTraceResult {
si = aggregate.Intersect(ray, tMax);
if (!si)
return TransmittanceTraceResult{false, Point3f(), Material()};
else
return TransmittanceTraceResult{true, si->intr.p(), si->intr.material};
},
[&](Point3f p) -> Ray {
return si->intr.SpawnRayTo(p);
});
});
if (!si)
return TransmittanceTraceResult{false, Point3f(), Material()};
else
return TransmittanceTraceResult{true, si->intr.p(),
si->intr.material};
},
[&](Point3f p) -> Ray { return si->intr.SpawnRayTo(p); });
});
}
void CPUAggregate::IntersectOneRandom(int maxRays, SubsurfaceScatterQueue *subsurfaceScatterQueue) const {
ParallelFor(0, subsurfaceScatterQueue->Size(),
[=](int index) {
const SubsurfaceScatterWorkItem &w = (*subsurfaceScatterQueue)[index];
uint64_t seed = Hash(w.p0, w.p1);
void CPUAggregate::IntersectOneRandom(
int maxRays, SubsurfaceScatterQueue *subsurfaceScatterQueue) const {
ParallelFor(0, subsurfaceScatterQueue->Size(), [=](int index) {
const SubsurfaceScatterWorkItem &w = (*subsurfaceScatterQueue)[index];
uint64_t seed = Hash(w.p0, w.p1);
WeightedReservoirSampler<SubsurfaceInteraction> wrs(seed);
Interaction base(w.p0, 0.f /* FIXME time */, Medium());
while (true) {
Ray r = base.SpawnRayTo(w.p1);
if (r.d == Vector3f(0, 0, 0))
break;
pstd::optional<ShapeIntersection> si = aggregate.Intersect(r, 1);
if (!si)
break;
base = si->intr;
if (si->intr.material == w.material)
wrs.Add(SubsurfaceInteraction(si->intr), 1.f);
}
WeightedReservoirSampler<SubsurfaceInteraction> wrs(seed);
Interaction base(w.p0, 0.f /* FIXME time */, Medium());
while (true) {
Ray r = base.SpawnRayTo(w.p1);
if (r.d == Vector3f(0, 0, 0))
break;
pstd::optional<ShapeIntersection> si = aggregate.Intersect(r, 1);
if (!si)
break;
base = si->intr;
if (si->intr.material == w.material)
wrs.Add(SubsurfaceInteraction(si->intr), 1.f);
}
if (wrs.HasSample()) {
subsurfaceScatterQueue->reservoirPDF[index] = wrs.SamplePDF();
subsurfaceScatterQueue->ssi[index] = wrs.GetSample();
} else
subsurfaceScatterQueue->reservoirPDF[index] = 0;
});
if (wrs.HasSample()) {
subsurfaceScatterQueue->reservoirPDF[index] = wrs.SamplePDF();
subsurfaceScatterQueue->ssi[index] = wrs.GetSample();
} else
subsurfaceScatterQueue->reservoirPDF[index] = 0;
});
}
} // namespace pbrt
......@@ -33,10 +33,10 @@ class CPUAggregate : public WavefrontAggregate {
Bounds3f Bounds() const { return aggregate.Bounds(); }
void IntersectClosest(
int maxRays, EscapedRayQueue *escapedRayQueue,
int maxRays, const RayQueue *rayQueue, EscapedRayQueue *escapedRayQueue,
HitAreaLightQueue *hitAreaLightQueue, MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue, RayQueue *rayQueue, RayQueue *nextRayQueue) const;
MediumSampleQueue *mediumSampleQueue, RayQueue *nextRayQueue) const;
void IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const;
......
......@@ -18,16 +18,16 @@ namespace pbrt {
void WavefrontPathIntegrator::GenerateCameraRays(int y0, int sampleIndex) {
// Define _generateRays_ lambda function
auto generateRays = [=](auto sampler) {
using Sampler = std::remove_reference_t<decltype(*sampler)>;
if constexpr (!std::is_same_v<Sampler, MLTSampler> &&
!std::is_same_v<Sampler, DebugMLTSampler>)
GenerateCameraRays<Sampler>(y0, sampleIndex);
using ConcreteSampler = std::remove_reference_t<decltype(*sampler)>;
if constexpr (!std::is_same_v<ConcreteSampler, MLTSampler> &&
!std::is_same_v<ConcreteSampler, DebugMLTSampler>)
GenerateCameraRays<ConcreteSampler>(y0, sampleIndex);
};
sampler.DispatchCPU(generateRays);
}
template <typename Sampler>
template <typename ConcreteSampler>
void WavefrontPathIntegrator::GenerateCameraRays(int y0, int sampleIndex) {
RayQueue *rayQueue = CurrentRayQueue(0);
ParallelFor(
......@@ -45,7 +45,7 @@ void WavefrontPathIntegrator::GenerateCameraRays(int y0, int sampleIndex) {
return;
// Initialize _Sampler_ for current pixel and sample
Sampler pixelSampler = *sampler.Cast<Sampler>();
ConcreteSampler pixelSampler = *sampler.Cast<ConcreteSampler>();
pixelSampler.StartPixelSample(pPixel, sampleIndex, 0);
// Sample wavelengths for ray path
......@@ -54,7 +54,7 @@ void WavefrontPathIntegrator::GenerateCameraRays(int y0, int sampleIndex) {
lu = 0.5f;
SampledWavelengths lambda = film.SampleWavelengths(lu);
// Compute _CameraSample_ and generate ray
// Generate _CameraSample_ and corresponding ray
CameraSample cameraSample = GetCameraSample(pixelSampler, pPixel, filter);
pstd::optional<CameraRay> cameraRay =
camera.GenerateRay(cameraSample, lambda);
......
......@@ -127,7 +127,7 @@ WavefrontPathIntegrator::WavefrontPathIntegrator(Allocator alloc, ParsedScene &s
pstd::vector<Light> allLights;
envLights = alloc.new_object<pstd::vector<Light>>(alloc);
infiniteLights = alloc.new_object<pstd::vector<Light>>(alloc);
for (const auto &light : scene.lights) {
Medium outsideMedium = findMedium(light.medium, &light.loc);
if (light.renderFromObject.IsAnimated())
......@@ -140,7 +140,7 @@ WavefrontPathIntegrator::WavefrontPathIntegrator(Allocator alloc, ParsedScene &s
if (l.Is<UniformInfiniteLight>() || l.Is<ImageInfiniteLight>() ||
l.Is<PortalImageInfiniteLight>())
envLights->push_back(l);
infiniteLights->push_back(l);
allLights.push_back(l);
}
......@@ -314,7 +314,7 @@ WavefrontPathIntegrator::WavefrontPathIntegrator(Allocator alloc, ParsedScene &s
alloc.new_object<SubsurfaceScatterQueue>(maxQueueSize, alloc);
}
if (envLights->size())
if (infiniteLights->size())
escapedRayQueue = alloc.new_object<EscapedRayQueue>(maxQueueSize, alloc);
hitAreaLightQueue = alloc.new_object<HitAreaLightQueue>(maxQueueSize, alloc);
......@@ -348,6 +348,9 @@ WavefrontPathIntegrator::WavefrontPathIntegrator(Allocator alloc, ParsedScene &s
// WavefrontPathIntegrator Method Definitions
Float WavefrontPathIntegrator::Render() {
Bounds2i pixelBounds = film.PixelBounds();
Vector2i resolution = pixelBounds.Diagonal();
Timer timer;
// Prefetch allocations to GPU memory
#ifdef PBRT_BUILD_GPU_RENDERER
if (Options->useGPU) {
......@@ -387,9 +390,6 @@ Float WavefrontPathIntegrator::Render() {
}
#endif // PBRT_BUILD_GPU_RENDERER
Timer timer;
Vector2i resolution = film.PixelBounds().Diagonal();
Bounds2i pixelBounds = film.PixelBounds();
// Launch thread to copy image for display server, if enabled
RGB *displayRGB = nullptr, *displayRGBHost = nullptr;
std::atomic<bool> exitCopyThread{false};
......@@ -471,21 +471,31 @@ Float WavefrontPathIntegrator::Render() {
});
}
// Loop over sample indices and evaluate pixel samples
int firstSampleIndex = 0, lastSampleIndex = samplesPerPixel;
// Update sample index range based on debug start, if provided
if (!Options->debugStart.empty()) {
std::vector<int> values = SplitStringToInts(Options->debugStart, ',');
if (values.size() != 2)
ErrorExit("Expected two integer values for --debugstart.");
if (values.size() != 1 && values.size() != 2)
ErrorExit("Expected either one or two integer values for --debugstart.");
firstSampleIndex = values[0];
lastSampleIndex = firstSampleIndex + values[1];
if (values.size() == 2)
lastSampleIndex = firstSampleIndex + values[1];
else
lastSampleIndex = firstSampleIndex + 1;
}
ProgressReporter progress(lastSampleIndex - firstSampleIndex, "Rendering",
Options->quiet, Options->useGPU);
for (int sampleIndex = firstSampleIndex; sampleIndex < lastSampleIndex;
++sampleIndex) {
CheckCallbackScope _([&]() {
return StringPrintf("Wavefrontrendering failed at sample %d. Debug with "
"\"--debugstart %d\"\n",
sampleIndex, sampleIndex);
});
// Render image for sample _sampleIndex_
LOG_VERBOSE("Starting to submit work for sample %d", sampleIndex);
for (int y0 = pixelBounds.pMin.y; y0 < pixelBounds.pMax.y;
......@@ -531,11 +541,12 @@ Float WavefrontPathIntegrator::Render() {
// Follow active ray paths and accumulate radiance estimates
GenerateRaySamples(wavefrontDepth, sampleIndex);
// Find closest intersections along active rays
aggregate->IntersectClosest(
maxQueueSize, escapedRayQueue, hitAreaLightQueue,
basicEvalMaterialQueue, universalEvalMaterialQueue, mediumSampleQueue,
CurrentRayQueue(wavefrontDepth), NextRayQueue(wavefrontDepth));
maxQueueSize, CurrentRayQueue(wavefrontDepth), escapedRayQueue,
hitAreaLightQueue, basicEvalMaterialQueue, universalEvalMaterialQueue,
mediumSampleQueue, NextRayQueue(wavefrontDepth));
if (wavefrontDepth > 0) {
// As above, with the indexing...
......@@ -545,18 +556,22 @@ Float WavefrontPathIntegrator::Render() {
stats->indirectRays[wavefrontDepth] += statsQueue->Size();
});
}
if (haveMedia)
SampleMediumInteraction(wavefrontDepth);
if (escapedRayQueue)
HandleEscapedRays();
HandleRayFoundEmission();
SampleMediumInteraction(wavefrontDepth);
HandleEscapedRays();
HandleEmissiveIntersection();
if (wavefrontDepth == maxDepth)
break;
EvaluateMaterialsAndBSDFs(wavefrontDepth);
// Do immediately so that we have space for shadow rays for subsurface..
TraceShadowRays(wavefrontDepth);
if (haveSubsurface)
SampleSubsurface(wavefrontDepth);
SampleSubsurface(wavefrontDepth);
}
UpdateFilm();
......@@ -579,6 +594,7 @@ Float WavefrontPathIntegrator::Render() {
progress.Update();
}
progress.Done();
#ifdef PBRT_BUILD_GPU_RENDERER
if (Options->useGPU)
GPUWait();
......@@ -604,12 +620,15 @@ 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
SampledSpectrum L(0.f);
for (const auto &light : *envLights) {
for (const auto &light : *infiniteLights) {
if (SampledSpectrum Le = light.Le(Ray(w.rayo, w.rayd), w.lambda); Le) {
// Compute path radiance contribution from infinite light
PBRT_DBG("L %f %f %f %f T_hat %f %f %f %f Le %f %f %f %f", L[0], L[1],
......@@ -643,7 +662,7 @@ void WavefrontPathIntegrator::HandleEscapedRays() {
});
}
void WavefrontPathIntegrator::HandleRayFoundEmission() {
void WavefrontPathIntegrator::HandleEmissiveIntersection() {
ForAllQueued(
"Handle emitters hit by indirect rays", hitAreaLightQueue, maxQueueSize,
PBRT_CPU_GPU_LAMBDA(const HitAreaLightWorkItem w) {
......
......@@ -30,16 +30,18 @@ class ParsedScene;
// WavefrontAggregate Definition
class WavefrontAggregate {
public:
// WavefrontAggregate Interface
virtual ~WavefrontAggregate() = default;
virtual Bounds3f Bounds() const = 0;
virtual void IntersectClosest(int maxRays, EscapedRayQueue *escapedRayQueue,
HitAreaLightQueue *hitAreaLightQueue,
MaterialEvalQueue *basicEvalMaterialQueue,
MaterialEvalQueue *universalEvalMaterialQueue,
MediumSampleQueue *mediumSampleQueue,
RayQueue *rayQueue, RayQueue *nextRayQueue) const = 0;
virtual void IntersectClosest(int maxRays, const RayQueue *rayQ,
EscapedRayQueue *escapedRayQ,
HitAreaLightQueue *hitAreaLightQ,
MaterialEvalQueue *basicMtlQ,
MaterialEvalQueue *universalMtlQ,
MediumSampleQueue *mediumSampleQ,
RayQueue *nextRayQ) const = 0;
virtual void IntersectShadow(int maxRays, ShadowRayQueue *shadowRayQueue,
SOA<PixelSampleState> *pixelSampleState) const = 0;
......@@ -72,7 +74,7 @@ class WavefrontPathIntegrator {
void SampleSubsurface(int wavefrontDepth);
void HandleEscapedRays();
void HandleRayFoundEmission();
void HandleEmissiveIntersection();
void EvaluateMaterialsAndBSDFs(int wavefrontDepth);
template <typename Mtl>
......@@ -91,33 +93,32 @@ class WavefrontPathIntegrator {
void UpdateFilm();
WavefrontPathIntegrator(Allocator alloc, ParsedScene &scene);
template <typename F>
void ParallelFor(const char *description, int nItems, F &&func) {
if (Options->useGPU) {
if (Options->useGPU)
#ifdef PBRT_BUILD_GPU_RENDERER
GPUParallelFor(description, nItems, func);
#else
LOG_FATAL("Options->useGPU was set without PBRT_BUILD_GPU_RENDERER enabled");
#endif
} else
else
pbrt::ParallelFor(0, nItems, func);
}
template <typename F>
void Do(const char *description, F &&func) {
if (Options->useGPU) {
if (Options->useGPU)
#ifdef PBRT_BUILD_GPU_RENDERER
GPUParallelFor(
description, 1, PBRT_CPU_GPU_LAMBDA(int) { func(); });
GPUParallelFor(description, 1, [=] PBRT_GPU(int) { func(); });
#else
LOG_FATAL("Options->useGPU was set without PBRT_BUILD_GPU_RENDERER enabled");
#endif
} else
else
func();
}
WavefrontPathIntegrator(Allocator alloc, ParsedScene &scene);
RayQueue *CurrentRayQueue(int wavefrontDepth) {
return rayQueues[wavefrontDepth & 1];
}
......@@ -143,13 +144,11 @@ class WavefrontPathIntegrator {
};
Stats *stats;
WavefrontAggregate *aggregate = nullptr;
Filter filter;
Film film;
Sampler sampler;
Camera camera;
pstd::vector<Light> *envLights;
pstd::vector<Light> *infiniteLights;
LightSampler lightSampler;
int maxDepth, samplesPerPixel;
......@@ -161,6 +160,8 @@ class WavefrontPathIntegrator {
RayQueue *rayQueues[2];
WavefrontAggregate *aggregate = nullptr;
MediumSampleQueue *mediumSampleQueue = nullptr;
MediumScatterQueue *mediumScatterQueue = nullptr;
......
此差异已折叠。
......@@ -44,6 +44,9 @@ struct SampleMediumScatteringCallback {
// WavefrontPathIntegrator Participating Media Methods
void WavefrontPathIntegrator::SampleMediumInteraction(int wavefrontDepth) {
if (!haveMedia)
return;
RayQueue *nextRayQueue = NextRayQueue(wavefrontDepth);
ForAllQueued(
"Sample medium interaction", mediumSampleQueue, maxQueueSize,
......
......@@ -14,18 +14,18 @@ namespace pbrt {
// WavefrontPathIntegrator Sampler Methods
void WavefrontPathIntegrator::GenerateRaySamples(int wavefrontDepth, int sampleIndex) {
auto generateSamples = [=](auto sampler) {
using Sampler = std::remove_reference_t<decltype(*sampler)>;
if constexpr (!std::is_same_v<Sampler, MLTSampler> &&
!std::is_same_v<Sampler, DebugMLTSampler>)
GenerateRaySamples<Sampler>(wavefrontDepth, sampleIndex);
using ConcreteSampler = std::remove_reference_t<decltype(*sampler)>;
if constexpr (!std::is_same_v<ConcreteSampler, MLTSampler> &&
!std::is_same_v<ConcreteSampler, DebugMLTSampler>)
GenerateRaySamples<ConcreteSampler>(wavefrontDepth, sampleIndex);
};
sampler.DispatchCPU(generateSamples);
}
template <typename Sampler>
template <typename ConcreteSampler>
void WavefrontPathIntegrator::GenerateRaySamples(int wavefrontDepth, int sampleIndex) {
// Generate description string _desc_ for ray sample generation
std::string desc = std::string("Generate ray samples - ") + Sampler::Name();
std::string desc = std::string("Generate ray samples - ") + ConcreteSampler::Name();
RayQueue *rayQueue = CurrentRayQueue(wavefrontDepth);
ForAllQueued(
......@@ -39,7 +39,7 @@ void WavefrontPathIntegrator::GenerateRaySamples(int wavefrontDepth, int sampleI
dimension += 2 * w.depth;
// Initialize _Sampler_ for pixel, sample index, and dimension
Sampler pixelSampler = *sampler.Cast<Sampler>();
ConcreteSampler pixelSampler = *sampler.Cast<ConcreteSampler>();
Point2i pPixel = pixelSampleState.pPixel[w.pixelIndex];
pixelSampler.StartPixelSample(pPixel, sampleIndex, dimension);
......@@ -47,7 +47,7 @@ void WavefrontPathIntegrator::GenerateRaySamples(int wavefrontDepth, int sampleI
RaySamples rs;
rs.direct.uc = pixelSampler.Get1D();
rs.direct.u = pixelSampler.Get2D();
// Initialize indirect and possibly subsurface samples in _rs_
// Initialize indirect and possibly subsurface and medium samples in _rs_
rs.indirect.uc = pixelSampler.Get1D();
rs.indirect.u = pixelSampler.Get2D();
rs.indirect.rr = pixelSampler.Get1D();
......
......@@ -16,6 +16,9 @@ namespace pbrt {
// WavefrontPathIntegrator Subsurface Scattering Methods
void WavefrontPathIntegrator::SampleSubsurface(int wavefrontDepth) {
if (!haveSubsurface)
return;
RayQueue *rayQueue = CurrentRayQueue(wavefrontDepth);
RayQueue *nextRayQueue = NextRayQueue(wavefrontDepth);
......
......@@ -156,9 +156,6 @@ struct EscapedRayWorkItem {
LightSampleContext prevIntrCtx;
};
// EscapedRayQueue Definition
using EscapedRayQueue = WorkQueue<EscapedRayWorkItem>;
// HitAreaLightWorkItem Definition
struct HitAreaLightWorkItem {
// HitAreaLightWorkItem Public Members
......@@ -412,6 +409,24 @@ class ShadowRayQueue : public WorkQueue<ShadowRayWorkItem> {
}
};
// EscapedRayQueue Definition
class EscapedRayQueue : public WorkQueue<EscapedRayWorkItem> {
public:
// EscapedRayQueue Public Methods
PBRT_CPU_GPU
int Push(RayWorkItem r);
using WorkQueue::WorkQueue;
using WorkQueue::Push;
};
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.lightPathPDF, r.prevIntrCtx});
}
// GetBSSRDFAndProbeRayQueue Definition
class GetBSSRDFAndProbeRayQueue : public WorkQueue<GetBSSRDFAndProbeRayWorkItem> {
public:
......@@ -492,6 +507,13 @@ class MediumSampleQueue : public WorkQueue<MediumSampleWorkItem> {
this->etaScale[index] = etaScale;
return index;
}
PBRT_CPU_GPU
int Push(RayWorkItem r, Float tMax) {
return Push(r.ray, tMax, r.lambda, r.T_hat, r.uniPathPDF, r.lightPathPDF,
r.pixelIndex, r.prevIntrCtx, r.isSpecularBounce,
r.anyNonSpecularBounces, r.etaScale);
}
};
// MediumScatterQueue Definition
......
......@@ -116,10 +116,12 @@ class WorkQueue : public SOA<WorkItem> {
// WorkQueue Inline Functions
template <typename F, typename WorkItem>
void ForAllQueued(const char *desc, WorkQueue<WorkItem> *q, int maxQueued, F &&func) {
if (Options->useGPU)
void ForAllQueued(const char *desc, const WorkQueue<WorkItem> *q, int maxQueued,
F &&func) {
if (Options->useGPU) {
// Launch GPU threads to process _q_ using _func_
#ifdef PBRT_BUILD_GPU_RENDERER
GPUParallelFor(desc, maxQueued, [=] PBRT_GPU(int index) mutable {
GPUParallelFor(desc, maxQueued, [=] PBRT_GPU(int index) {
if (index >= q->Size())
return;
func((*q)[index]);
......@@ -127,8 +129,11 @@ void ForAllQueued(const char *desc, WorkQueue<WorkItem> *q, int maxQueued, F &&f
#else
LOG_FATAL("Options->useGPU was set without PBRT_BUILD_GPU_RENDERER enabled");
#endif
else
} else {
// Process _q_ using _func_ with CPU threads
ParallelFor(0, q->Size(), [&](int index) { func((*q)[index]); });
}
}
// MultiWorkQueue Definition
......@@ -157,6 +162,7 @@ class MultiWorkQueue<TypePack<Ts...>> {
PBRT_CPU_GPU int Push(const T &value) {
return Get<T>()->Push(value);
}
PBRT_CPU_GPU
void Reset() { (Get<Ts>()->Reset(), ...); }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册