Refactor shaders

This commit is contained in:
2022-10-22 22:05:24 +02:00
parent 6b7774681f
commit 43e25b2628
23 changed files with 378 additions and 158 deletions

View File

@@ -2,7 +2,6 @@ add_library(fever_engine
main.cpp
Controller.cpp
Window.cpp
ShaderProgram.cpp
Light.cpp
Scene.cpp
FrameBuffer.cpp
@@ -13,6 +12,7 @@ add_library(fever_engine
gltf_loader.cpp
material.cpp
camera.cpp
shader.cpp
)
target_compile_features(fever_engine PUBLIC cxx_std_20)

View File

@@ -2,9 +2,10 @@
#include "FrameBuffer.h"
#include "Helper.h"
#include "Light.h"
#include "ShaderProgram.h"
#include "Window.h"
#include "gltf_loader.h"
#include "render.h"
#include "shader.h"
#include "util/Log.h"
#include <GLFW/glfw3.h>
@@ -22,10 +23,11 @@
using namespace entt::literals;
Controller::Controller()
: m_gameWindow(std::make_shared<Window>()),
: m_scene(m_shader_cache),
m_gameWindow(std::make_shared<Window>()),
m_postProcessFrameBuffer(m_gameWindow->dimensions().first,
m_gameWindow->dimensions().second,
postProcessingProgram)
post_processing_shader)
{
// if (!gltf.cameras.empty()) {
// auto const &gltf_camera = gltf.cameras.at(0);
@@ -41,18 +43,20 @@ Controller::Controller()
void Controller::run()
{
updateExposure(postProcessingProgram);
updateExposure(post_processing_shader);
// m_camera->translate(glm::vec3(0., .5, 2.));
entt::hashed_string shader_hash (Material::SHADER_NAME.data());
auto standard_material_shader =
m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
DirectionalLight directional_light(
DirectionalLight::Prototype("", glm::vec3(-0.2, -1.0, -0.3), glm::vec3(1.0f), 5.f),
&defaultProgram);
standard_material_shader.handle().get());
directional_light.setActive(true);
PointLight point_light(
PointLight::Prototype("", "", glm::vec3(4.0, 1.0, 6.0), glm::vec3(1.0F), 3.0F),
&defaultProgram);
standard_material_shader.handle().get());
point_light.setActive(true);
Log::logger().info("Startup complete. Enter game loop.");
@@ -62,8 +66,8 @@ void Controller::run()
// --- Timing ---
limit_framerate();
// --- Update game ---
m_gameWindow->clear_mouse_cursor_input(); // MOVE DOWN AGAIN!
// --- Check events, handle input ---
m_gameWindow->clear_mouse_cursor_input();
glfwPollEvents();
auto const &key_input = m_gameWindow->key_input();
@@ -72,7 +76,10 @@ void Controller::run()
static constexpr auto MICROSECONDS_PER_SECOND = 1'000'000;
m_scene.update(
std::chrono::microseconds(static_cast<unsigned>(m_deltaTime * MICROSECONDS_PER_SECOND)),
key_input,mouse_cursor_input, m_gameWindow->aspectRatio());
key_input,
mouse_cursor_input,
m_gameWindow->aspectRatio(),
m_gameWindow->cursor_catched());
// --- Render and buffer swap ---
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -80,7 +87,7 @@ void Controller::run()
m_postProcessFrameBuffer.bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_scene.draw(&defaultProgram);
Render::render(m_scene.registry());
Framebuffer::unbind();
m_postProcessFrameBuffer.drawOnEntireScreen();
@@ -92,19 +99,6 @@ void Controller::run()
m_gameWindow->update_dimensions();
update_window_dimensions();
}
// --- Check events, handle input ---
// m_gameWindow->clear_mouse_cursor_input();
// glfwPollEvents();
// auto const &key_input = m_gameWindow->key_input();
// auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
// m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime);
// if (m_gameWindow->cursor_catched()) {
// m_camera->updateDirectionFromMouseInput(mouse_cursor_input);
// }
}
}
@@ -137,9 +131,9 @@ void Controller::update_window_dimensions()
m_postProcessFrameBuffer.changeDimensions(dimensions.first, dimensions.second);
}
void Controller::updateExposure(ShaderProgram &shaderProgram) const
void Controller::updateExposure(Shader &shader) const
{
shaderProgram.bind();
shaderProgram.setUniform("u_exposure", m_exposure);
ShaderProgram::unbind();
shader.bind();
shader.set_uniform("u_exposure", m_exposure);
Shader::unbind();
}

