Skip to content

Commit 04296d9

Browse files
committed
Added accumulators
1 parent ca8c232 commit 04296d9

File tree

9 files changed

+590
-354
lines changed

9 files changed

+590
-354
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#ifndef _NBL_HLSL_RWMC_INCLUDED_
2+
#define _NBL_HLSL_RWMC_INCLUDED_
3+
#include "nbl/builtin/hlsl/cpp_compat.hlsl"
4+
#include <nbl/builtin/hlsl/vector_utils/vector_traits.hlsl>
5+
#include <nbl/builtin/hlsl/colorspace/encodeCIEXYZ.hlsl>
6+
7+
namespace nbl
8+
{
9+
namespace hlsl
10+
{
11+
namespace rwmc
12+
{
13+
14+
struct RWMCCascadeSettings
15+
{
16+
uint32_t size;
17+
uint32_t start;
18+
uint32_t base;
19+
};
20+
21+
template<typename CascadeLayerType, uint32_t CascadeSize>
22+
struct CascadeEntry
23+
{
24+
CascadeLayerType data[CascadeSize];
25+
};
26+
27+
template<typename CascadeLayerType, uint32_t CascadeSize>
28+
struct RWMCCascadeAccumulator
29+
{
30+
using output_storage_type = CascadeEntry<CascadeLayerType, CascadeSize>;
31+
output_storage_type accumulation;
32+
uint32_t cascadeSampleCounter[CascadeSize];
33+
RWMCCascadeSettings cascadeSettings;
34+
35+
void initialize()
36+
{
37+
for (int i = 0; i < CascadeSize; ++i)
38+
{
39+
accumulation.data[i] = (CascadeLayerType)0.0f;
40+
cascadeSampleCounter[i] = 0u;
41+
}
42+
43+
// TODO: pass these values to this function
44+
cascadeSettings.size = 6;
45+
cascadeSettings.start = 1.0f;
46+
cascadeSettings.base = 1.0f;
47+
}
48+
49+
typename vector_traits<CascadeLayerType>::scalar_type getLuma(NBL_CONST_REF_ARG(CascadeLayerType) col)
50+
{
51+
return hlsl::dot<CascadeLayerType>(hlsl::transpose(colorspace::scRGBtoXYZ)[1], col);
52+
}
53+
54+
// most of this code is stolen from https://cg.ivd.kit.edu/publications/2018/rwmc/tool/split.cpp
55+
void addSample(uint32_t sampleIndex, float32_t3 sample)
56+
{
57+
float lowerScale = cascadeSettings.start;
58+
float upperScale = lowerScale * cascadeSettings.base;
59+
60+
const float luma = getLuma(sample);
61+
62+
uint32_t lowerCascadeIndex = 0u;
63+
while (!(luma < upperScale) && lowerCascadeIndex < cascadeSettings.size - 2)
64+
{
65+
lowerScale = upperScale;
66+
upperScale *= cascadeSettings.base;
67+
++lowerCascadeIndex;
68+
}
69+
70+
float lowerCascadeLevelWeight;
71+
float higherCascadeLevelWeight;
72+
73+
if (luma <= lowerScale)
74+
lowerCascadeLevelWeight = 1.0f;
75+
else if (luma < upperScale)
76+
lowerCascadeLevelWeight = max(0.0f, (lowerScale / luma - lowerScale / upperScale) / (1.0f - lowerScale / upperScale));
77+
else // Inf, NaN ...
78+
lowerCascadeLevelWeight = 0.0f;
79+
80+
if (luma < upperScale)
81+
higherCascadeLevelWeight = max(0.0f, 1.0f - lowerCascadeLevelWeight);
82+
else
83+
higherCascadeLevelWeight = upperScale / luma;
84+
85+
uint32_t higherCascadeIndex = lowerCascadeIndex + 1u;
86+
87+
const uint32_t sampleCount = sampleIndex + 1u;
88+
const float reciprocalSampleCount = 1.0f / float(sampleCount);
89+
accumulation.data[lowerCascadeIndex] += (sample * lowerCascadeLevelWeight - (sampleCount - (cascadeSampleCounter[lowerCascadeIndex])) * accumulation.data[lowerCascadeIndex]) * reciprocalSampleCount;
90+
accumulation.data[higherCascadeIndex] += (sample * higherCascadeLevelWeight - (sampleCount - (cascadeSampleCounter[higherCascadeIndex])) * accumulation.data[higherCascadeIndex]) * reciprocalSampleCount;
91+
cascadeSampleCounter[lowerCascadeIndex] = sampleCount;
92+
cascadeSampleCounter[higherCascadeIndex] = sampleCount;
93+
}
94+
};
95+
96+
}
97+
}
98+
}
99+
100+
#endif

31_HLSLPathTracer/app_resources/hlsl/pathtracer.hlsl

Lines changed: 45 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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>
4465
struct 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;

31_HLSLPathTracer/app_resources/hlsl/render.comp.hlsl

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,32 @@
3636
#define BXDF_COUNT 7
3737

