pathtracer.cpp 8.96 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
{
9
	Pathtracer::Pathtracer(std::shared_ptr<core::SceneNode> graph_root, RayGenType ray_generator)
10
11
		: Pathtracer(std::make_shared<SceneCollector>(graph_root), ray_generator)
	{
12

13
	}
14

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

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

Johannes Braun's avatar
Johannes Braun committed
26
		core::Context::current().messages()->addObserver(this, tags::scene);
27
28
		m_render_target = std::make_unique<core::Texture>(core::Texture::Target::e2D, core::Texture::StoreFormat::eRGBA32Float);
		m_color_storage = 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
42
43
44
45
46
47
48
49
	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");
50
51
52
53
54
		m_bounce_thresholds[Effect::eDiffusion] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2));
		m_bounce_thresholds[Effect::eReflection] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4));
		m_bounce_thresholds[Effect::eTransmission] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4));
		m_bounce_thresholds[Effect::eEmission] = static_cast<uint8_t>(bounces_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8));
		
55
56
		//ls thresholds
		const auto ls_thresholds_child = pt_child.find_child_by_attribute("group", "name", "ls-thresholds");
57
58
59
60
61
		m_linespace_bounces[Effect::eDiffusion] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "diffusion").attribute("value").as_uint(2));
		m_linespace_bounces[Effect::eReflection] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "reflection").attribute("value").as_uint(4));
		m_linespace_bounces[Effect::eTransmission] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "transmission").attribute("value").as_uint(4));
		m_linespace_bounces[Effect::eEmission] = static_cast<uint8_t>(ls_thresholds_child.find_child_by_attribute("item", "name", "emission").attribute("value").as_uint(8));
		m_linespace_distance = ls_thresholds_child.find_child_by_attribute("item", "name", "distance").attribute("value").as_float(10.f);
62

63
64
		m_linespace_accuracy = ls_thresholds_child.find_child_by_attribute("item", "name", "accuracy").attribute("value").as_float(0.5f);
		m_linespace_shadow = ls_thresholds_child.find_child_by_attribute("item", "name", "shadow").attribute("value").as_float(0.5f);
65

66
67
		m_clamp_direct = pt_child.find_child_by_attribute("item", "name", "clamp-direct").attribute("value").as_float(8);
		m_clamp_indirect = pt_child.find_child_by_attribute("item", "name", "clamp-indirect").attribute("value").as_float(8);
68
	}
69

70
71
	void Pathtracer::reset()
	{
72
		m_samples_current = 0;
unknown's avatar
unknown committed
73

74
		m_collector->apply(*m_render_shader);
unknown's avatar
unknown committed
75

76
77
78
79
		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);
		m_render_shader->uniform("u_render_config.bounce_thresholds", uint32_t(m_bounce_thresholds));
80

81
82
83
84
		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);
		m_render_shader->uniform("u_linespace_properties.bounce_thresholds", uint32_t(m_linespace_bounces));
unknown's avatar
unknown committed
85

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

Johannes Braun's avatar
Johannes Braun committed
92
	const core::Texture &Pathtracer::render(uint32_t width, uint32_t height)