View File

@@ -1,13 +1,14 @@
#pragma once
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "Scene.h"
#include "shader.h"
#include <glm/glm.hpp>
#include <memory>
#include <vector>
#include <unordered_map>
#include <vector>
#include <entt/entt.hpp>
class Window;
class Scene;
@@ -21,21 +22,21 @@ public:
void run();
void updateExposure(ShaderProgram &shaderProgram) const;
void updateExposure(Shader &shader) const;
private:
void limit_framerate();
void update_window_dimensions();
std::shared_ptr<Window> m_gameWindow;
ShaderProgram defaultProgram{{"defaultProgram", "data/shaders/basic.vert", "data/shaders/basic.frag"}};
ShaderProgram skyboxProgram{{"skyboxProgram", "data/shaders/skybox.vert", "data/shaders/skybox.frag"}};
ShaderProgram postProcessingProgram{
{"postProcessingProgram", "data/shaders/postprocessing.vert", "data/shaders/postprocessing.frag"}};
Shader skybox_shader{"skybox", "data/shaders"};
Shader post_processing_shader{"post_processing", "data/shaders"};
Framebuffer m_postProcessFrameBuffer;
entt::resource_cache<Shader, ShaderLoader> m_shader_cache;
static constexpr unsigned MAX_FPS = 60;
Scene m_scene;

View File

@@ -1,5 +1,5 @@
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "shader.h"
#include "util/Log.h"
#include <cstddef>
@@ -19,7 +19,7 @@ GLuint Framebuffer::getFBO() const
return m_FBO;
}
Framebuffer::Framebuffer(uint32_t width, uint32_t height, ShaderProgram &shaderProgram) : m_shaderProgram(shaderProgram)
Framebuffer::Framebuffer(uint32_t width, uint32_t height, Shader &shader) : m_shader(shader)
{
glGenFramebuffers(1, &m_FBO);
@@ -46,12 +46,11 @@ void Framebuffer::drawOnEntireScreen() const
glGetIntegerv(GL_POLYGON_MODE, &wireframe);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
m_shaderProgram.bind();
m_shader.bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, getTextureId());
GLint location = glGetUniformLocation(m_shaderProgram.getShaderProgramId(), "u_texture");
glUniform1i(location, 0);
m_shader.set_uniform("u_texture", 0);
// A VAO is necessary although no data is stored in it
GLuint temp_vao;
@@ -61,7 +60,7 @@ void Framebuffer::drawOnEntireScreen() const
glBindVertexArray(0);
glPolygonMode(GL_FRONT_AND_BACK, static_cast<GLenum>(wireframe));
m_shaderProgram.unbind();
m_shader.unbind();
}
void Framebuffer::changeDimensions(uint32_t width, uint32_t height)
@@ -108,7 +107,7 @@ void Framebuffer::generateTextures(uint32_t width, uint32_t height)
void Framebuffer::setExposureCorrection(bool exposureCorrection) const
{
m_shaderProgram.bind();
m_shaderProgram.setUniform("u_exposureCorrection", exposureCorrection);
m_shaderProgram.unbind();
m_shader.bind();
m_shader.set_uniform("u_exposureCorrection", exposureCorrection);
m_shader.unbind();
}

View File

