gbuffer.cpp 8.88 KB
Newer Older
unknown's avatar
unknown committed
1
2
3
4
#include "GBuffer.h" 
#include <core/state.h>
#include <core/numeric/flags.h>
#include <util/files.h>
5
#include <core/objects/light.h>
6
#include <core/message_tags.h>
unknown's avatar
unknown committed
7

8
namespace glare::core
unknown's avatar
unknown committed
9
{
10
11
	GBuffer::GBuffer()
		: m_width(0), m_height(0), m_skybox(std::make_shared<core::Skybox>())
12
	{
13
	}
14

15
16
17
18
19
	GBuffer::GBuffer(unsigned int width, unsigned int height, unsigned samples)
		: GBuffer()
	{
		initialize(width, height, samples);
	}
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
	void GBuffer::initialize(unsigned width, unsigned height, unsigned samples)
	{
		m_width = width;
		m_height = height;

		m_texture_renderer = DefaultTextureRenderers::makeRenderer(files::shader("screenshader/gbuffer/gbuffer.frag"));

		const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());

		m_gbuffer_framebuffer = std::make_shared<Framebuffer<TextureMultisampled>>(static_cast<unsigned>(mode->width), static_cast<unsigned>(mode->height), samples);
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor0);
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor1);
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor2);
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor3);
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor4);
36
		m_gbuffer_framebuffer->attach(gl::Attachment::eColor5);
37
38
		m_gbuffer_framebuffer->attach(gl::Attachment::eDepth);

39
40
41
42
43
		m_temporary_framebuffer_01 = std::make_shared<Framebuffer<Texture>>(static_cast<unsigned>(mode->width), static_cast<unsigned>(mode->height));
		m_temporary_framebuffer_01->attach(gl::Attachment::eColor0);
		m_temporary_framebuffer_02 = std::make_shared<Framebuffer<Texture>>(static_cast<unsigned>(mode->width), static_cast<unsigned>(mode->height));
		m_temporary_framebuffer_02->attach(gl::Attachment::eColor0);

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
		m_lights_buffer = std::make_unique<Buffer<gl::BufferType::eShaderStorage>>();

		//Update all uniforms that won't change anymore...
		m_texture_renderer->shader().uniform("u_gbuffer.base_ior", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor0).makeTextureResident());
		m_texture_renderer->shader().uniform("u_gbuffer.rough_metallic_transmit_emit", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor1).makeTextureResident());
		m_texture_renderer->shader().uniform("u_gbuffer.normal", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor2).makeTextureResident());
		m_texture_renderer->shader().uniform("u_gbuffer.modelview_position", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor3).makeTextureResident());
		m_texture_renderer->shader().uniform("u_gbuffer.world_position", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor4).makeTextureResident());
		m_texture_renderer->shader().uniform("u_gbuffer.depth", m_gbuffer_framebuffer->depthAttachment().makeTextureResident());

		// Those will only be later updated at will when resizing.
		m_texture_renderer->shader().uniform("screen.width", m_width);
		m_texture_renderer->shader().uniform("screen.height", m_height);
		m_texture_renderer->shader().uniform("u_samples", m_gbuffer_framebuffer->samples());

		m_texture_renderer->shader().bindSubroutine(gl::ShaderType::eFragment, "u_light_sample[0]", "samplePoint");
		m_texture_renderer->shader().bindSubroutine(gl::ShaderType::eFragment, "u_light_sample[1]", "sampleSpot");
		m_texture_renderer->shader().bindSubroutine(gl::ShaderType::eFragment, "u_light_sample[2]", "sampleDirectional");
		m_texture_renderer->shader().bindSubroutine(gl::ShaderType::eFragment, "u_light_sample[3]", "sampleAmbient");

		registerForMessage(tags::light);
	}
unknown's avatar
unknown committed
66

67
68
69
70
	GBuffer::~GBuffer()
	{
		cleanUp();
	}
71

72
73
74
75
	void GBuffer::cleanUp()
	{
		unregisterForMessage(tags::light);
	}
76

77
78
79
	void GBuffer::handle(messaging::message_t &message)
	{
		switch (message.name)
80
		{
81
82
83
84
85
86
87
88
89
90
		default: break;
		case tags::light:
		{
			auto light_update = message.as<LightUpdate>();
			if (light_update.ptr && m_light_to_index.count(light_update.light_id) == 0)
			{
				//Light has just been created.
				m_lights.push_back(light_update.ptr->buildLightShadow());
				m_light_to_index[light_update.light_id] = m_lights.size() - 1;
				m_lights_buffer->upload<LightShadow>(m_lights, gl::BufferUsage::eDynamicCopy);
91

92
93
94
95
96
97
98
99
				//Check if successfully added.
				assert(m_light_to_index.count(light_update.light_id) != 0);
				assert(m_lights.size() > m_light_to_index.at(light_update.light_id));
			}
			else if (light_update.ptr == nullptr)
			{
				//Light has just been removed.
				if (m_light_to_index.count(light_update.light_id) != 0)
100
				{
101
102
					size_t position = m_light_to_index[light_update.light_id];
					m_lights.erase(m_lights.begin() + position);
103

104
					m_light_to_index.erase(light_update.light_id);
105

106
107
108
109
110
					for (auto it = m_light_to_index.begin(); it != m_light_to_index.end(); ++it)
					{
						// decrement vector index as one element has been removed before
						if (it->second >= position)
							it->second = it->second - 1;
111
112
					}

113
					m_lights_buffer->upload<LightShadow>(m_lights, gl::BufferUsage::eDynamicCopy);
114
115
				}

116
117
118
119
120
121
122
123
124
125
126
127
128
129
				//Check if successfully added.
				assert(m_light_to_index.count(light_update.light_id) == 0);
			}
			else
			{
				assert(m_light_to_index.count(light_update.light_id) != 0);

				// Light has changed.
				// don't change any indices, just update the buffer
				auto data = light_update.ptr->buildLightShadow();
				auto index = m_light_to_index[light_update.light_id];
				m_lights[index] = data;
				m_lights_buffer->map<LightShadow>(m_lights.size(), gl::BufferMapBit::eWrite)[index] = data;
				m_lights_buffer->unmap();
130
			}
131
		} break;
unknown's avatar
unknown committed
132
		}
133
	}
