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

Update from book source. No functional changes.

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