@@ -2,12 +2,12 @@
#include <glad/gl.h>
class ShaderProgram;
class Shader;
class Framebuffer
{
public:
Framebuffer(uint32_t width, uint32_t height, ShaderProgram &shaderProgram);
Framebuffer(uint32_t width, uint32_t height, Shader &shader);
~Framebuffer();
void bind() const;
@@ -29,5 +29,5 @@ private:
GLuint m_depthStencilBuffer;
GLuint m_FBO;
ShaderProgram &m_shaderProgram;
Shader &m_shader;
};

View File

@@ -1,12 +1,12 @@
#include "Light.h"
#include "ShaderProgram.h"
#include "shader.h"
#include <string>
uint32_t Light::s_idCounter = 0;
Light::Light(const std::string &name, glm::vec3 color, float intensity, ShaderProgram *shaderProgram)
: m_shaderProgram(shaderProgram), m_intensity(intensity), m_lightColor(color * intensity)
Light::Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader)
: m_shader(shader), m_intensity(intensity), m_lightColor(color * intensity)
{
m_id = s_idCounter++;
}
@@ -18,9 +18,9 @@ glm::vec3 Light::getColor()
return m_lightColor;
}
void Light::setShaderProgram(ShaderProgram *shaderProgram)
void Light::setShader(Shader *shader)
{
this->m_shaderProgram = shaderProgram;
this->m_shader = shader;
update();
}
@@ -41,21 +41,21 @@ void Light::setActive(bool active)
update();
}
PointLight::PointLight(Prototype prototype, ShaderProgram *shaderProgram)
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_position(prototype.position)
PointLight::PointLight(Prototype prototype, Shader *shader)
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_position(prototype.position)
{
update();
}
void PointLight::update()
{
m_shaderProgram->bind();
m_shader->bind();
m_shaderProgram->setUniform((getStructMemberName() + "isActive").c_str(), m_isActive);
m_shaderProgram->setUniform((getStructMemberName() + "position").c_str(), m_position);
m_shaderProgram->setUniform((getStructMemberName() + "color").c_str(), m_lightColor);
m_shader->set_uniform((getStructMemberName() + "isActive").c_str(), m_isActive);
m_shader->set_uniform((getStructMemberName() + "position").c_str(), m_position);
m_shader->set_uniform((getStructMemberName() + "color").c_str(), m_lightColor);
m_shaderProgram->unbind();
m_shader->unbind();
}
std::string PointLight::getStructMemberName()
@@ -76,21 +76,21 @@ void PointLight::setPosition(glm::vec3 position)
update();
}
DirectionalLight::DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram)
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_direction(prototype.direction)
DirectionalLight::DirectionalLight(Prototype prototype, Shader *shader)
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_direction(prototype.direction)
{
update();
}
void DirectionalLight::update()
{
m_shaderProgram->bind();
m_shader->bind();
m_shaderProgram->setUniform("u_directionalLight.isActive", m_isActive);
m_shaderProgram->setUniform("u_directionalLight.direction", m_direction);
m_shaderProgram->setUniform("u_directionalLight.color", m_lightColor);
m_shader->set_uniform("u_directionalLight.isActive", m_isActive);
m_shader->set_uniform("u_directionalLight.direction", m_direction);
m_shader->set_uniform("u_directionalLight.color", m_lightColor);
m_shaderProgram->unbind();
m_shader->unbind();
}
void DirectionalLight::setDirection(glm::vec3 direction)

View File

