pathtracer.cpp 13.5 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
namespace glare::raytrace
unknown's avatar
unknown committed
7
{
8
9
	Pathtracer::Pathtracer()
		: Pathtracer(RayGeneratorType::eTrace)
unknown's avatar
unknown committed
10
11
	{

12
	}
unknown's avatar
unknown committed
13

14
15
16
	Pathtracer::Pathtracer(std::shared_ptr<core::GraphNode> graph_root)
		: Pathtracer(std::make_shared<SceneCollector>(graph_root))
	{
17

18
	}
19

20
21
22
	Pathtracer::Pathtracer(std::shared_ptr<core::GraphNode> graph_root, RayGeneratorType ray_generator)
		: Pathtracer(std::make_shared<SceneCollector>(graph_root), ray_generator)
	{
23

24
	}
25

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

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

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
	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.";
		m_render_shader = std::make_unique<core::Program>(files::shader("/pathtracer/pathtracer.comp"));
		m_generator_type = ray_generator;
		m_trace_buffer = std::make_unique<core::Buffer<gl::BufferType::eShaderStorage>>();

		registerForMessage(tags::scene);

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

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

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
	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");
		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));

		//ls thresholds
		const auto ls_thresholds_child = pt_child.find_child_by_attribute("group", "name", "ls-thresholds");
		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));

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

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

101
		m_collector->apply(*m_render_shader);
unknown's avatar
unknown committed
102

103
104
105
		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);
106

107
108
109
		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);
110

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

118
119
		m_linespace_config.bounce_thresholds = 0;
		for (int i = 0; i < 4; ++i)
unknown's avatar
unknown committed
120
		{
121
			m_linespace_config.bounce_thresholds |= (m_ls_bounce_count_thresholds[i] & 0xff) << (8 * i);
unknown's avatar
unknown committed
122
		}
123
		m_render_shader->uniform("u_linespace_properties.bounce_thresholds", m_linespace_config.bounce_thresholds);
unknown's avatar
unknown committed
124

125
126
127
128
129
		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");
	}
130

131
132
	const core::TextureRGBA_32F &Pathtracer::render(uint32_t width, uint32_t height)
	{
Johannes Braun's avatar
Johannes Braun committed
133
		static auto color_storage = std::make_unique<core::TextureRGBA_32F>(width, height);
134
135
136
		if (width != m_last_width || height != m_last_height) {
			m_last_width = width;
			m_last_height = height;
137

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

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

Johannes Braun's avatar
Johannes Braun committed
148
149
150
151
152
		if (m_render_config.current_sample == 0)
		{
			gl::clearTextureImage(color_storage->id(), 0, gl::TextureFormat::eRGBA, gl::Type::eFloat, glm::value_ptr(glm::vec4(0)));
		}

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

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

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

169
170
171
172
			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
173

174
175
176
177
178
			if (debug.print_render_times) core::ClockGL::instance().start();
			m_render_shader->use();
			m_render_shader->uniform("u_render_config.current_sample", m_render_config.current_sample);
			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
179

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

183
184
		return *m_render_target;
	}
185

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

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

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

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

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

212
213
214
215
	void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
	{
		m_collector = collector;
		m_collector->collect();
216

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

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

233
234
235
		m_skybox = core::state::skybox;
		reset();
	}
236

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

248
249
250
251
	const core::Program& Pathtracer::shader() const
	{
		return *m_render_shader;
	}
252

253
254
255
256
	uint32_t Pathtracer::width() const
	{
		return m_last_width;
	}
257

258
259
260
261
	uint32_t Pathtracer::height() const
	{
		return m_last_height;
	}
262

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

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

273
274
275
276
	std::shared_ptr<SceneCollector> Pathtracer::collector() const
	{
		return m_collector;
	}
277

278
279
280
281
	unsigned Pathtracer::currentSample() const
	{
		return m_render_config.current_sample;
	}
282

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

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

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

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

301
302
303
	void Pathtracer::setLinespaceBounceThresholds(EffectType type, uint8_t bounces)
	{
		uint8_t clamped = bounces & 0xff;
304

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

310
311
312
		m_ls_bounce_count_thresholds[unsigned(type)] = clamped;
		reset();
	}
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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
	uint8_t Pathtracer::getLinespaceBounceThreshold(EffectType type)
	{
		return m_ls_bounce_count_thresholds[static_cast<unsigned>(type)];
	}

	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
	{
		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;
unknown's avatar
unknown committed
409
410
	}
}