pathtracer.cpp 12.7 KB
Newer Older
1
2
#include "pathtracer.h"

3
#include <pugixml/pugixml.hpp>
4
#include <core/rendering/texture_renderer.h>
5
#include <util/files.h>
unknown's avatar
unknown committed
6

7
namespace glare::raytrace
unknown's avatar
unknown committed
8
{
Johannes Braun's avatar
Johannes Braun committed
9
10
	std::unique_ptr<core::Program> Pathtracer::m_render_shader = nullptr;

11
12
	Pathtracer::Pathtracer()
		: Pathtracer(RayGeneratorType::eTrace)
unknown's avatar
unknown committed
13
14
	{

15
	}
unknown's avatar
unknown committed
16

Johannes Braun's avatar
Johannes Braun committed
17
	Pathtracer::Pathtracer(std::shared_ptr<core::SceneNode> graph_root)
18
19
		: Pathtracer(std::make_shared<SceneCollector>(graph_root))
	{
20

21
	}
22

Johannes Braun's avatar
Johannes Braun committed
23
	Pathtracer::Pathtracer(std::shared_ptr<core::SceneNode> graph_root, RayGeneratorType ray_generator)
24
25
		: Pathtracer(std::make_shared<SceneCollector>(graph_root), ray_generator)
	{
26

27
	}
28

29
30
31
32
	Pathtracer::Pathtracer(RayGeneratorType ray_generator)
		: Pathtracer(std::shared_ptr<SceneCollector>(nullptr), ray_generator)
	{
	}
unknown's avatar
unknown committed
33

34
35
36
37
	Pathtracer::Pathtracer(std::shared_ptr<SceneCollector> collector)
		: Pathtracer(collector, RayGeneratorType::eTrace)
	{
	}
unknown's avatar
unknown committed
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
	Pathtracer::Pathtracer(std::shared_ptr<SceneCollector> collector, RayGeneratorType ray_generator)
	{
		m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = 4;
		m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eReflection)] = 6;
		m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eTransmission)] = 12;
		m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eEmission)] = 1;

		m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = 1;
		m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eReflection)] = 3;
		m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eTransmission)] = 3;
		m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eEmission)] = 6;

		m_linespace_config.distance_threshold = 8.f;
		m_render_config.bounces = 16;
		Log_Hint << "Pathtracing Shader will now be compiled. This might take a couple of seconds.";
Johannes Braun's avatar
Johannes Braun committed
54
		if(!m_render_shader) m_render_shader = std::make_unique<core::Program>(files::shader("/pathtracer/pathtracer.comp"));
55
56
		m_generator_type = ray_generator;

Johannes Braun's avatar
Johannes Braun committed
57
		core::Context::current().messages()->addObserver(this, tags::scene);
58
59
60
61

		if (collector)
			initialize(collector);
	}
unknown's avatar
unknown committed
62

63
64
	Pathtracer::~Pathtracer()
	{
65
		if (core::Context::hasCurrentContext() && !core::Context::current().window().isClosing())
Johannes Braun's avatar
Johannes Braun committed
66
			core::Context::current().messages()->removeObserver(this, tags::scene);
67
	}
unknown's avatar
unknown committed
68

69
70
71
72
73
74
75
76
77
78
	void Pathtracer::loadSettings(const fs::path &xml_file)
	{
		pugi::xml_document preferences_file;
		Log_Info << "Pathtracer settings file load status: " << preferences_file.load_file(xml_file.c_str()).description();

		//Pathtracer
		const auto pt_child = preferences_file.child("pathtracer");

		//bounces
		const auto bounces_child = pt_child.find_child_by_attribute("group", "name", "bounces");
Johannes Braun's avatar
Johannes Braun committed
79
80
81
82
		dynamic_config.bounces.thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2));
		dynamic_config.bounces.thresholds[static_cast<unsigned>(EffectType::eReflection)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4));
		dynamic_config.bounces.thresholds[static_cast<unsigned>(EffectType::eTransmission)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4));
		dynamic_config.bounces.thresholds[static_cast<unsigned>(EffectType::eEmission)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8));
83
84
85

		//ls thresholds
		const auto ls_thresholds_child = pt_child.find_child_by_attribute("group", "name", "ls-thresholds");