@@ -3,7 +3,7 @@
#include <glm/glm.hpp>
#include <string>
class ShaderProgram;
class Shader;
class Light
{
@@ -21,7 +21,7 @@ public:
float intensity;
};
Light(const std::string &name, glm::vec3 color, float intensity, ShaderProgram *shaderProgram);
Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader);
virtual ~Light() = 0;
virtual void update() = 0;
@@ -29,12 +29,12 @@ public:
void setActive(bool active);
void setColor(glm::vec3 color);
void setIntensity(float intensity);
void setShaderProgram(ShaderProgram *shaderProgram);
void setShader(Shader *shader);
glm::vec3 getColor();
protected:
ShaderProgram *m_shaderProgram;
Shader *m_shader;
uint32_t m_id;
static uint32_t s_idCounter;
@@ -59,7 +59,7 @@ public:
glm::vec3 position;
};
PointLight(Prototype prototype, ShaderProgram *shaderProgram);
PointLight(Prototype prototype, Shader *shader);
~PointLight() override = default;
void setPosition(glm::vec3 position);
@@ -84,7 +84,7 @@ public:
glm::vec3 direction;
};
DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram);
DirectionalLight(Prototype prototype, Shader *shader);
~DirectionalLight() override = default;
void setDirection(glm::vec3 direction);

View File

@@ -1,20 +1,21 @@
#include "Scene.h"
#include "ShaderProgram.h"
#include "camera.h"
#include "mesh.h"
#include "name.h"
#include "relationship.h"
#include "shader.h"
#include "transform.h"
#include "util/Log.h"
using namespace entt::literals;
// TODO: make scene initialization part of gltf loader as seen in bevy
Scene::Scene()
Scene::Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache)
{
GltfLoader loader{.image_cache = m_image_cache,
.material_cache = m_material_cache,
.mesh_cache = m_mesh_cache,
.shader_cache = shader_cache,
.gltf_mesh_cache = m_gltf_mesh_cache,
.gltf_node_cache = m_gltf_node_cache,
.gltf_scene_cache = m_gltf_scene_cache};
@@ -92,16 +93,16 @@ Scene::Scene()
// Spawn the camera
auto entity = m_registry.create();
m_registry.emplace<Name>(entity, "Camera");
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.5, -1.0)});
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.25, -1.0)});
m_registry.emplace<GlobalTransform>(entity, GlobalTransform{});
m_registry.emplace<Camera>(entity,
Camera{.projection = Camera::Perspective{}});
m_registry.emplace<Camera>(entity, Camera{.projection = Camera::Perspective{}});
}
void Scene::update(std::chrono::duration<float> delta,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio)
float aspect_ratio,
bool cursor_catched)
{
{
// Update GlobalTransform components
@@ -138,38 +139,10 @@ void Scene::update(std::chrono::duration<float> delta,
}
}
Camera::keyboard_movement(m_registry, key_input, delta);
Camera::mouse_orientation(m_registry, mouse_cursor_input);
Camera::aspect_ratio_update(m_registry, aspect_ratio);
}
void Scene::draw(ShaderProgram *shaderprogram) const
{
auto mesh_view = m_registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
auto camera_view = m_registry.view<Camera const, GlobalTransform const>();
auto camera_entity = camera_view.front();
auto [camera, camera_transform] = camera_view.get(camera_entity);
glm::mat4 view_projection_matrix =
camera.projection_matrix() * Camera::view_matrix(camera_transform);
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
shaderprogram->bind();
// Bind textures
material.bind(*shaderprogram);
// Bind modelview matrix uniform
{
glm::mat4 modelViewProj = view_projection_matrix * transform.transform;
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
shaderprogram->setUniform("u_modelMatrix", transform.transform);
shaderprogram->setUniform("u_viewPosition", camera_transform.position());
}
glBindVertexArray(mesh.vao);
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
glBindVertexArray(0);
ShaderProgram::unbind();
Camera::keyboard_movement(m_registry, key_input, delta);
if (cursor_catched) {
Camera::mouse_orientation(m_registry, mouse_cursor_input);
}
}

View File

@@ -8,19 +8,20 @@
#include <chrono>
#include <entt/entt.hpp>
class ShaderProgram;
class Shader;
class Scene
{
public:
Scene();
Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache);
void update(std::chrono::duration<float> delta_time,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio);
float aspect_ratio,
bool cursor_catched);
void draw(ShaderProgram *shaderprogram) const;
auto registry() -> entt::registry & { return m_registry; }
private:
entt::registry m_registry;

