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

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

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

		}

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

		}

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

		}

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

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

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

45
46
47
48
			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;
49

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

			registerForMessage(tags::scene);

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

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

69
		void Pathtracer::loadSettings(const fs::path &xml_file)
70
71
72
73
74
75
76
77
78
		{
			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");
79
80
81
82
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2));
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eReflection)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4));
			m_bounce_count_thresholds[static_cast<unsigned>(EffectType::eTransmission)] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4));
			m_bounce_count_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");
86
87
88
89
			m_ls_bounce_count_thresholds[static_cast<unsigned>(EffectType::eDiffusion)] = static_cast<uint8_t>(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)] = static_cast<uint8_t>(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)] = static_cast<uint8_t>(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)] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8));
90
91
92
93
94
95
96
97
98

			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);
		}

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

			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;
116
			for (int i = 0; i < 4; ++i)
117
			{
118
				bounce_thresholds |= (m_bounce_count_thresholds[i] & 0xff) << (8 * i);
119
120
121
122
			}
			m_render_shader->uniform("u_render_config.bounce_thresholds", bounce_thresholds);

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

			m_render_shader->bindSubroutine(gl::ShaderType::eCompute, "u_light_sample[0]", "samplePoint");
130
131
132
			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
133
134
		}

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

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

145
146
147
				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);
148
				m_render_config.current_sample = 0;
unknown's avatar
unknown committed
149
			}
150

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

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

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

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

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

178
				++m_render_config.current_sample;
unknown's avatar
unknown committed
179
180
181
182
183
			}

			return *m_render_target;
		}

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

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

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

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

205
206
207
208
209
		RayGeneratorType Pathtracer::getGenerator() const
		{
			return m_generator_type;
		}

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

			m_skybox = core::state::skybox;
216
217
218
219
220
			reset();
		}

		void Pathtracer::reload(std::shared_ptr<core::GraphNode> graph_root)
		{
221
222
223
224
225
226
227
228
229
230
231
			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
232
233
234
			reset();
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

			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)
		{
314
			return m_ls_bounce_count_thresholds[static_cast<unsigned>(type)];
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
		}

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

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

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

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

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

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

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

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

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