55#include <nbl/builtin/hlsl/colorspace/encodeCIEXYZ.hlsl>
66#include <nbl/builtin/hlsl/math/functions.hlsl>
77#include <nbl/builtin/hlsl/bxdf/bxdf_traits.hlsl>
8+ #include <nbl/builtin/hlsl/vector_utils/vector_traits.hlsl>
89
910#include "rand_gen.hlsl"
1011#include "ray_gen.hlsl"
@@ -40,10 +41,30 @@ struct PathTracerCreationParams
4041 BxDFCreation dielectricParams;
4142};
4243
43- template<class RandGen, class RayGen, class Intersector, class MaterialSystem, /* class PathGuider, */ class NextEventEstimator>
44+ // TODO: maybe implement a concept to ensure that OutputTypeVec is a vector?
45+ template<typename OutputTypeVec>
46+ struct DefaultAccumulator
47+ {
48+ using output_storage_type = OutputTypeVec;
49+ output_storage_type accumulation;
50+
51+ void initialize ()
52+ {
53+ accumulation = (output_storage_type)0.0f ;
54+ }
55+
56+ void addSample (uint32_t sampleIndex, float32_t3 sample )
57+ {
58+ using ScalarType = typename vector_traits<OutputTypeVec>::scalar_type;
59+ ScalarType rcpSampleSize = 1.0 / (sampleIndex + 1 );
60+ accumulation += (sample - accumulation) * rcpSampleSize;
61+ }
62+ };
63+
64+ template<class RandGen, class RayGen, class Intersector, class MaterialSystem, /* class PathGuider, */ class NextEventEstimator, class Accumulator>
4465struct Unidirectional
4566{
46- using this_t = Unidirectional<RandGen, RayGen, Intersector, MaterialSystem, NextEventEstimator>;
67+ using this_t = Unidirectional<RandGen, RayGen, Intersector, MaterialSystem, NextEventEstimator, Accumulator >;
4768 using randgen_type = RandGen;
4869 using raygen_type = RayGen;
4970 using intersector_type = Intersector;
@@ -53,6 +74,7 @@ struct Unidirectional
5374 using scalar_type = typename MaterialSystem::scalar_type;
5475 using vector3_type = vector <scalar_type, 3 >;
5576 using measure_type = typename MaterialSystem::measure_type;
77+ using output_storage_type = typename Accumulator::output_storage_type;
5678 using sample_type = typename NextEventEstimator::sample_type;
5779 using ray_dir_info_type = typename sample_type::ray_dir_info_type;
5880 using ray_type = typename RayGen::ray_type;
@@ -265,105 +287,40 @@ struct Unidirectional
265287 // #endif
266288 }
267289
268- measure_type getSingleSampleMeasure (uint32_t sampleID, uint32_t depth, NBL_CONST_REF_ARG (scene_type) scene)
269- {
270- vector3_type uvw = rand3d (0u, sampleID, randGen.rng ()); // TODO: take from scramblebuf?
271- ray_type ray = rayGen.generate (uvw);
272-
273- // bounces
274- bool hit = true ;
275- bool rayAlive = true ;
276- for (int d = 1 ; (d <= depth) && hit && rayAlive; d += 2 )
277- {
278- ray.intersectionT = numeric_limits<scalar_type>::max ;
279- ray.objectID = intersector_type::traceRay (ray, scene);
280-
281- hit = ray.objectID.id != -1 ;
282- if (hit)
283- rayAlive = closestHitProgram (1 , sampleID, ray, scene);
284- }
285- if (!hit)
286- missProgram (ray);
287-
288- return ray.payload.accumulation;
289- }
290-
291290 // Li
292- measure_type getMeasure (uint32_t numSamples, uint32_t depth, NBL_CONST_REF_ARG (scene_type) scene)
291+ output_storage_type getMeasure (uint32_t numSamples, uint32_t depth, NBL_CONST_REF_ARG (scene_type) scene)
293292 {
294- measure_type Li = (measure_type)0.0 ;
293+ Accumulator accumulator;
294+ accumulator.initialize ();
295295 //scalar_type meanLumaSq = 0.0;
296296 for (uint32_t i = 0 ; i < numSamples; i++)
297297 {
298- measure_type accumulation = getSingleSampleMeasure (i, depth, scene);
299- scalar_type rcpSampleSize = 1.0 / (i + 1 );
300- Li += (accumulation - Li) * rcpSampleSize;
298+ vector3_type uvw = rand3d (0u, i, randGen.rng ()); // TODO: take from scramblebuf?
299+ ray_type ray = rayGen.generate (uvw);
301300
302- // TODO: visualize high variance
303-
304- // TODO: russian roulette early exit?
305- }
306-
307- return Li;
308- }
309-
310- struct RWMCCascadeSettings
311- {
312- uint32_t size;
313- uint32_t start;
314- uint32_t base;
315- };
316-
317- void generateCascade (int32_t2 coords, uint32_t numSamples, uint32_t depth, NBL_CONST_REF_ARG (RWMCCascadeSettings) cascadeSettings, NBL_CONST_REF_ARG (scene_type) scene)
318- {
319- // TODO: move `MaxCascadeSize` somewhere else
320- const static uint32_t MaxCascadeSize = 10u;
321- float32_t4 cascadeEntry[MaxCascadeSize];
322- for (int i = 0 ; i < MaxCascadeSize; ++i)
323- cascadeEntry[i] = float32_t4 (0.0f , 0.0f , 0.0f , 0.0f );
324-
325- float lowerScale = cascadeSettings.start;
326- float upperScale = lowerScale * cascadeSettings.base;
327-
328- // most of this code is stolen from https://cg.ivd.kit.edu/publications/2018/rwmc/tool/split.cpp
329- for (uint32_t i = 0 ; i < numSamples; i++)
330- {
331- measure_type accumulation = getSingleSampleMeasure (i, depth, scene);
332-
333- const float luma = getLuma (accumulation);
334-
335- uint32_t lowerCascadeIndex = 0u;
336- while (!(luma < upperScale) && lowerCascadeIndex < cascadeSettings.size - 2 )
301+ // bounces
302+ bool hit = true ;
303+ bool rayAlive = true ;
304+ for (int d = 1 ; (d <= depth) && hit && rayAlive; d += 2 )
337305 {
338- lowerScale = upperScale;
339- upperScale *= cascadeSettings.base;
340- ++lowerCascadeIndex;
341- }
306+ ray.intersectionT = numeric_limits<scalar_type>::max ;
307+ ray.objectID = intersector_type::traceRay (ray, scene);
342308
343- float lowerCascadeLevelWeight;
344- float higherCascadeLevelWeight;
309+ hit = ray.objectID.id != -1 ;
310+ if (hit)
311+ rayAlive = closestHitProgram (1 , i, ray, scene);
312+ }
313+ if (!hit)
314+ missProgram (ray);
345315
346- if (luma <= lowerScale)
347- lowerCascadeLevelWeight = 1.0f ;
348- else if (luma < upperScale)
349- lowerCascadeLevelWeight = max (0.0f , (lowerScale / luma - lowerScale / upperScale) / (1.0f - lowerScale / upperScale));
350- else // Inf, NaN ...
351- lowerCascadeLevelWeight = 0.0f ;
316+ accumulator.addSample (i, ray.payload.accumulation);
352317
353- if (luma < upperScale)
354- higherCascadeLevelWeight = max (0.0f , 1.0f - lowerCascadeLevelWeight);
355- else
356- higherCascadeLevelWeight = upperScale / luma;
318+ // TODO: visualize high variance
357319
358- // TODO: odrazu liczyc srednia
359- cascadeEntry[lowerCascadeIndex] += float32_t4 (accumulation * lowerCascadeLevelWeight, 1.0f );
320+ // TODO: russian roulette early exit?
360321 }
361322
362- for (uint32_t i = 0 ; i < 6 ; i++)
363- {
364- cascadeEntry[i] /= float (numSamples);
365- cascade[uint3 (coords.x, coords.y, i)] = cascadeEntry[i];
366- }
323+ return accumulator.accumulation;
367324 }
368325
369326 NBL_CONSTEXPR_STATIC_INLINE uint32_t MAX_DEPTH_LOG2 = 4u;
0 commit comments