View File

@@ -7,8 +7,8 @@
ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreateProgram())
{
std::string vertexShaderSource = parse(prototype.vertexPath).value();
std::string fragmentShaderSource = parse(prototype.fragmentPath).value();
std::string vertexShaderSource = parse(prototype.vertexPath);
std::string fragmentShaderSource = parse(prototype.fragmentPath);
GLuint vertexShader = compile(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
@@ -21,7 +21,9 @@ ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreatePr
GLint isLinked = 0;
glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked);
if (isLinked == 0) {
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")", prototype.vertexPath, prototype.fragmentPath);
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")",
prototype.vertexPath,
prototype.fragmentPath);
}
#ifdef NDEBUG
@@ -50,19 +52,17 @@ void ShaderProgram::unbind()
glUseProgram(0);
}
auto ShaderProgram::parse(const std::filesystem::path &path) -> std::optional<std::string>
auto ShaderProgram::parse(const std::filesystem::path &path) -> std::string
{
std::fstream shaderfile;
shaderfile.open(path, std::ios::in);
std::fstream file;
file.open(path, std::ios::in);
if (!shaderfile.is_open()) {
Log::logger().warn("Shader \"{}\" not found", path.c_str());
return {};
if (!file.is_open()) {
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
std::terminate();
}
std::string contents((std::istreambuf_iterator<char>(shaderfile)), (std::istreambuf_iterator<char>()));
return contents;
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
}
auto ShaderProgram::compile(const std::string &shaderSource, GLenum type) -> GLuint
@@ -108,49 +108,49 @@ auto ShaderProgram::retrieveUniformLocation(std::string_view uniform_name) const
return location;
}
void ShaderProgram::setUniform(const std::string &name, bool value) const
void ShaderProgram::set_uniform(const std::string &name, bool value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1i(location, (int)value);
}
void ShaderProgram::setUniform(const std::string &name, int value) const
void ShaderProgram::set_uniform(const std::string &name, int value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1i(location, value);
}
void ShaderProgram::setUniform(const std::string &name, unsigned int value) const
void ShaderProgram::set_uniform(const std::string &name, unsigned int value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1ui(location, value);
}
void ShaderProgram::setUniform(const std::string &name, float value) const
void ShaderProgram::set_uniform(const std::string &name, float value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1f(location, value);
}
void ShaderProgram::setUniform(const std::string &name, glm::vec2 vector) const
void ShaderProgram::set_uniform(const std::string &name, glm::vec2 vector) const
{
GLint location = retrieveUniformLocation(name);
glUniform2f(location, vector.x, vector.y);
}
void ShaderProgram::setUniform(const std::string &name, glm::vec3 vector) const
void ShaderProgram::set_uniform(const std::string &name, glm::vec3 vector) const
{
GLint location = retrieveUniformLocation(name);
glUniform3f(location, vector.x, vector.y, vector.z);
}
void ShaderProgram::setUniform(const std::string &name, glm::mat3 matrix) const
void ShaderProgram::set_uniform(const std::string &name, glm::mat3 matrix) const
{
GLint location = retrieveUniformLocation(name);
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
}
void ShaderProgram::setUniform(const std::string &name, glm::mat4 matrix) const
void ShaderProgram::set_uniform(const std::string &name, glm::mat4 matrix) const
{
GLint location = retrieveUniformLocation(name);
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));

View File

