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

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

namespace glare
{
10
	namespace raytrace
unknown's avatar
unknown committed
11
	{
12
		Pathtracer::Pathtracer()
13
			: Pathtracer(RayGeneratorType::eTrace)
unknown's avatar
unknown committed
14
15
16
17
		{

		}

18
19
20
21
22
23
		Pathtracer::Pathtracer(std::shared_ptr<core::GraphNode> graph_root)
			: Pathtracer(std::make_shared<SceneCollector>(graph_root))
		{

		}

24
		Pathtracer::Pathtracer(std::shared_ptr<core::GraphNode> graph_root, RayGeneratorType ray_generator)
25
26
27
28
29
			: Pathtracer(std::make_shared<SceneCollector>(graph_root), ray_generator)
		{

		}

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

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

40
		Pathtracer::Pathtracer(std::shared_ptr<SceneCollector> collector, RayGeneratorType ray_generator)
unknown's avatar
unknown committed
41
		{
42
43
44
45
			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;
46

47
48
49
50
			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;
51

52
			m_linespace_config.distance_threshold = 8.f;
53
			m_render_config.bounces = 16;
54
			Log_Hint << "Pathtracing Shader will now be compiled. This might take a couple of seconds.";
55
			m_render_shader = std::make_unique<core::Program>(files::shader("/pathtracer/pathtracer.comp"));
56
			m_generator_type = ray_generator;
unknown's avatar
unknown committed
57
			m_trace_buffer = std::make_unique<core::Buffer<gl::BufferType::eShaderStorage>>();
58
59
60

			registerForMessage(tags::scene);

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

65
		Pathtracer::~Pathtracer()
unknown's avatar
unknown committed
66
		{
67
68
			if (!core::state::window->isClosing())
				unregisterForMessage(tags::scene);
unknown's avatar
unknown committed
69
70
		}

71
		void Pathtracer::loadSettings(const fs::path &xml_file)
72
73
74
75
76
77
78
79
80
		{
			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");
81
82
83
84
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = bounces_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2);
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eReflection)] = bounces_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4);
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eTransmission)] = bounces_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4);
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eEmission)] = bounces_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8);
85
86
87

			//ls thresholds
			const auto ls_thresholds_child = pt_child.find_child_by_attribute("group", "name", "ls-thresholds");
88
89
90
91
			m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = ls_thresholds_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2);
			m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eReflection)] = ls_thresholds_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4);
			m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eTransmission)] = ls_thresholds_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4);
			m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eEmission)] = ls_thresholds_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8);
92
93
94
95
96
97
98
99
100

			m_linespace_config.accuracy_threshold = ls_thresholds_child.find_child_by_attribute("item", "name", "accuracy").attribute("value").as_float(0.5f);
			m_linespace_config.shadow_threshold = ls_thresholds_child.find_child_by_attribute("item", "name", "shadow").attribute("value").as_float(0.5f);
			m_linespace_config.distance_threshold = ls_thresholds_child.find_child_by_attribute("item", "name", "distance").attribute("value").as_float(10.f);

			m_render_config.clamp_direct = pt_child.find_child_by_attribute("item", "name", "clamp-direct").attribute("value").as_float(8);
			m_render_config.clamp_indirect = pt_child.find_child_by_attribute("item", "name", "clamp-indirect").attribute("value").as_float(8);
		}

101
		void Pathtracer::reset()
unknown's avatar
unknown committed
102
		{
103
			m_render_config.current_sample = 0;
unknown's avatar
unknown committed
104
			if (m_color_store)
unknown's avatar
unknown committed
105
				gl::clearTextureImage(m_color_store->id(), 0, gl::TextureFormat::eRGBA, gl::Type::eFloat, glm::value_ptr(glm::vec4(0)));
106
107
108
109
110
111
112
113
114
115
116
117

			m_collector->apply(*m_render_shader);

			m_render_shader->uniform("u_render_config.num_bounces", m_render_config.bounces);
			m_render_shader->uniform("u_render_config.clamp_direct", m_render_config.clamp_direct);
			m_render_shader->uniform("u_render_config.clamp_indirect", m_render_config.clamp_indirect);

			m_render_shader->uniform("u_linespace_properties.accuracy_quality", m_linespace_config.accuracy_threshold);
			m_render_shader->uniform("u_linespace_properties.shadow_quality", m_linespace_config.shadow_threshold);
			m_render_shader->uniform("u_linespace_properties.distance_threshold", m_linespace_config.distance_threshold);

			unsigned bounce_thresholds = 0;
118
			for (int i = 0; i < 4; ++i)
119
			{
120
				bounce_thresholds |= (m_bounce_count_thresholds[i] & 0xff) << (8 * i);
121
122
123
124
			}
			m_render_shader->uniform("u_render_config.bounce_thresholds", bounce_thresholds);

			m_linespace_config.bounce_thresholds = 0;
125
			for (int i = 0; i < 4; ++i)
126
			{
127
				m_linespace_config.bounce_thresholds |= (m_ls_bounce_count_thresholds[i] & 0xff) << (8 * i);
128
129
			}
			m_render_shader->uniform("u_linespace_properties.bounce_thresholds", m_linespace_config.bounce_thresholds);
130
131

			m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[0]", "samplePoint");
132
133
134
			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");
unknown's avatar
unknown committed
135
136
		}