unknown's avatar
unknown committed
134

135
136
137
138
139
140
	void GBuffer::record(std::function<void()> render_function) const
	{
		activate();
		render_function();
		deactivate();
	}
unknown's avatar
unknown committed
141

142
143
144
145
146
	void GBuffer::activate() const
	{
		m_gbuffer_framebuffer->activate();
		gl::clear(gl::ClearBufferBits::eColor | gl::ClearBufferBits::eDepth);
	}
unknown's avatar
unknown committed
147

148
149
150
151
	void GBuffer::deactivate() const
	{
		m_gbuffer_framebuffer->deactivate();
	}
unknown's avatar
unknown committed
152

153
154
	void GBuffer::draw() const
	{
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

		m_temporary_framebuffer_01->activate();
		static auto ssao_renderer = DefaultTextureRenderers::makeRenderer(files::shader("screenshader/ssao/ssao.frag"));
		ssao_renderer->shader().uniform("projection_matrix", state::camera->projectionMatrix());
		ssao_renderer->shader().uniform("screen_space_positions", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor3).makeTextureResident());
		ssao_renderer->shader().uniform("screen_space_normals", m_gbuffer_framebuffer->colorAttachment(gl::Attachment::eColor5).makeTextureResident());
		ssao_renderer->shader().uniform("u_gbuffer.depth", m_gbuffer_framebuffer->depthAttachment().makeTextureResident());
		ssao_renderer->shader().uniform("screen_size", glm::vec2(m_width, m_height));
		ssao_renderer->draw();
		m_temporary_framebuffer_01->deactivate();

		m_temporary_framebuffer_02->activate();
		static auto blur_1d = DefaultTextureRenderers::makeRenderer(files::shader("screenshader/blur/blur_1d.frag"));
		blur_1d->shader().uniform("rgb_color_texture", m_temporary_framebuffer_01->colorAttachment(gl::Attachment::eColor0).makeTextureResident());
		blur_1d->shader().uniform("axis", 0u);
		blur_1d->draw();
		m_temporary_framebuffer_02->deactivate();

		m_temporary_framebuffer_01->activate();
		blur_1d->shader().uniform("rgb_color_texture", m_temporary_framebuffer_02->colorAttachment(gl::Attachment::eColor0).makeTextureResident());
		blur_1d->shader().uniform("axis", 1u);
		blur_1d->draw();
		m_temporary_framebuffer_01->deactivate();

179
180
181
		deactivate();
		gl::setEnabled(gl::EnableParameter::eDepthTest, false);
		m_texture_renderer->shader().use();
unknown's avatar
unknown committed
182

183
		m_texture_renderer->shader().storageBuffer("lightsBuffer", *m_lights_buffer);
unknown's avatar
unknown committed
184

185
186
		if (m_skybox->isInitialized())
			m_texture_renderer->shader().uniform("environment", m_skybox->makeResident());
187

188
		m_texture_renderer->shader().uniform("u_ssao_texture", m_temporary_framebuffer_01->colorAttachment(gl::Attachment::eColor0).makeTextureResident());
189
190
191
192
193
194
		m_texture_renderer->shader().uniform("u_view", state::camera->viewMatrix());
		m_texture_renderer->shader().uniform("u_projection", state::camera->projectionMatrix());
		m_texture_renderer->shader().uniform("camera_position", glm::vec3(state::camera->owner()->worldTransform().position));
		m_texture_renderer->draw();
		gl::setEnabled(gl::EnableParameter::eDepthTest, true);
	}
195

196
197
198
199
	std::shared_ptr<Skybox> GBuffer::getSkybox() const
	{
		return m_skybox;
	}
unknown's avatar
unknown committed
200

201
202
203
204
	void GBuffer::setSkybox(std::shared_ptr<Skybox> skybox)
	{
		m_skybox = skybox;
	}
unknown's avatar
unknown committed
205

206
207
208
209
	const Framebuffer<TextureMultisampled>& GBuffer::framebuffer() const
	{
		return *m_gbuffer_framebuffer;
	}
unknown's avatar
unknown committed
210

211
212
213
214
	void GBuffer::updateSize(unsigned width, unsigned height)
	{
		updateSize(width, height, m_gbuffer_framebuffer->samples());
	}
215

216
217
218
219
220
221
222
223
	void GBuffer::updateSize(unsigned width, unsigned height, unsigned samples)
	{
		m_width = width;// width;
		m_height = height;// height;
		m_gbuffer_framebuffer->resize(width, height, samples);
		m_texture_renderer->shader().uniform("screen.width", m_width);
		m_texture_renderer->shader().uniform("screen.height", m_height);
		m_texture_renderer->shader().uniform("u_samples", samples);
unknown's avatar
unknown committed
224
	}
225
}