@@ -26,19 +26,19 @@ public:
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
// May be rewritten...
void setUniform(const std::string &name, bool value) const;
void setUniform(const std::string &name, int value) const;
void setUniform(const std::string &name, unsigned int value) const;
void setUniform(const std::string &name, float value) const;
void setUniform(const std::string &name, glm::vec2 vector) const;
void setUniform(const std::string &name, glm::vec3 vector) const;
void setUniform(const std::string &name, glm::mat3 matrix) const;
void setUniform(const std::string &name, glm::mat4 matrix) const;
void set_uniform(const std::string &name, bool value) const;
void set_uniform(const std::string &name, int value) const;
void set_uniform(const std::string &name, unsigned int value) const;
void set_uniform(const std::string &name, float value) const;
void set_uniform(const std::string &name, glm::vec2 vector) const;
void set_uniform(const std::string &name, glm::vec3 vector) const;
void set_uniform(const std::string &name, glm::mat3 matrix) const;
void set_uniform(const std::string &name, glm::mat4 matrix) const;
auto getShaderProgramId() const -> GLuint;
private:
static auto parse(const std::filesystem::path &path) -> std::optional<std::string>;
static auto parse(const std::filesystem::path &path) -> std::string;
static auto compile(const std::string &shaderSource, GLenum type) -> GLuint;
GLuint m_shaderProgramId;

View File

@@ -1,6 +1,6 @@
#include "gltf_loader.h"
#include "util/Log.h"
#include "definitions/attribute_locations.h"
#include "util/Log.h"
#include <iterator>
@@ -73,7 +73,8 @@ static auto load_material(fx::gltf::Material const &material,
fx::gltf::Document const &gltf,
std::filesystem::path const &document_path,
entt::resource_cache<Material> &material_cache,
entt::resource_cache<Image> &image_cache) -> entt::resource<Material>
entt::resource_cache<Image> &image_cache,
entt::resource_cache<Shader, ShaderLoader> &shader_cache) -> entt::resource<Material>
{
auto base_color_texture_id = material.pbrMetallicRoughness.baseColorTexture.index;
auto normal_texture_id = material.normalTexture.index;
@@ -92,6 +93,10 @@ static auto load_material(fx::gltf::Material const &material,
load_texture(normal_texture, gltf, document_path, Image::ColorFormat::RGB, image_cache);
}
entt::hashed_string shader_hash(Material::SHADER_NAME.data());
entt::resource<Shader> shader =
shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
if (material.name.empty()) {
Log::logger().warn("glTF material has no name.");
}
@@ -100,7 +105,8 @@ static auto load_material(fx::gltf::Material const &material,
return material_cache
.load(material_hash,
Material{.base_color_texture = base_color_image,
.normal_map_texture = normal_map_image})
.normal_map_texture = normal_map_image,
.shader = shader})
.first->second;
}
@@ -256,8 +262,8 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
// Load materials
std::vector<entt::resource<Material>> materials;
for (auto const &gltf_material : gltf.materials) {
entt::resource<Material> material =
load_material(gltf_material, gltf, document_path, material_cache, image_cache);
entt::resource<Material> material = load_material(
gltf_material, gltf, document_path, material_cache, image_cache, shader_cache);
materials.push_back(material);
}

View File

@@ -55,6 +55,7 @@ struct GltfLoader final
entt::resource_cache<Image> &image_cache;
entt::resource_cache<Material> &material_cache;
entt::resource_cache<Mesh> &mesh_cache;
entt::resource_cache<Shader, ShaderLoader> &shader_cache;
entt::resource_cache<GltfMesh> &gltf_mesh_cache;
entt::resource_cache<GltfNode> &gltf_node_cache;

View File