Johannes Braun's avatar
Johannes Braun committed
86
87
88
89
90
		dynamic_config.linespace.thresholds.bounces[static_cast<unsigned>(EffectType::eDiffusion)] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2));
		dynamic_config.linespace.thresholds.bounces[static_cast<unsigned>(EffectType::eReflection)] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4));
		dynamic_config.linespace.thresholds.bounces[static_cast<unsigned>(EffectType::eTransmission)] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4));
		dynamic_config.linespace.thresholds.bounces[static_cast<unsigned>(EffectType::eEmission)] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8));
		dynamic_config.linespace.thresholds.distance = ls_thresholds_child.find_child_by_attribute("item", "name", "distance").attribute("value").as_float(10.f);
91

Johannes Braun's avatar
Johannes Braun committed
92
93
		dynamic_config.linespace.quality.accuracy = ls_thresholds_child.find_child_by_attribute("item", "name", "accuracy").attribute("value").as_float(0.5f);
		dynamic_config.linespace.quality.shadow = ls_thresholds_child.find_child_by_attribute("item", "name", "shadow").attribute("value").as_float(0.5f);
94

Johannes Braun's avatar
Johannes Braun committed
95
96
		dynamic_config.clamp.direct = pt_child.find_child_by_attribute("item", "name", "clamp-direct").attribute("value").as_float(8);
		dynamic_config.clamp.indirect = pt_child.find_child_by_attribute("item", "name", "clamp-indirect").attribute("value").as_float(8);
97
	}
98

99
100
101
	void Pathtracer::reset()
	{
		m_render_config.current_sample = 0;
unknown's avatar
unknown committed
102

103
		m_collector->apply(*m_render_shader);
unknown's avatar
unknown committed
104

Johannes Braun's avatar
Johannes Braun committed
105
106
107
		m_render_shader->uniform("u_render_config.num_bounces", dynamic_config.bounces.count);
		m_render_shader->uniform("u_render_config.clamp_direct", dynamic_config.clamp.direct);
		m_render_shader->uniform("u_render_config.clamp_indirect", dynamic_config.clamp.indirect);
108

Johannes Braun's avatar
Johannes Braun committed
109
110
111
		m_render_shader->uniform("u_linespace_properties.accuracy_quality", dynamic_config.linespace.quality.accuracy);
		m_render_shader->uniform("u_linespace_properties.shadow_quality", dynamic_config.linespace.quality.shadow);
		m_render_shader->uniform("u_linespace_properties.distance_threshold", dynamic_config.linespace.thresholds.distance);
112

113
114
		unsigned bounce_thresholds = 0;
		for (int i = 0; i < 4; ++i)
unknown's avatar
unknown committed
115
		{
Johannes Braun's avatar
Johannes Braun committed
116
			bounce_thresholds |= (dynamic_config.bounces.thresholds[i] & 0xff) << (8 * i);
unknown's avatar
unknown committed
117
		}
118
		m_render_shader->uniform("u_render_config.bounce_thresholds", bounce_thresholds);
unknown's avatar
unknown committed
119

Johannes Braun's avatar
Johannes Braun committed
120
		unsigned bounce_thresholds = 0;
121
		for (int i = 0; i < 4; ++i)
unknown's avatar
unknown committed
122
		{
Johannes Braun's avatar
Johannes Braun committed
123
			bounce_thresholds |= (dynamic_config.linespace.thresholds.bounces[i] & 0xff) << (8 * i);
unknown's avatar
unknown committed
124
		}
Johannes Braun's avatar
Johannes Braun committed
125
		m_render_shader->uniform("u_linespace_properties.bounce_thresholds", bounce_thresholds);
unknown's avatar
unknown committed
126

127
128
129
130
131
		m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[0]", "samplePoint");
		m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[1]", "sampleSpot");
		m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[2]", "sampleDirectional");
		m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[3]", "sampleAmbient");
	}
132

