aurora-rendering-engine/src/rasterizer/rasterizer.cpp

198 lines
6.2 KiB
C++

/**
* @file rasterizer.cpp
* @brief Implementation of Rasterizer class
*/
#include <are/rasterizer/rasterizer.h>
#include <are/rasterizer/gbuffer.h>
#include <are/rasterizer/shader_program.h>
#include <are/scene/scene_manager.h>
#include <are/scene/camera.h>
#include <are/scene/mesh.h>
#include <are/scene/material.h>
#include <are/geometry/vertex.h>
#include <are/core/logger.h>
#include <are/core/profiler.h>
#include <are/platform/gl_context.h>
#include <glad/glad.h>
#include <glm/gtc/matrix_inverse.hpp>
namespace are {
Rasterizer::Rasterizer(int width, int height)
: gbuffer_(std::make_unique<GBuffer>(width, height))
, gbuffer_shader_(std::make_unique<ShaderProgram>())
, triangle_base_provider_(nullptr)
, state_()
, width_(width)
, height_(height) {
}
Rasterizer::~Rasterizer() = default;
void Rasterizer::set_state(const RasterizerState& state) {
state_ = state;
}
void Rasterizer::set_triangle_base_provider(std::function<uint32_t(size_t)> provider) {
triangle_base_provider_ = std::move(provider);
}
void Rasterizer::resize(int width, int height) {
ARE_PROFILE_FUNCTION();
if (width == width_ && height == height_) return;
width_ = width;
height_ = height;
gbuffer_->resize(width_, height_);
}
void Rasterizer::render_gbuffer(const SceneManager& scene, const Camera& camera) {
ARE_PROFILE_FUNCTION();
if (!gbuffer_shader_ || !gbuffer_shader_->is_valid()) {
ARE_LOG_ERROR("Rasterizer: gbuffer shader not ready");
return;
}
gbuffer_->bind();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (state_.enable_depth_test) {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
} else {
glDisable(GL_DEPTH_TEST);
}
if (state_.enable_cull_face) {
glEnable(GL_CULL_FACE);
glCullFace(static_cast<GLenum>(state_.cull_face_mode));
glFrontFace(static_cast<GLenum>(state_.front_face));
} else {
glDisable(GL_CULL_FACE);
}
gbuffer_shader_->use();
gbuffer_shader_->set_uniform("u_view", camera.get_view_matrix());
gbuffer_shader_->set_uniform("u_projection", camera.get_projection_matrix());
const auto& meshes = scene.get_all_meshes();
for (size_t mi = 0; mi < meshes.size(); ++mi) {
const auto& mesh = meshes[mi];
if (mesh.is_empty() || !mesh.has_gpu_resources()) continue;
Mat4 model = Mat4(1.0f);
gbuffer_shader_->set_uniform("u_model", model);
Mat3 normal_matrix = glm::inverseTranspose(Mat3(model));
gbuffer_shader_->set_uniform("u_normal_matrix", normal_matrix);
uint32_t tri_base = triangle_base_provider_ ? triangle_base_provider_(mi) : 0u;
// IMPORTANT: u_triangle_id_base is uint in GLSL, must use glUniform1ui
gbuffer_shader_->set_uniform("u_triangle_id_base", tri_base);
const Material* mat = scene.get_material(mesh.get_material());
if (mat) {
gbuffer_shader_->set_uniform("u_albedo", mat->get_albedo());
gbuffer_shader_->set_uniform("u_metallic", mat->get_metallic());
gbuffer_shader_->set_uniform("u_roughness", mat->get_roughness());
} else {
gbuffer_shader_->set_uniform("u_albedo", Vec3(0.8f));
gbuffer_shader_->set_uniform("u_metallic", 0.0f);
gbuffer_shader_->set_uniform("u_roughness", 0.5f);
}
glBindVertexArray(mesh.get_vao());
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.get_index_count()), GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
}
gbuffer_->unbind();
ARE_GL_CHECK();
}
GBuffer& Rasterizer::get_gbuffer() { return *gbuffer_; }
const GBuffer& Rasterizer::get_gbuffer() const { return *gbuffer_; }
void Rasterizer::upload_mesh(Mesh& mesh) {
ARE_PROFILE_FUNCTION();
if (mesh.is_empty()) {
ARE_LOG_WARN("Rasterizer: upload_mesh on empty mesh");
return;
}
if (mesh.has_gpu_resources()) delete_mesh(mesh);
setup_mesh_buffers(mesh);
}
void Rasterizer::delete_mesh(Mesh& mesh) {
ARE_PROFILE_FUNCTION();
uint32_t vao = mesh.get_vao();
uint32_t vbo = mesh.get_vbo();
uint32_t ebo = mesh.get_ebo();
if (vao) glDeleteVertexArrays(1, &vao);
if (vbo) glDeleteBuffers(1, &vbo);
if (ebo) glDeleteBuffers(1, &ebo);
mesh.set_vao(0);
mesh.set_vbo(0);
mesh.set_ebo(0);
}
void Rasterizer::initialize_shaders(const std::string& shader_dir) {
ARE_PROFILE_FUNCTION();
bool ok = true;
ok &= gbuffer_shader_->load_shader(ShaderType::ARE_SHADER_VERTEX, shader_dir + "gbuffer/gbuffer.vert");
ok &= gbuffer_shader_->load_shader(ShaderType::ARE_SHADER_FRAGMENT, shader_dir + "gbuffer/gbuffer.frag");
ok &= gbuffer_shader_->link();
if (!ok) {
ARE_LOG_ERROR("Rasterizer: Failed to init gbuffer shaders");
}
}
void Rasterizer::setup_mesh_buffers(Mesh& mesh) {
ARE_PROFILE_FUNCTION();
uint32_t vao = 0, vbo = 0, ebo = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, mesh.get_vertex_count() * sizeof(Vertex), mesh.get_vertices().data(), GL_STATIC_DRAW);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.get_index_count() * sizeof(uint32_t), mesh.get_indices().data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(get_position_offset()));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(get_normal_offset()));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(get_texcoord_offset()));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<void*>(get_tangent_offset()));
glBindVertexArray(0);
mesh.set_vao(vao);
mesh.set_vbo(vbo);
mesh.set_ebo(ebo);
ARE_GL_CHECK();
}
} // namespace are