@@ -1,7 +1,7 @@
#include "material.h"
#include "ShaderProgram.h"
#include "shader.h"
GpuMaterial::GpuMaterial(Material const &material)
GpuMaterial::GpuMaterial(Material const &material) : shader(material.shader)
{
int texture_unit_counter = 0;
@@ -17,11 +17,11 @@ GpuMaterial::GpuMaterial(Material const &material)
normal_map_texture = std::make_pair(GpuImage(material.normal_map_texture.value()), binding);
}
}
void GpuMaterial::bind(ShaderProgram const &shader_program) const
void GpuMaterial::bind() const
{
auto bind_texture = [&shader_program](auto const &texture) {
auto bind_texture = [this](auto const &texture) {
if (texture.has_value()) {
shader_program.setUniform(texture->second.uniform_name, texture->second.texture_unit);
shader->set_uniform(texture->second.uniform_name, texture->second.texture_unit);
glActiveTexture(GL_TEXTURE0 + texture->second.texture_unit);
glBindTexture(GL_TEXTURE_2D, texture->first.texture);
}

View File

@@ -1,23 +1,27 @@
#pragma once
#include "image.h"
#include "shader.h"
#include <entt/entt.hpp>
#include <optional>
class ShaderProgram;
class Shader;
struct Material
{
std::optional<entt::resource<Image>> base_color_texture;
std::optional<entt::resource<Image>> normal_map_texture;
static constexpr std::string_view SHADER_NAME{"standard_material"};
entt::resource<Shader> shader;
};
struct GpuMaterial
{
GpuMaterial(Material const &material);
void bind(ShaderProgram const &shader_program) const;
void bind() const;
struct Binding
{
@@ -27,4 +31,6 @@ struct GpuMaterial
std::optional<std::pair<GpuImage, Binding>> base_color_texture;
std::optional<std::pair<GpuImage, Binding>> normal_map_texture;
entt::resource<Shader> shader;
};

43
src/render.h Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include "camera.h"
#include "material.h"
#include "mesh.h"
#include <entt/entt.hpp>
namespace Render {
void render(entt::registry &registry)
{
auto mesh_view = registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
auto camera_view = registry.view<Camera const, GlobalTransform const>();
auto camera_entity = camera_view.front();
auto [camera, camera_transform] = camera_view.get(camera_entity);
glm::mat4 view_projection_matrix =
camera.projection_matrix() * Camera::view_matrix(camera_transform);
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
auto shader = material.shader;
shader->bind();
// Bind textures
material.bind();
// Bind modelview matrix uniform
{
glm::mat4 modelViewProj = view_projection_matrix * transform.transform;
shader->set_uniform("u_modelViewProjMatrix", modelViewProj);
shader->set_uniform("u_modelMatrix", transform.transform);
shader->set_uniform("u_viewPosition", camera_transform.position());
}
glBindVertexArray(mesh.vao);
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
glBindVertexArray(0);
Shader::unbind();
}
}
} // namespace Render

View File

@@ -69,7 +69,7 @@ void AbstractCubeMap::bind(ShaderProgram *shaderProgram) const
{
std::string uniformName = "u_skybox";
shaderProgram->setUniform(uniformName, 0);
shaderProgram->set_uniform(uniformName, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
}

146
src/shader.cpp Normal file
View File

@@ -0,0 +1,146 @@
#include "shader.h"
#include "util/Log.h"
#include <fmt/format.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
Shader::Shader(std::string_view name, std::filesystem::path const &directory)
: program(glCreateProgram())
{
std::filesystem::path vertex_shader_path = directory / name;
vertex_shader_path.concat(".vert");
std::filesystem::path frag_shader_path = directory / name;
frag_shader_path.concat(".frag");
std::string vertex_shader_source = parse(vertex_shader_path);
std::string fragment_shader_source = parse(frag_shader_path);
GLuint vertex_shader = compile(vertex_shader_source, GL_VERTEX_SHADER);
GLuint fragment_shader = compile(fragment_shader_source, GL_FRAGMENT_SHADER);
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
GLint linked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (linked == 0) {
Log::logger().warn(R"(Failed to link Shader "{}")", name);
}
#ifdef NDEBUG
glDetachShader(m_ShaderId, vertexShader);
glDetachShader(m_ShaderId, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
#endif
Log::logger().trace(R"(Loaded Shader "{}")", name);
}
Shader::~Shader()
{
glDeleteProgram(program);
}
void Shader::bind() const
{
glUseProgram(program);
}
void Shader::unbind()
{
glUseProgram(0);
}
auto Shader::parse(const std::filesystem::path &path) -> std::string
{
std::fstream file;
file.open(path, std::ios::in);
if (!file.is_open()) {
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
std::terminate();
}
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
}
auto Shader::compile(std::string_view source, GLenum type) -> GLuint
{
GLuint program = glCreateShader(type);
auto const *src = source.data();
glShaderSource(program, 1, &src, nullptr);
glCompileShader(program);
int result{};
glGetShaderiv(program, GL_COMPILE_STATUS, &result);
if (result != GL_TRUE) {
int length{};
glGetShaderiv(program, GL_INFO_LOG_LENGTH, &length);
std::string message;
message.reserve(static_cast<unsigned>(length));
glGetShaderInfoLog(program, length, &length, message.data());
Log::logger().error("Shader compilation failed: {}", message);
return 0;
}
return program;
}
auto Shader::retrieveUniformLocation(std::string_view uniform_name) const -> GLint
{
if (uniform_location_cache.find(uniform_name.data()) != uniform_location_cache.end()) {
return uniform_location_cache[uniform_name.data()];
}
GLint location = glGetUniformLocation(program, uniform_name.data());
if (location != -1) {
uniform_location_cache[uniform_name.data()] = location;
} else {
Log::logger().warn(R"(Uniform "{}" not found.)", uniform_name);
}
return location;
}
template <typename T>
void Shader::set_uniform(std::string_view name, T value) const
{
GLint location = retrieveUniformLocation(name);
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, int>) {
glUniform1i(location, (int)value);
} else if constexpr (std::is_same_v<T, unsigned>) {
glUniform1ui(location, value);
} else if constexpr (std::is_same_v<T, float>) {
glUniform1f(location, value);
} else if constexpr (std::is_same_v<T, glm::vec2>) {
glUniform2f(location, value.x, value.y); //NOLINT(cppcoreguidelines-pro-type-union-access)
} else if constexpr (std::is_same_v<T, glm::vec3>) {
glUniform3f(location, value.x, value.y, value.z); //NOLINT(cppcoreguidelines-pro-type-union-access)
} else if constexpr (std::is_same_v<T, glm::mat3>) {
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(value));
} else if constexpr (std::is_same_v<T, glm::mat4>) {
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}
}
template void Shader::set_uniform(std::string_view, bool) const;
template void Shader::set_uniform(std::string_view, int) const;
template void Shader::set_uniform(std::string_view, unsigned) const;
template void Shader::set_uniform(std::string_view, float) const;
template void Shader::set_uniform(std::string_view, glm::vec2) const;
template void Shader::set_uniform(std::string_view, glm::vec3) const;
template void Shader::set_uniform(std::string_view, glm::mat3) const;
template void Shader::set_uniform(std::string_view, glm::mat4) const;

50
src/shader.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <filesystem>
#include <glad/gl.h>
#include <glm/glm.hpp>
#include <string_view>
#include <unordered_map>
struct Shader
{
Shader(std::string_view name, std::filesystem::path const &directory);
Shader(Shader const &) = delete;
auto operator=(Shader const &) -> Shader & = delete;
Shader(Shader &&other) noexcept : program(other.program) { other.program = 0; }
auto operator=(Shader &&other) noexcept -> Shader &
{
program = other.program;
other.program = 0;
return *this;
};
~Shader();
void bind() const;
static void unbind();
template <typename T>
void set_uniform(std::string_view name, T value) const;
private:
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
static auto parse(const std::filesystem::path &path) -> std::string;
static auto compile(std::string_view source, GLenum type) -> GLuint;
GLuint program;
mutable std::unordered_map<std::string, GLint> uniform_location_cache;
};
struct ShaderLoader
{
using result_type = std::shared_ptr<Shader>;
static constexpr std::string_view shader_directory{"data/shaders"};
auto operator()(std::string_view name) -> result_type
{
return std::make_shared<Shader>(name, shader_directory);
}
};