133
134
135
136
137
	const core::TextureRGBA_32F &Pathtracer::render(uint32_t width, uint32_t height)
	{
		if (width != m_last_width || height != m_last_height) {
			m_last_width = width;
			m_last_height = height;
138

Johannes Braun's avatar
Johannes Braun committed
139
			m_trace_buffer.reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
140
			m_render_target = std::make_unique<core::TextureRGBA_32F>(width, height);
Johannes Braun's avatar
Johannes Braun committed
141
			m_color_storage = std::make_unique<core::TextureRGBA_32F>(width, height);
142

143
			m_render_shader->uniform("u_render_target", m_render_target->makeImageResident(gl::Access::eReadWrite));
Johannes Braun's avatar
Johannes Braun committed
144
145
146
			m_render_shader->uniform("u_color_store", m_color_storage->makeImageResident(gl::Access::eReadWrite));
			m_render_shader->storageBuffer("trace_buffer", m_trace_buffer);
			samples.current = 0;
unknown's avatar
unknown committed
147
148
		}

Johannes Braun's avatar
Johannes Braun committed
149
		if (samples.current == 0)
Johannes Braun's avatar
Johannes Braun committed
150
		{
151
			m_collector->collect();
Johannes Braun's avatar
Johannes Braun committed
152
			gl::clearTextureImage(m_color_storage->id(), 0, gl::TextureFormat::eRGBA, gl::Type::eFloat, glm::value_ptr(glm::vec4(0)));
unknown's avatar
unknown committed
153
154
		}

155
		for (unsigned sample = 0; sample < m_render_config.samples_per_frame; sample++) {
unknown's avatar
unknown committed
156

Johannes Braun's avatar
Johannes Braun committed
157
			if (samples.current >= samples.max)
158
				return *m_render_target;
unknown's avatar
unknown committed
159

160
161
162
163
			if (debug.print_render_times) core::ClockGL::instance().start();
			const static std::unique_ptr<RayGenerator> ray_generator = std::make_unique<RayGenerator>();
			ray_generator->generate(*this);
			if (debug.print_render_times) Log_Hint << "RENDER TIME [Generate Primary Rays]: " << core::ClockGL::instance().end() << " ns";
unknown's avatar
unknown committed
164

165
166
			if (debug.print_render_times) core::ClockGL::instance().start();
			m_render_shader->use();
Johannes Braun's avatar
Johannes Braun committed
167
			m_render_shader->uniform("u_render_config.current_sample", samples.current);
Johannes Braun's avatar
Johannes Braun committed
168
			m_render_shader->uniform("random_seed", ray_generator->randomSeed());
169
170
			m_render_shader->dispatch2d(width, 16, height, 16);
			if (debug.print_render_times) Log_Hint << "RENDER TIME [Trace and Bounce]: " << core::ClockGL::instance().end() << " ns";
unknown's avatar
unknown committed
171

Johannes Braun's avatar
Johannes Braun committed
172
			++samples.current;
unknown's avatar
unknown committed
173
		}
174

175
176
		return *m_render_target;
	}
177

Johannes Braun's avatar
Johannes Braun committed
178
	void Pathtracer::draw(std::shared_ptr<core::SceneNode> node)
179
180
181
182
	{
		// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
		if (!m_collector)
			reload(node);
183

184
		static const std::shared_ptr<core::TextureRenderer> texture_renderer = core::DefaultTextureRenderers::makeSimpleRenderer();
185
		texture_renderer->draw(render(core::Context::current().window().getWidth(), core::Context::current().window().getHeight()));
186
	}
187

188
189
190
191
	void Pathtracer::saveRender(fs::path target) const
	{
		core::textures::saveTexture(target, *m_render_target);
	}
192

193
194
195
196
197
	void Pathtracer::setGenerator(RayGeneratorType generator)
	{
		m_generator_type = generator;
		reset();
	}
198

199
200
201
202
	RayGeneratorType Pathtracer::getGenerator() const
	{
		return m_generator_type;
	}
203

204
205
206
	void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
	{
		m_collector = collector;
207

208
209
		reset();
	}
210

Johannes Braun's avatar
Johannes Braun committed
211
	void Pathtracer::reload(std::shared_ptr<core::SceneNode> graph_root)
212
213
	{
		if (!m_collector)
214
		{
215
			m_collector = std::make_shared<SceneCollector>(graph_root);
216
		}
217
		else
218
		{
219
220
			m_collector->setDirty(DirtyFlags::eAll);
			m_collector->collect(graph_root);
221
222
		}

223
224
		reset();
	}
225

Johannes Braun's avatar
Johannes Braun committed
226
	void Pathtracer::onNotify(msg::id_type id, msg::message_type message)
