Implemented uniform buffers. Optimized data upload to GPU

This commit is contained in:
2026-09-27 05:33:36 +02:00
parent 1703ead546
commit a9bda25031
13 changed files with 382 additions and 195 deletions

View File

@@ -26,6 +26,7 @@ OBJS := build/camera.o \
build/shader.o \
build/texture.o \
build/transform.o \
build/uniformbuffer.o \
build/utils.o \
build/window.o \
build/glad.o \

View File

@@ -110,6 +110,8 @@ void FrameBuffer::resize(GLsizei width, GLsizei height)
glBindRenderbuffer(GL_RENDERBUFFER, m_render_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
m_width, m_height);
glBindTexture(GL_TEXTURE_2D, 0);
}
} // namespace Fan

View File

@@ -69,7 +69,7 @@ int main()
/******************** Resource loading ********************/
auto shader = Shader::create("./src/shaders/default.vert", "./src/shaders/default.frag");
auto debug_shader = Shader::create("./src/shaders/debug.vert", "./src/shaders/debug.frag");
auto debug_shader = Shader::create("./src/shaders/debug.vert", "./src/shaders/debug.frag", false);
auto backpack = load_obj("./assets/backpack/backpack.obj", shader);

View File

@@ -5,7 +5,7 @@ namespace Fan
void Material::bind() const
{
shader->use();
shader->bind();
// Diffuse (slot 0)
if (diffuse_map) {

View File

@@ -19,7 +19,7 @@ Rc<Mesh> Mesh::create(const std::vector<Vertex>& vertices,
// Upload vertex data
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]),
&vertices[0], GL_STATIC_DRAW);
&vertices[0], GL_DYNAMIC_DRAW);
// Upload index data
if (has_indices) {

View File

@@ -1,6 +1,7 @@
#include <iostream>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <glad/gl.h>
#include "renderer.hpp"
@@ -8,12 +9,19 @@
namespace Fan
{
Rc<UniformBuffer> Renderer::s_camera_ubo = nullptr;
Rc<UniformBuffer> Renderer::s_light_ubo = nullptr;
void Renderer::init()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
using bp = Shader::BindingPoint;
s_camera_ubo = UniformBuffer::create(sizeof(CameraData), bp::Camera);
s_light_ubo = UniformBuffer::create(sizeof(LightEnvironmentData), bp::LightEnvironment);
}
void Renderer::set_viewport(int x, int y, int width, int height)
@@ -39,85 +47,35 @@ void Renderer::clear()
void Renderer::draw_scene(const Scene& scene, const Camera& camera,
int screen_width, int screen_height)
{
glm::mat4 view_projection = camera.get_view_projection_matrix(screen_width, screen_height);
GLuint last_shader_id = 0;
update_global_data(scene, camera, screen_width, screen_height);
// TODO: Order entities by material to minimize uniform uploads
for (const Entity& entity : scene.get_entities()) {
if (!entity.mesh || !entity.material || !entity.material->shader) { continue; }
// Sort Entities: Shader -> Material -> Entities
using RenderQueue = std::unordered_map<Shader*, std::unordered_map<Material*, std::vector<const Entity*>>>;
RenderQueue render_queue;
Rc<Shader> shader = entity.material->shader;
GLuint current_shader_id = shader->get_id();
// Only upload scene uniforms if the shader changed
if (current_shader_id != last_shader_id) {
shader->use();
// Upload camera uniforms
shader->set_mat4("u_view_projection", view_projection);
shader->set_vec3("u_view_pos", camera.position);
// Upload lighting uniforms
const LightEnvironment& env = scene.light_environment;
shader->set_vec3("u_directional_light.direction", env.directional_light.direction);
shader->set_vec3("u_directional_light.ambient", env.directional_light.ambient);
shader->set_vec3("u_directional_light.diffuse", env.directional_light.diffuse);
shader->set_vec3("u_directional_light.specular", env.directional_light.specular);
if (env.point_lights.size() > MAX_POINT_LIGHTS) {
std::cerr << "WARNING: RENDERER: Maximum number of point lights exceeded"
<< " (" << MAX_POINT_LIGHTS << ")" << std::endl;
}
int point_count = std::min(static_cast<int>(env.point_lights.size()), MAX_POINT_LIGHTS);
shader->set_int("u_point_light_count", point_count);
for (int i = 0; i < point_count; ++i) {
std::string prefix = "u_point_lights[" + std::to_string(i) + "].";
shader->set_vec3(prefix + "position", env.point_lights[i].position);
shader->set_float(prefix + "constant", env.point_lights[i].constant);
shader->set_float(prefix + "linear", env.point_lights[i].linear);
shader->set_float(prefix + "quadratic", env.point_lights[i].quadratic);
shader->set_vec3(prefix + "ambient", env.point_lights[i].ambient);
shader->set_vec3(prefix + "diffuse", env.point_lights[i].diffuse);
shader->set_vec3(prefix + "specular", env.point_lights[i].specular);
}
if (env.spot_lights.size() > MAX_SPOT_LIGHTS) {
std::cerr << "WARNING: RENDERER: Maximum number of spot lights exceeded"
<< " (" << MAX_POINT_LIGHTS << ")" << std::endl;
}
int spot_count = std::min(static_cast<int>(env.spot_lights.size()), MAX_SPOT_LIGHTS);
shader->set_int("u_spot_light_count", spot_count);
for (int i = 0; i < spot_count; ++i) {
std::string prefix = "u_spot_lights[" + std::to_string(i) + "].";
shader->set_vec3(prefix + "position", env.spot_lights[i].position);
shader->set_vec3(prefix + "direction", env.spot_lights[i].direction);
shader->set_float(prefix + "cut_off", env.spot_lights[i].cut_off);
shader->set_float(prefix + "outer_cut_off", env.spot_lights[i].outer_cut_off);
shader->set_float(prefix + "constant", env.spot_lights[i].constant);
shader->set_float(prefix + "linear", env.spot_lights[i].linear);
shader->set_float(prefix + "quadratic", env.spot_lights[i].quadratic);
shader->set_vec3(prefix + "ambient", env.spot_lights[i].ambient);
shader->set_vec3(prefix + "diffuse", env.spot_lights[i].diffuse);
shader->set_vec3(prefix + "specular", env.spot_lights[i].specular);
}
last_shader_id = current_shader_id;
for (const auto& entity : scene.get_entities()) {
if (!entity.mesh || !entity.material || !entity.material->shader) {
// Ignore empty entities
continue;
}
// Bind the specific textures and the shininess float
entity.material->bind();
Shader* shader_ptr = entity.material->shader.get();
Material* material_ptr = entity.material.get();
render_queue[shader_ptr][material_ptr].push_back(&entity);
}
// Upload the model matrix to transform the specific object
shader->set_mat4("u_model", entity.transform.get_model_matrix());
// Draw using the sorted queue
for (const auto& [shader, materials] : render_queue) {
shader->bind();
// Dispatch the draw call
entity.mesh->draw();
for (const auto& [material, entities] : materials) {
material->bind();
for (const auto& entity : entities) {
shader->set_mat4("u_model", entity->transform.get_model_matrix());
entity->mesh->draw();
}
}
}
}
@@ -126,46 +84,78 @@ void Renderer::draw_debug_wireframes(const Scene& scene, const Camera& camera,
const Rc<Shader>& debug_shader,
const Rc<Mesh>& default_mesh)
{
debug_shader->use();
debug_shader->set_mat4("u_view_projection", camera.get_view_projection_matrix(screen_width, screen_height));
update_global_data(scene, camera, screen_width, screen_height);
// Force wireframe mode and disable depth testing so we can see through objects
set_wireframe(true);
glDisable(GL_DEPTH_TEST);
// Draw all standard entities (green)
debug_shader->set_vec3("u_color", glm::vec3(0.0f, 0.7f, 0.0f));
for (const Entity& entity : scene.get_entities()) {
// If an entity has no mesh, use the default debug mesh
auto mesh = entity.mesh ? entity.mesh : default_mesh;
debug_shader->bind();
for (const auto& entity : scene.get_entities()) {
debug_shader->set_mat4("u_model", entity.transform.get_model_matrix());
mesh->draw();
if (entity.mesh) {
entity.mesh->draw();
} else {
default_mesh->draw();
}
}
// Draw point lights (yellow)
debug_shader->set_vec3("u_color", glm::vec3(0.7f, 0.7f, 0.0f));
for (const PointLight& light : scene.light_environment.point_lights) {
glm::mat4 model = glm::translate(glm::mat4(1.0f), light.position);
model = glm::scale(model, glm::vec3(0.2f));
debug_shader->set_mat4("u_model", model);
default_mesh->draw();
}
// Draw spot lights (cyan)
debug_shader->set_vec3("u_color", glm::vec3(0.0f, 0.7f, 0.7f));
for (const SpotLight& light : scene.light_environment.spot_lights) {
glm::mat4 model = glm::translate(glm::mat4(1.0f), light.position);
model = glm::scale(model, glm::vec3(0.2f));
debug_shader->set_mat4("u_model", model);
default_mesh->draw();
}
// Restore state
glEnable(GL_DEPTH_TEST);
set_wireframe(false);
}
void Renderer::update_global_data(const Scene& scene, const Camera& camera, int screen_width, int screen_height)
{
// Update camera UBO
CameraData cam_data{};
cam_data.view = camera.get_view_matrix();
cam_data.projection = camera.get_projection_matrix(screen_width, screen_height);
s_camera_ubo->update(&cam_data, sizeof(CameraData));
// Update light UBO
LightEnvironmentData light_data{};
const LightEnvironment& env = scene.light_environment;
// Map DirectionalLight
const auto& dir_src = env.directional_light;
light_data.dir_light.direction = glm::vec4(dir_src.direction, 0.0f);
light_data.dir_light.ambient = glm::vec4(dir_src.ambient, 0.0f);
light_data.dir_light.diffuse = glm::vec4(dir_src.diffuse, 0.0f);
light_data.dir_light.specular = glm::vec4(dir_src.specular, 0.0f);
// Map PointLights
if (light_data.active_point_lights > MAX_POINT_LIGHTS) {
std::cerr << "WARNING: RENDERER: Maximum number of point lights reached"
<< " (" << MAX_POINT_LIGHTS << ")" << std::endl;
}
light_data.active_point_lights = std::min(static_cast<int>(env.point_lights.size()), MAX_POINT_LIGHTS);
for (int i = 0; i < light_data.active_point_lights; ++i) {
const auto& src = env.point_lights[i];
light_data.point_lights[i].position = glm::vec4(src.position, 1.0f);
light_data.point_lights[i].ambient = glm::vec4(src.ambient, 1.0f);
light_data.point_lights[i].diffuse = glm::vec4(src.diffuse, 1.0f);
light_data.point_lights[i].specular = glm::vec4(src.specular, 1.0f);
light_data.point_lights[i].attenuation = glm::vec4(src.constant, src.linear, src.quadratic, 0.0f);
}
// Map SpotLights
if (light_data.active_spot_lights > MAX_SPOT_LIGHTS) {
std::cerr << "WARNING: RENDERER: Maximum number of spot lights reached"
<< " (" << MAX_SPOT_LIGHTS << ")" << std::endl;
}
light_data.active_spot_lights = std::min(static_cast<int>(env.spot_lights.size()), MAX_SPOT_LIGHTS);
for (int i = 0; i < light_data.active_spot_lights; ++i) {
const auto& src = env.spot_lights[i];
light_data.spot_lights[i].position = glm::vec4(src.position, 1.0f);
light_data.spot_lights[i].direction = glm::vec4(src.direction, 0.0f);
light_data.spot_lights[i].ambient = glm::vec4(src.ambient, 1.0f);
light_data.spot_lights[i].diffuse = glm::vec4(src.diffuse, 1.0f);
light_data.spot_lights[i].specular = glm::vec4(src.specular, 1.0f);
light_data.spot_lights[i].attenuation = glm::vec4(src.constant, src.linear, src.quadratic, 0.0f);
light_data.spot_lights[i].cut_offs = glm::vec4(src.cut_off, src.outer_cut_off, 0.0f, 0.0f);
}
s_light_ubo->update(&light_data, sizeof(LightEnvironmentData));
}
} // namespace Fan

View File

@@ -3,6 +3,7 @@
#include "scene.hpp"
#include "camera.hpp"
#include "uniformbuffer.hpp"
namespace Fan
{
@@ -23,6 +24,58 @@ public:
int screen_width, int screen_height,
const Rc<Shader>& debug_shader,
const Rc<Mesh>& default_mesh);
private:
static Rc<UniformBuffer> s_camera_ubo;
static Rc<UniformBuffer> s_light_ubo;
static void update_global_data(const Scene& scene, const Camera& camera,
int screen_width, int screen_height);
struct CameraData {
glm::mat4 view;
glm::mat4 projection;
};
// Maps to Fan::DirectionalLight
struct DirectionalLightData {
glm::vec4 direction;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
};
// Maps to Fan::PointLight
struct PointLightData {
glm::vec4 position;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
glm::vec4 attenuation; // x = constant, y = linear, z = quadratic
};
// Maps to Fan::SpotLight
struct SpotLightData {
glm::vec4 position;
glm::vec4 direction;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
glm::vec4 attenuation; // x = constant, y = linear, z = quadratic
glm::vec4 cut_offs; // x = cut_off (cos), y = outer_cut_off (cos)
};
struct LightEnvironmentData {
DirectionalLightData dir_light;
int active_point_lights;
int active_spot_lights;
int _padding[2]; // Pad the 8 bytes of integers to a 16-byte boundary
PointLightData point_lights[MAX_POINT_LIGHTS];
SpotLightData spot_lights[MAX_SPOT_LIGHTS];
};
};
} // namespace Fan

View File

@@ -9,7 +9,8 @@ namespace Fan
{
Rc<Shader> Shader::create(const std::string& vertex_shader_path,
const std::string& fragment_shader_path)
const std::string& fragment_shader_path,
bool bind_standard_blocks/* = true*/)
{
auto vertex_shader = compile_shader(vertex_shader_path, GL_VERTEX_SHADER);
if (!vertex_shader) {
@@ -46,7 +47,14 @@ Rc<Shader> Shader::create(const std::string& vertex_shader_path,
return nullptr;
}
return make_rc<Shader>(shader_program);
Rc<Shader> shader = make_rc<Shader>(shader_program);
if (bind_standard_blocks) {
shader->bind_uniform_block("CameraBlock", BindingPoint::Camera);
shader->bind_uniform_block("LightEnvironmentBlock", BindingPoint::LightEnvironment);
}
return shader;
}
Shader::~Shader()
@@ -141,7 +149,7 @@ Opt<GLuint> Shader::compile_shader(const std::string& source_path,
return shader;
}
void Shader::use() const
void Shader::bind() const
{
if (m_id == 0) {
return;
@@ -150,4 +158,17 @@ void Shader::use() const
glUseProgram(m_id);
}
void Shader::bind_uniform_block(const std::string& name, GLuint binding_point) const
{
GLuint block_index = glGetUniformBlockIndex(m_id, name.c_str());
if (block_index == GL_INVALID_INDEX) {
std::cerr << "ERROR: SHADER: Uniform block not found: "
<< name << std::endl;
return;
}
glUniformBlockBinding(m_id, block_index, binding_point);
}
} // namespace Fan

View File

@@ -13,8 +13,15 @@ namespace Fan
class Shader
{
public:
struct BindingPoint
{
static constexpr GLuint Camera = 0;
static constexpr GLuint LightEnvironment = 1;
};
static Rc<Shader> create(const std::string& vertex_path,
const std::string& fragment_path);
const std::string& fragment_path,
bool bind_standard_blocks = true);
Shader(GLuint id) : m_id{id} {}
~Shader();
@@ -33,7 +40,8 @@ public:
void set_vec3(const std::string& name, const glm::vec3& value);
void set_mat4(const std::string& name, const glm::mat4& value);
void use() const;
void bind() const;
void bind_uniform_block(const std::string& name, GLuint binding_point) const;
private:
GLuint m_id{};

View File

@@ -1,143 +1,139 @@
#version 330 core
struct Material
{
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct DirectionalLight
{
vec3 direction;
/******************** std140 struct layouts ********************/
vec3 ambient;
vec3 diffuse;
vec3 specular;
struct DirLight {
vec4 direction;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
struct PointLight {
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 attenuation; // x = constant, y = linear, z = quadratic
};
struct SpotLight {
vec3 position;
vec3 direction;
float cut_off;
float outer_cut_off;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec4 position;
vec4 direction;
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 attenuation; // x = constant, y = linear, z = quadratic
vec4 cut_offs; // x = cut_off (cos), y = outer_cut_off (cos)
};
/******************** Uniform buffers ********************/
layout (std140) uniform CameraBlock {
mat4 view;
mat4 projection;
};
#define MAX_POINT_LIGHTS 32
#define MAX_SPOT_LIGHTS 32
layout (std140) uniform LightEnvironmentBlock {
DirLight dir_light;
int active_point_lights;
int active_spot_lights;
PointLight point_lights[MAX_POINT_LIGHTS];
SpotLight spot_lights[MAX_SPOT_LIGHTS];
};
uniform Material u_material;
in vec3 frag_position;
in vec3 normal;
in vec2 texture_coords;
out vec4 frag_color;
uniform vec3 u_view_pos;
uniform Material u_material;
uniform DirectionalLight u_directional_light;
#define MAX_POINT_LIGHTS 32
#define MAX_SPOT_LIGHTS 32
uniform PointLight u_point_lights[MAX_POINT_LIGHTS];
uniform int u_point_light_count;
uniform SpotLight u_spot_lights[MAX_SPOT_LIGHTS];
uniform int u_spot_light_count;
vec3 calculate_directional_light(DirectionalLight light, vec3 normal, vec3 view_dir);
vec3 calculate_directional_light(DirLight light, vec3 normal, vec3 view_dir);
vec3 calculate_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 view_dir);
vec3 calculate_spot_light(SpotLight light, vec3 normal, vec3 frag_position, vec3 view_dir);
void main()
{
vec3 norm = normalize(normal);
vec3 view_dir = normalize(u_view_pos - frag_position);
vec3 result = calculate_directional_light(u_directional_light, norm, view_dir);
vec3 view_pos = vec3(inverse(view)[3]);
vec3 view_dir = normalize(view_pos - frag_position);
for (int i = 0; i < u_point_light_count; ++i) {
result += calculate_point_light(u_point_lights[i], norm, frag_position, view_dir);
// DirectionalLight
vec3 result = calculate_directional_light(dir_light, norm, view_dir);
// PointLights
for (int i = 0; i < active_point_lights; ++i) {
result += calculate_point_light(point_lights[i], norm, frag_position, view_dir);
}
for (int i = 0; i < u_spot_light_count; ++i) {
result += calculate_spot_light(u_spot_lights[i], norm, frag_position, view_dir);
// SpotLights
for (int i = 0; i < active_spot_lights; ++i) {
result += calculate_spot_light(spot_lights[i], norm, frag_position, view_dir);
}
frag_color = vec4(result, 1.0);
}
vec3 calculate_directional_light(DirectionalLight light, vec3 normal, vec3 view_dir)
vec3 calculate_directional_light(DirLight light, vec3 normal, vec3 view_dir)
{
vec3 light_dir = normalize(-light.direction);
vec3 light_dir = normalize(-light.direction.xyz);
float diff = max(dot(normal, light_dir), 0.0);
vec3 reflect_dir = reflect(-light_dir, normal);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), u_material.shininess);
vec3 ambient = light.ambient * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular * spec * vec3(texture(u_material.specular, texture_coords));
vec3 ambient = light.ambient.xyz * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse.xyz * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular.xyz * spec * vec3(texture(u_material.specular, texture_coords));
return ambient + diffuse + specular;
}
vec3 calculate_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 view_dir)
{
vec3 light_dir = normalize(light.position - frag_position);
vec3 light_dir = normalize(light.position.xyz - frag_position);
float diff = max(dot(normal, light_dir), 0.0);
vec3 reflect_dir = reflect(-light_dir, normal);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), u_material.shininess);
float dist = length(light.position - frag_position);
float attenuation = 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
vec3 ambient = light.ambient * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular * spec * vec3(texture(u_material.specular, texture_coords));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
float dist = length(light.position.xyz - frag_position);
float attenuation = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * (dist * dist));
return ambient + diffuse + specular;
vec3 ambient = light.ambient.xyz * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse.xyz * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular.xyz * spec * vec3(texture(u_material.specular, texture_coords));
return (ambient + diffuse + specular) * attenuation;
}
vec3 calculate_spot_light(SpotLight light, vec3 normal, vec3 frag_position, vec3 view_dir)
{
vec3 light_dir = normalize(light.position - frag_position);
vec3 light_dir = normalize(light.position.xyz - frag_position);
float diff = max(dot(normal, light_dir), 0.0);
vec3 reflect_dir = reflect(-light_dir, normal);
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), u_material.shininess);
float dist = length(light.position - frag_position);
float attenuation = 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist* dist));
float theta = dot(light_dir, normalize(-light.direction));
float epsilon = light.cut_off - light.outer_cut_off;
float intensity = clamp((theta - light.outer_cut_off) / epsilon, 0.0, 1.0);
float dist = length(light.position.xyz - frag_position);
float attenuation = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * (dist * dist));
vec3 ambient = light.ambient * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular * spec * vec3(texture(u_material.specular, texture_coords));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
float theta = dot(light_dir, normalize(-light.direction.xyz));
float epsilon = light.cut_offs.x - light.cut_offs.y;
float intensity = clamp((theta - light.cut_offs.y) / epsilon, 0.0, 1.0);
return ambient + diffuse + specular;
vec3 ambient = light.ambient.xyz * vec3(texture(u_material.diffuse, texture_coords));
vec3 diffuse = light.diffuse.xyz * diff * vec3(texture(u_material.diffuse, texture_coords));
vec3 specular = light.specular.xyz * spec * vec3(texture(u_material.specular, texture_coords));
return (ambient + diffuse + specular) * attenuation * intensity;
}