93
	{
94
95
96
		if (width != m_width || height != m_height) {
			m_width = width;
			m_height = height;
97

Johannes Braun's avatar
Johannes Braun committed
98
			m_trace_buffer.reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
99

100
101
			m_render_target->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
			m_color_storage->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
Johannes Braun's avatar
Johannes Braun committed
102

103
104
			m_render_shader->uniform("u_render_target", m_render_target->imageAddress(gl::Access::eReadWrite));
			m_render_shader->uniform("u_color_store", m_color_storage->imageAddress(gl::Access::eReadWrite));
Johannes Braun's avatar
Johannes Braun committed
105
			m_render_shader->storageBuffer("trace_buffer", m_trace_buffer);
106
107

			m_samples_current = 0;
unknown's avatar
unknown committed
108
109
		}

110
		if (m_samples_current == 0)
Johannes Braun's avatar
Johannes Braun committed
111
		{
112
			m_collector->collect();
Johannes Braun's avatar
Johannes Braun committed
113
			gl::clearTextureImage(m_color_storage->id(), 0, gl::TextureFormat::eRGBA, gl::Type::eFloat, glm::value_ptr(glm::vec4(0)));
unknown's avatar
unknown committed
114
115
		}

116
		for (unsigned sample = 0; sample < m_samples_per_frame; sample++) {
unknown's avatar
unknown committed
117

118
			if (m_samples_current >= m_samples_max)
119
				return *m_render_target;
unknown's avatar
unknown committed
120

121
			const static std::unique_ptr<RayGenerator> ray_generator = std::make_unique<RayGenerator>();
unknown's avatar
unknown committed
122

123
124
125
126
			{
				LogTime("Generate Primary Rays", m_debug_times);
				ray_generator->generate(*this);
			}
unknown's avatar
unknown committed
127

128
129
130
131
132
133
134
135
136
			{
				LogTime("Trace and Bounce", m_debug_times);
				m_render_shader->use();
				m_render_shader->uniform("u_render_config.current_sample", m_samples_current);
				m_render_shader->uniform("random_seed", ray_generator->randomSeed());
				m_render_shader->dispatch2d(width, 16, height, 16);
			}

			++m_samples_current;
unknown's avatar
unknown committed
137
		}
138

139
140
		return *m_render_target;
	}
141

Johannes Braun's avatar
Johannes Braun committed
142
	void Pathtracer::draw(std::shared_ptr<core::SceneNode> node)
143
144
145
146
	{
		// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
		if (!m_collector)
			reload(node);
147

148
		static const std::shared_ptr<core::TextureRenderer> texture_renderer = core::DefaultTextureRenderers::makeSimpleRenderer();
149
		texture_renderer->draw(render(core::Context::current().window().getWidth(), core::Context::current().window().getHeight()));
150
	}
151

152
	void Pathtracer::saveRender(const fs::path& target) const
153
	{
154
155
156
157
158
159
160
161
		if (target.extension() == ".hdr")
		{
			m_render_target->get<float>().save(target);
		}
		else
		{
			m_render_target->get<uint8_t>().save(target);
		}
162
	}
163

164
	Pathtracer::EffectArray::operator unsigned()
165
	{
166
167
168
169
170
171
172
173
174
175
176
		return *reinterpret_cast<uint32_t*>(m_data.data());
	}

	uint8_t& Pathtracer::EffectArray::operator[](Effect effect)
	{
		return m_data[static_cast<size_t>(effect)];
	}

	const uint8_t& Pathtracer::EffectArray::operator[](Effect effect) const
	{
		return m_data[static_cast<size_t>(effect)];
177
	}
178

179
	Pathtracer::LogTime::LogTime(std::string label, bool enabled): m_label(std::move(label)), m_enabled(enabled)
180
	{
181
182
183
184
185
186
187
		core::ClockGL::instance().start();
	}

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

190
191
	void Pathtracer::initialize(std::shared_ptr<SceneCollector> collector)
	{
192
		assert(collector != nullptr);
193

194
		m_collector = collector;
195
196
		reset();
	}
197

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

202
		if (!m_collector)
203
			m_collector = std::make_shared<SceneCollector>();
204

205
206
		m_collector->setDirty(DirtyFlags::eAll);
		m_collector->collect(graph_root);
207
208
		reset();
	}
209

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

221
222
223
224
	const core::Program& Pathtracer::shader() const
	{
		return *m_render_shader;
	}
225

226
227
	uint32_t Pathtracer::width() const
	{
228
		return m_width;
229
	}
230

231
232
	uint32_t Pathtracer::height() const
	{
233
		return m_height;
234
	}
235

Johannes Braun's avatar
Johannes Braun committed
236
	core::Buffer& Pathtracer::traceBuffer()
237
	{
Johannes Braun's avatar
Johannes Braun committed
238
		return m_trace_buffer;
239
	}
240

Johannes Braun's avatar
Johannes Braun committed
241
	const core::Texture& Pathtracer::renderTarget() const
242
243
244
	{
		return *m_render_target;
	}
245

246
247
248
249
	std::shared_ptr<SceneCollector> Pathtracer::collector() const
	{
		return m_collector;
	}
unknown's avatar
unknown committed
250
}