137
		const core::TextureRGBA_32F &Pathtracer::render(uint32_t width, uint32_t height)
unknown's avatar
unknown committed
138
139
140
141
		{
			if (width != m_last_width || height != m_last_height) {
				m_last_width = width;
				m_last_height = height;
142

143
				m_trace_buffer->reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
unknown's avatar
unknown committed
144
145
				m_render_target = std::make_unique<core::TextureRGBA_32F>(width, height);
				m_color_store = std::make_unique<core::TextureRGBA_32F>(width, height);
146

147
148
149
				m_render_shader->uniform("u_render_target", m_render_target->makeImageResident(gl::Access::eReadWrite));
				m_render_shader->uniform("u_color_store", m_color_store->makeImageResident(gl::Access::eReadWrite));
				m_render_shader->storageBuffer("trace_buffer", *m_trace_buffer);
150
				m_render_config.current_sample = 0;
unknown's avatar
unknown committed
151
			}
152

153
154
155
			if (m_skybox && m_skybox->isInitialized())
			{
				m_render_shader->uniform("u_environment.cubemap", m_skybox->makeResident());
156
				m_render_shader->uniform("u_environment.has_cubemap", 1);
157
158
159
160
			}
			else
			{
				m_render_shader->uniform("u_environment.color", glm::vec4(0.7f, 0.9f, 0.97f, 1));
161
				m_render_shader->uniform("u_environment.has_cubemap", 0);
162
163
			}

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

166
				if (m_render_config.current_sample >= m_render_config.max_samples)
unknown's avatar
unknown committed
167
168
					return *m_render_target;

169
				if (debug.print_render_times) core::ClockGL::instance().start();
170
171
				const static std::unique_ptr<RayGenerator> ray_generator = std::make_unique<RayGenerator>();
				ray_generator->generate(*this);
172
				if (debug.print_render_times) Log_Hint << "RENDER TIME [Generate Primary Rays]: " << core::ClockGL::instance().end() << " ns";
173

174
				if (debug.print_render_times) core::ClockGL::instance().start();
unknown's avatar
unknown committed
175
				m_render_shader->use();
176
				m_render_shader->uniform("u_render_config.current_sample", m_render_config.current_sample);
Johannes Braun's avatar
Johannes Braun committed
177
				m_render_shader->dispatch2d(width, 16, height, 16);
178
				if (debug.print_render_times) Log_Hint << "RENDER TIME [Trace and Bounce]: " << core::ClockGL::instance().end() << " ns";
unknown's avatar
unknown committed
179

180
				++m_render_config.current_sample;
unknown's avatar
unknown committed
181
182
183
184
185
			}

			return *m_render_target;
		}

Johannes Braun's avatar
Johannes Braun committed
186
		void Pathtracer::draw(std::shared_ptr<core::GraphNode> node)
187
		{
Johannes Braun's avatar
Johannes Braun committed
188
189
190
191
			// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
			if (!m_collector)
				reload(node);

192
			static const std::shared_ptr<core::TextureRenderer> texture_renderer = core::DefaultTextureRenderers::makeSimpleRenderer();
Johannes Braun's avatar
Johannes Braun committed
193
			texture_renderer->draw(render(core::state::window->getWidth(), core::state::window->getHeight()));
194
195
		}

196
		void Pathtracer::saveRender(fs::path target) const
unknown's avatar
unknown committed
197
		{
unknown's avatar
unknown committed
198
			core::textures::saveTexture(target, *m_render_target);
unknown's avatar
unknown committed
199
200
		}

201
		void Pathtracer::setGenerator(RayGeneratorType generator)
unknown's avatar
unknown committed
202
		{
203
			m_generator_type = generator;
unknown's avatar
unknown committed
204
205
206
			reset();
		}

207
208
209
210
211
		RayGeneratorType Pathtracer::getGenerator() const
		{
			return m_generator_type;
		}