View File

@@ -8,12 +8,16 @@ out vec3 frag_position;
out vec3 normal;
out vec2 texture_coords;
layout (std140) uniform CameraBlock {
mat4 view;
mat4 projection;
};
uniform mat4 u_model;
uniform mat4 u_view_projection;
void main()
{
gl_Position = u_view_projection * u_model * vec4(a_position, 1.0);
gl_Position = projection * view * u_model * vec4(a_position, 1.0);
frag_position = vec3(u_model * vec4(a_position, 1.0));

70
src/uniformbuffer.cpp Normal file
View File

@@ -0,0 +1,70 @@
#include <iostream>
#include <utility>
#include "uniformbuffer.hpp"
namespace Fan
{
Rc<UniformBuffer> UniformBuffer::create(size_t size, GLuint binding_point)
{
GLuint id;
glGenBuffers(1, &id);
glBindBuffer(GL_UNIFORM_BUFFER, id);
glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, binding_point, id);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
std::cerr << "ERROR: UNIFORMBUFFER: Could not create uniformbuffer" << std::endl;
glDeleteBuffers(1, &id);
return nullptr;
}
return make_rc<UniformBuffer>(id, size, binding_point);
}
UniformBuffer::~UniformBuffer()
{
glDeleteBuffers(1, &m_id);
}
UniformBuffer::UniformBuffer(UniformBuffer&& other) noexcept
: m_id(std::exchange(other.m_id, 0))
, m_size(std::exchange(other.m_size, 0))
, m_binding_point(std::exchange(other.m_binding_point, 0))
{
}
UniformBuffer& UniformBuffer::operator=(UniformBuffer&& other) noexcept
{
if (this == &other) { return *this; }
std::swap(m_id, other.m_id);
std::swap(m_size, other.m_size);
std::swap(m_binding_point, other.m_binding_point);
return *this;
}
void UniformBuffer::update(const void* data, size_t size, size_t offset) const
{
if (size + offset > m_size) {
std::cerr << "ERROR: UNIFORMBUFFER: Attempted to upload data outside of bounds on update" << std::endl;
return;
}
if (!data) {
std::cerr << "ERROR: UNIFORMBUFFER: Provided null data pointer on update" << std::endl;
return;
}
glBindBuffer(GL_UNIFORM_BUFFER, m_id);
glBufferSubData(GL_UNIFORM_BUFFER, offset, size, data);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
} // namespace Fan

42
src/uniformbuffer.hpp Normal file
View File

@@ -0,0 +1,42 @@
#ifndef FAN_UNIFORMBUFFER_HPP_
#define FAN_UNIFORMBUFFER_HPP_
#include <cstddef>
#include <glad/gl.h>
#include "utils.hpp"
namespace Fan
{
class UniformBuffer
{
public:
static Rc<UniformBuffer> create(size_t size, GLuint binding_point);
UniformBuffer(GLuint id, size_t size, GLuint binding_point)
: m_id(id)
, m_size(size)
, m_binding_point(binding_point) {}
~UniformBuffer();
UniformBuffer(const UniformBuffer&) = delete;
UniformBuffer& operator=(const UniformBuffer&) = delete;
UniformBuffer(UniformBuffer&& other) noexcept;
UniformBuffer& operator=(UniformBuffer&& other) noexcept;
GLuint get_id() const;
size_t get_size() const;
GLuint get_binding_point() const;
// Upload data to the GPU buffer
void update(const void* data, size_t size, size_t offset = 0) const;
private:
GLuint m_id{};
size_t m_size{};
GLuint m_binding_point{};
};
} // namespace Fan
#endif // FAN_UNIFORMBUFFER_HPP_