227
	{
Johannes Braun's avatar
Johannes Braun committed
228
		switch (id)
229
		{
230
		case tags::scene:
231
			reset();
232
233
			break;
		default: break;
234
		}
235
	}
236

237
238
239
240
	const core::Program& Pathtracer::shader() const
	{
		return *m_render_shader;
	}
241

242
243
244
245
	uint32_t Pathtracer::width() const
	{
		return m_last_width;
	}
246

247
248
249
250
	uint32_t Pathtracer::height() const
	{
		return m_last_height;
	}
251

Johannes Braun's avatar
Johannes Braun committed
252
	core::Buffer& Pathtracer::traceBuffer()
253
	{
Johannes Braun's avatar
Johannes Braun committed
254
		return m_trace_buffer;
255
	}
256

257
258
259
260
	const core::TextureRGBA_32F& Pathtracer::renderTarget() const
	{
		return *m_render_target;
	}
261

262
263
264
265
	std::shared_ptr<SceneCollector> Pathtracer::collector() const
	{
		return m_collector;
	}
266

267
268
	unsigned Pathtracer::currentSample() const
	{
Johannes Braun's avatar
Johannes Braun committed
269
		return samples.current;
270
	}
271

Johannes Braun's avatar
Johannes Braun committed
272
	/*
273
274
	void Pathtracer::setEffectBounces(EffectType type, uint8_t bounces)
	{
Johannes Braun's avatar
Johannes Braun committed
275
		m_bounce_count_thresholds[static_cast<unsigned>(type)] = bounces;
276
277
		reset();
	}
278

279
280
281
282
	uint8_t Pathtracer::getEffectBounces(EffectType type)
	{
		return m_bounce_count_thresholds[static_cast<unsigned>(type)];
	}
283

284
285
	void Pathtracer::setLinespaceBounceThresholds(EffectType type, uint8_t bounces)
	{
Johannes Braun's avatar
Johannes Braun committed
286
		m_ls_bounce_count_thresholds[unsigned(type)] = bounces;
287
288
		reset();
	}
289

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
	uint8_t Pathtracer::getLinespaceBounceThreshold(EffectType type)
	{
		return m_ls_bounce_count_thresholds[static_cast<unsigned>(type)];
	}

	void Pathtracer::setBounces(unsigned count)
	{
		reset();
		m_render_config.bounces = count;
	}

	unsigned Pathtracer::getBounces() const
	{
		return m_render_config.bounces;
	}

	void Pathtracer::setMaxSamples(unsigned count)
	{
		m_render_config.max_samples = count;
	}

	unsigned Pathtracer::getMaxSamples() const
	{
		return m_render_config.max_samples;
	}

	void Pathtracer::setSamplesPerFrame(unsigned count)
	{
		m_render_config.samples_per_frame = count;
	}

	unsigned Pathtracer::getSamplesPerFrame() const
	{
		return m_render_config.samples_per_frame;
	}

	void Pathtracer::setClampDirect(float clamp_direct)
	{
		m_render_config.clamp_direct = clamp_direct; reset();
	}

	float Pathtracer::getClampDirect() const
	{
		return m_render_config.clamp_direct;
	}

	void Pathtracer::setClampIndirect(float clamp_indirect)
	{
		m_render_config.clamp_indirect = clamp_indirect; reset();
	}

	float Pathtracer::getClampIndirect() const
	{
		return m_render_config.clamp_indirect;
	}

	void Pathtracer::setAccuracyThreshold(float accuracy_threshold)
	{
		m_linespace_config.accuracy_threshold = accuracy_threshold; reset();
	}

	float Pathtracer::getAccuracyThreshold() const
	{
		return m_linespace_config.accuracy_threshold;
	}

	void Pathtracer::setShadowThreshold(float shadow_threshold)
	{
		m_linespace_config.shadow_threshold = shadow_threshold; reset();
	}

	float Pathtracer::getShadowThreshold() const
	{
		return m_linespace_config.shadow_threshold;
	}

	void Pathtracer::setDistanceThreshold(float distance_threshold)
	{
		m_linespace_config.distance_threshold = distance_threshold; reset();
	}

	float Pathtracer::getDistanceThreshold() const
	{
		return m_linespace_config.distance_threshold;
Johannes Braun's avatar
Johannes Braun committed
374
	}*/
unknown's avatar
unknown committed
375
}