212
		void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
unknown's avatar
unknown committed
213
214
		{
			m_collector = collector;
215
			m_collector->collect();
216
217

			m_skybox = core::state::skybox;
218
219
220
221
222
			reset();
		}

		void Pathtracer::reload(std::shared_ptr<core::GraphNode> graph_root)
		{
223
224
225
226
227
228
229
230
231
232
233
			if (!m_collector)
			{
				m_collector = std::make_shared<SceneCollector>(graph_root);
			}
			else
			{
				m_collector->setDirty(DirtyFlags::eAll);
				m_collector->collect(graph_root);
			}

			m_skybox = core::state::skybox;
unknown's avatar
unknown committed
234
235
236
			reset();
		}

237
		void Pathtracer::handle(messaging::message_t& message)
unknown's avatar
unknown committed
238
239
240
		{
			switch (message.name)
			{
241
			case tags::scene:
unknown's avatar
unknown committed
242
243
				reset();
				break;
244
			default: break;
unknown's avatar
unknown committed
245
246
247
			}
		}

Johannes Braun's avatar
Johannes Braun committed
248
		const core::Program& Pathtracer::shader() const
unknown's avatar
unknown committed
249
250
251
252
		{
			return *m_render_shader;
		}

253
		uint32_t Pathtracer::width() const
unknown's avatar
unknown committed
254
255
256
257
		{
			return m_last_width;
		}

258
		uint32_t Pathtracer::height() const
unknown's avatar
unknown committed
259
260
261
262
		{
			return m_last_height;
		}

263
		core::Buffer<gl::BufferType::eShaderStorage>& Pathtracer::traceBuffer() const
unknown's avatar
unknown committed
264
265
266
267
		{
			return *m_trace_buffer;
		}

268
		const core::TextureRGBA_32F& Pathtracer::renderTarget() const
unknown's avatar
unknown committed
269
270
271
272
		{
			return *m_render_target;
		}

273
		std::shared_ptr<SceneCollector> Pathtracer::collector() const
unknown's avatar
unknown committed
274
275
276
		{
			return m_collector;
		}
277
278
279
280
281
282
283
284

		unsigned Pathtracer::currentSample() const
		{
			return m_render_config.current_sample;
		}

		void Pathtracer::setEffectBounces(EffectType type, uint8_t bounces)
		{
285
			uint8_t clamped = bounces & 0xff;
286
287
288
289
290
291

			if (clamped != bounces)
			{
				Log_Warn << bounces << " - value larger than 15 (0xf). Result of " << clamped << " may be unintended.";
			}

292
			m_bounce_count_thresholds[static_cast<unsigned>(type)] = clamped;
293
294
295
296
297
			reset();
		}

		uint8_t Pathtracer::getEffectBounces(EffectType type)
		{
298
			return m_bounce_count_thresholds[static_cast<unsigned>(type)];
299
300
301
302
		}

		void Pathtracer::setLinespaceBounceThresholds(EffectType type, uint8_t bounces)
		{
303
			uint8_t clamped = bounces & 0xff;
304
305
306
307
308
309
310
311
312
313
314
315

			if (clamped != bounces)
			{
				Log_Warn << bounces << " - value larger than 15 (0xf). Result of " << clamped << " may be unintended.";
			}

			m_ls_bounce_count_thresholds[unsigned(type)] = clamped;
			reset();
		}

		uint8_t Pathtracer::getLinespaceBounceThreshold(EffectType type)
		{
316
			return m_ls_bounce_count_thresholds[static_cast<unsigned>(type)];
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
		}

		void Pathtracer::setSkybox(std::shared_ptr<core::Skybox> skybox)
		{
			m_skybox = skybox;
			reset();
		}

		std::shared_ptr<core::Skybox> Pathtracer::getSkybox() const
		{
			return m_skybox;
		}

		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
367
368
		{
			return m_render_config.clamp_direct;
369
370
371
372
373
374
375
376
		}

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

		float Pathtracer::getClampIndirect() const
377
378
		{
			return m_render_config.clamp_indirect;
379
380
381
382
383
384
385
386
		}

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

		float Pathtracer::getAccuracyThreshold() const
387
388
		{
			return m_linespace_config.accuracy_threshold;
389
390
391
392
393
394
395
396
		}

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

		float Pathtracer::getShadowThreshold() const
397
398
		{
			return m_linespace_config.shadow_threshold;
399
400
401
402
403
404
405
406
407
		}

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

		float Pathtracer::getDistanceThreshold() const
		{
408
			return m_linespace_config.distance_threshold;
409
		}
unknown's avatar
unknown committed
410
411
	}
}