3838
#include "render_common.hlsl"
39+
#include "rwmc_global_settings_common.hlsl"
40+
41+
#ifdef RWMC_ENABLED
42+
#include "RWMCCascadeAccumulator.hlsl"
43+
#include "render_rwmc_common.hlsl"
44+
#endif
45+
46+
#ifdef RWMC_ENABLED
47+
[[vk::push_constant]] RenderRWMCPushConstants pc;
48+
#else
49+
[[vk::push_constant]] RenderPushConstants pc;
50+
#endif
51+
52+
[[vk::combinedImageSampler]] [[vk::binding(0, 2)]] Texture2D<float3> envMap; // unused
53+
[[vk::combinedImageSampler]] [[vk::binding(0, 2)]] SamplerState envSampler;
54+
55+
[[vk::binding(1, 2)]] Buffer<uint3> sampleSequence;
56+
57+
[[vk::combinedImageSampler]] [[vk::binding(2, 2)]] Texture2D<uint2> scramblebuf; // unused
58+
[[vk::combinedImageSampler]] [[vk::binding(2, 2)]] SamplerState scrambleSampler;
59+
60+
#ifdef RWMC_ENABLED
61+
[[vk::image_format("rgba16f")]] [[vk::binding(0, 1)]] RWTexture2DArray<float32_t4> cascade;
62+
#endif
63+
[[vk::image_format("rgba16f")]] [[vk::binding(0, 0)]] RWTexture2D<float32_t4> outImage;
64+
3965
#include "pathtracer.hlsl"
4066

4167
using namespace nbl;
@@ -96,7 +122,15 @@ using raygen_type = ext::RayGen::Basic<ray_type>;
96122
using intersector_type = ext::Intersector::Comprehensive<ray_type, light_type, bxdfnode_type>;
97123
using material_system_type = ext::MaterialSystem::System<diffuse_bxdf_type, conductor_bxdf_type, dielectric_bxdf_type>;
98124
using nee_type = ext::NextEventEstimator::Estimator<scene_type, ray_type, sample_t, aniso_interaction, ext::IntersectMode::IM_PROCEDURAL, LIGHT_TYPE, POLYGON_METHOD>;
99-
using pathtracer_type = ext::PathTracer::Unidirectional<randgen_type, raygen_type, intersector_type, material_system_type, nee_type>;
125+
126+
#ifdef RWMC_ENABLED
127+
// TODO: get cascade size from a shared include file
128+
using accumulator_type = rwmc::RWMCCascadeAccumulator<float32_t3, 6u>;
129+
#else
130+
using accumulator_type = ext::PathTracer::DefaultAccumulator<float32_t3>;
131+
#endif
132+
133+
using pathtracer_type = ext::PathTracer::Unidirectional<randgen_type, raygen_type, intersector_type, material_system_type, nee_type, accumulator_type>;
100134

101135
static const ext::Shape<ext::PST_SPHERE> spheres[SPHERE_COUNT] = {
102136
ext::Shape<ext::PST_SPHERE>::create(float3(0.0, -100.5, -1.0), 100.0, 0u, light_type::INVALID_ID),
@@ -129,7 +163,7 @@ static const ext::Shape<ext::PST_RECTANGLE> rectangles[1];
129163
#endif
130164

131165
static const light_type lights[LIGHT_COUNT] = {
132-
light_type::create(spectral_t(30.0,25.0,15.0),
166+
light_type::create(LightEminence,
133167
#ifdef SPHERE_LIGHT
134168
8u,
135169
#else
@@ -217,23 +251,19 @@ void main(uint32_t3 threadID : SV_DispatchThreadID)
217251

218252
pathtracer_type pathtracer = pathtracer_type::create(ptCreateParams);
219253

220-
bool useRWMC = bool(pc.useRWMC);
221-
if (!useRWMC)
254+
#ifdef RWMC_ENABLED
255+
accumulator_type::output_storage_type cascadeEntry = pathtracer.getMeasure(pc.sampleCount, pc.depth, scene);
256+
for (uint32_t i = 0; i < CascadeSize; ++i)
222257
{
223-
float32_t3 color = pathtracer.getMeasure(pc.sampleCount, pc.depth, scene);
224-
float32_t4 pixCol = float32_t4(color, 1.0);
225-
outImage[coords] = pixCol;
258+
float32_t4 cascadeLayerEntry = float32_t4(cascadeEntry.data[i], 1.0f);
259+
cascade[uint3(coords.x, coords.y, i)] = cascadeLayerEntry;
226260
}
227-
else
228-
{
229-
pathtracer_type::RWMCCascadeSettings cascadeSettings;
230-
cascadeSettings.size = pc.rwmcCascadeSize;
231-
cascadeSettings.start = pc.rwmcCascadeStart;
232-
cascadeSettings.base = pc.rwmcCascadeBase;
261+
#else
262+
float32_t3 color = pathtracer.getMeasure(pc.sampleCount, pc.depth, scene);
263+
outImage[coords] = float32_t4(color, 1.0);
264+
#endif
233265

234-
// TODO: template parameter should be
235-
pathtracer.generateCascade(coords, pc.sampleCount, pc.depth, cascadeSettings, scene);
236-
}
266+
237267

238268
#ifdef PERSISTENT_WORKGROUPS
239269
}

0 commit comments

Comments
 (0)