pathtracer.cpp 7.51 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>
6
#include <core/res/preferences.h>
unknown's avatar
unknown committed
7

8
namespace glare::raytrace
unknown's avatar
unknown committed
9
{
10
	Pathtracer::Pathtracer(std::shared_ptr<core::SceneNode> graph_root, RayGenType ray_generator)
11
		: Pathtracer(graph_root ? std::make_shared<SceneCollector>(graph_root) : nullptr, ray_generator)
12
	{
13

14
	}
15

16
	Pathtracer::Pathtracer(RayGenType ray_generator)
17
18
19
		: Pathtracer(std::shared_ptr<SceneCollector>(nullptr), ray_generator)
	{
	}
unknown's avatar
unknown committed
20

21
	Pathtracer::Pathtracer(std::shared_ptr<SceneCollector> collector, RayGenType ray_generator)
22
23
	{
		Log_Hint << "Pathtracing Shader will now be compiled. This might take a couple of seconds.";
24
		if (!m_render_shader) m_render_shader = std::make_unique<core::Program>(files::shader("/pathtracer/pathtracer.comp"));
25
		m_ray_generator = ray_generator;
26

Johannes Braun's avatar
Johannes Braun committed
27
		core::Context::current().messages()->addObserver(this, tags::scene);
28
		m_render_target = std::make_unique<core::Texture>(core::Texture::Target::e2D, core::Texture::StoreFormat::eRGBA32Float);
29
30
31
32

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

34
35
	Pathtracer::~Pathtracer()
	{
36
		if (core::Context::hasCurrentContext() && !core::Context::current().window().isClosing())
Johannes Braun's avatar
Johannes Braun committed
37
			core::Context::current().messages()->removeObserver(this, tags::scene);
38
	}
unknown's avatar
unknown committed
39

40
41
	void Pathtracer::loadSettings(const fs::path &xml_file)
	{
42
		core::Preferences pt_preferences(xml_file);
43
44

		//bounces
45
46
47
48
		m_bounce_thresholds[Effect::eDiffusion]		= pt_preferences["bounces/diffusion"].as_uint(2);
		m_bounce_thresholds[Effect::eReflection]	= pt_preferences["bounces/reflection"].as_uint(4);
		m_bounce_thresholds[Effect::eTransmission]	= pt_preferences["bounces/transmission"].as_uint(4);
		m_bounce_thresholds[Effect::eEmission]		= pt_preferences["bounces/emission"].as_uint(8);
49

50
		//ls thresholds
51
52
53
54
55
56
57
58
59
60
61
		m_linespace_bounces[Effect::eDiffusion]		= pt_preferences["ls-thresholds/diffusion"].as_uint(2);
		m_linespace_bounces[Effect::eReflection]	= pt_preferences["ls-thresholds/reflection"].as_uint(4);
		m_linespace_bounces[Effect::eTransmission]	= pt_preferences["ls-thresholds/transmission"].as_uint(4);
		m_linespace_bounces[Effect::eEmission]		= pt_preferences["ls-thresholds/emission"].as_uint(8);

		m_linespace_distance	= pt_preferences["ls-thresholds/distance"].as_float(10.f);
		m_linespace_accuracy	= pt_preferences["ls-thresholds/accuracy"].as_float(0.5f);
		m_linespace_shadow		= pt_preferences["ls-thresholds/shadow"].as_float(0.5f);

		m_clamp_direct		= pt_preferences["clamp-direct"].as_float(8.f);
		m_clamp_indirect	= pt_preferences["clamp-indirect"].as_float(8.f);
62
	}
63

64
65
	void Pathtracer::reset()
	{
66
		m_samples_current = 0;
unknown's avatar
unknown committed
67

68
		m_collector->apply(*m_render_shader);
unknown's avatar
unknown committed
69

70
71
72
		m_render_shader->uniform("u_render_config.num_bounces", m_bounce_count);
		m_render_shader->uniform("u_render_config.clamp_direct", m_clamp_direct);
		m_render_shader->uniform("u_render_config.clamp_indirect", m_clamp_indirect);
73

74
75
76
77
78
79
		for (int i = 0; i < 4; ++i)
		{
			const std::string idx = "[" + std::to_string(i) + "]";
			m_render_shader->uniform("u_render_config.bounce_thresholds" + idx, m_bounce_thresholds[i]);
			m_render_shader->uniform("u_linespace_properties.bounce_thresholds" + idx, m_linespace_bounces[i]);
		}
80

81
82
83
		m_render_shader->uniform("u_linespace_properties.accuracy_quality", m_linespace_accuracy);
		m_render_shader->uniform("u_linespace_properties.shadow_quality", m_linespace_shadow);
		m_render_shader->uniform("u_linespace_properties.distance_threshold", m_linespace_distance);
unknown's avatar
unknown committed
84

85
86
87
88
89
		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");
	}
90

91
	const core::Texture &Pathtracer::render(unsigned width, unsigned height)
92
	{
93
94
95
		if (width != m_width || height != m_height) {
			m_width = width;
			m_height = height;
96

97
			m_trace_buffer.reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
98
			m_render_target = std::make_unique<core::Texture>(core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
Johannes Braun's avatar
Johannes Braun committed
99

100
			m_render_shader->uniform("textures.render_target", m_render_target->imageAddress(gl::Access::eReadWrite));
Johannes Braun's avatar
Johannes Braun committed
101
			m_render_shader->storageBuffer("trace_buffer", m_trace_buffer);
102
103

			m_samples_current = 0;
unknown's avatar
unknown committed
104
105
		}

106
		if (m_samples_current == 0)
Johannes Braun's avatar
Johannes Braun committed
107
		{
108
			m_collector->collect();
unknown's avatar
unknown committed
109
110
		}

111
112
		for (unsigned sample = 0; sample < m_samples_per_frame; sample++) {
			if (m_samples_current >= m_samples_max)
113
				return *m_render_target;
unknown's avatar
unknown committed
114

115
116
			{
				LogTime("Generate Primary Rays", m_debug_times);
117
				const static std::unique_ptr<RayGenerator> ray_generator = std::make_unique<RayGenerator>();
118
119
				ray_generator->generate(*this);
			}
unknown's avatar
unknown committed
120

121
122
123
124
			{
				LogTime("Trace and Bounce", m_debug_times);
				m_render_shader->use();
				m_render_shader->uniform("u_render_config.current_sample", m_samples_current);
125
				m_render_shader->uniform("random_seed", RayGenerator::randomSeed());
126
				m_render_shader->dispatch2D(width, 16, height, 16);
127
128
129
			}

			++m_samples_current;
unknown's avatar
unknown committed
130
		}
131

132
133
		return *m_render_target;
	}
134

Johannes Braun's avatar
Johannes Braun committed
135
	void Pathtracer::draw(std::shared_ptr<core::SceneNode> node)
136
137
138
139
	{
		// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
		if (!m_collector)
			reload(node);
140
141
		else
			m_collector->collect(node);
142

143
		static const auto texture_renderer = core::TextureRenderer::makeSimple();
144
		texture_renderer->draw(render(core::Context::current().window().getWidth(), core::Context::current().window().getHeight()));
145
	}
146

147
	void Pathtracer::saveRender(const fs::path& target) const
148
	{
149
150
151
152
		if (target.extension() == ".hdr")
			m_render_target->get<float>().save(target);
		else
			m_render_target->get<uint8_t>().save(target);
153
	}
154

155
	int& Pathtracer::EffectArray::operator[](Effect effect)
156
	{
157
		return m_data[static_cast<size_t>(effect)];
158
159
	}

160
	const int& Pathtracer::EffectArray::operator[](Effect effect) const
161
162
163
164
	{
		return m_data[static_cast<size_t>(effect)];
	}

165
	int& Pathtracer::EffectArray::operator[](int effect)
166
	{
167
168
169
170
171
172
		return m_data[effect];
	}

	const int& Pathtracer::EffectArray::operator[](int effect) const
	{
		return m_data[effect];
173
	}
174

175
176
	Pathtracer::LogTime::LogTime(std::string label, bool enabled)
		: m_enabled(enabled), m_label(std::move(label))
177
	{
178
179
180
181
182
183
		core::ClockGL::instance().start();
	}

	Pathtracer::LogTime::~LogTime()
	{
		if (m_enabled)
184
			Log_Hint << "Log Time for label=\"" << m_label << "\": " << core::ClockGL::instance().end() << " ns";
185
	}
186

187
188
	void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
	{
189
		assert(collector != nullptr);
190

191
		m_collector = collector;
192
193
		reset();
	}
194

Johannes Braun's avatar
Johannes Braun committed
195
	void Pathtracer::reload(std::shared_ptr<core::SceneNode> graph_root)
196
	{
197
198
		assert(graph_root != nullptr);

199
		if (!m_collector)
200
			m_collector = std::make_shared<SceneCollector>();
201

202
203
		m_collector->setDirty(DirtyFlags::eAll);
		m_collector->collect(graph_root);
204
205
		reset();
	}
206

Johannes Braun's avatar
Johannes Braun committed
207
	void Pathtracer::onNotify(msg::id_type id, msg::message_type message)
208
	{
Johannes Braun's avatar
Johannes Braun committed
209
		switch (id)
210
		{
211
		case tags::scene:
212
			reset();
213
214
			break;
		default: break;
215
		}
216
	}
217

218
219
220
221
	const core::Program& Pathtracer::shader() const
	{
		return *m_render_shader;
	}
222

223
224
	uint32_t Pathtracer::width() const
	{
225
		return m_width;
226
	}
227

228
229
	uint32_t Pathtracer::height() const
	{
230
		return m_height;
231
	}
232

Johannes Braun's avatar
Johannes Braun committed
233
	core::Buffer& Pathtracer::traceBuffer()
234
	{
Johannes Braun's avatar
Johannes Braun committed
235
		return m_trace_buffer;
236
	}
237

Johannes Braun's avatar
Johannes Braun committed
238
	const core::Texture& Pathtracer::renderTarget() const
239
240
241
	{
		return *m_render_target;
	}
242

243
244
245
246
	std::shared_ptr<SceneCollector> Pathtracer::collector() const
	{
		return m_collector;
	}
unknown's avatar
unknown committed
247
}