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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,20 +1,21 @@
#include "Scene.h" #include "Scene.h"
#include "ShaderProgram.h"
#include "camera.h" #include "camera.h"
#include "mesh.h" #include "mesh.h"
#include "name.h" #include "name.h"
#include "relationship.h" #include "relationship.h"
#include "shader.h"
#include "transform.h" #include "transform.h"
#include "util/Log.h" #include "util/Log.h"
using namespace entt::literals; using namespace entt::literals;
// TODO: make scene initialization part of gltf loader as seen in bevy // 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, GltfLoader loader{.image_cache = m_image_cache,
.material_cache = m_material_cache, .material_cache = m_material_cache,
.mesh_cache = m_mesh_cache, .mesh_cache = m_mesh_cache,
.shader_cache = shader_cache,
.gltf_mesh_cache = m_gltf_mesh_cache, .gltf_mesh_cache = m_gltf_mesh_cache,
.gltf_node_cache = m_gltf_node_cache, .gltf_node_cache = m_gltf_node_cache,
.gltf_scene_cache = m_gltf_scene_cache}; .gltf_scene_cache = m_gltf_scene_cache};
@@ -92,16 +93,16 @@ Scene::Scene()
// Spawn the camera // Spawn the camera
auto entity = m_registry.create(); auto entity = m_registry.create();
m_registry.emplace<Name>(entity, "Camera"); 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<GlobalTransform>(entity, GlobalTransform{});
m_registry.emplace<Camera>(entity, m_registry.emplace<Camera>(entity, Camera{.projection = Camera::Perspective{}});
Camera{.projection = Camera::Perspective{}});
} }
void Scene::update(std::chrono::duration<float> delta, void Scene::update(std::chrono::duration<float> delta,
KeyInput const &key_input, KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input, MouseCursorInput const &mouse_cursor_input,
float aspect_ratio) float aspect_ratio,
bool cursor_catched)
{ {
{ {
// Update GlobalTransform components // 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); Camera::aspect_ratio_update(m_registry, aspect_ratio);
} Camera::keyboard_movement(m_registry, key_input, delta);
if (cursor_catched) {
void Scene::draw(ShaderProgram *shaderprogram) const Camera::mouse_orientation(m_registry, mouse_cursor_input);
{
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();
} }
} }

View File

@@ -8,19 +8,20 @@
#include <chrono> #include <chrono>
#include <entt/entt.hpp> #include <entt/entt.hpp>
class ShaderProgram; class Shader;
class Scene class Scene
{ {
public: public:
Scene(); Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache);
void update(std::chrono::duration<float> delta_time, void update(std::chrono::duration<float> delta_time,
KeyInput const &key_input, KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_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: private:
entt::registry m_registry; entt::registry m_registry;

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#include "material.h" #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; 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); 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()) { 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); glActiveTexture(GL_TEXTURE0 + texture->second.texture_unit);
glBindTexture(GL_TEXTURE_2D, texture->first.texture); glBindTexture(GL_TEXTURE_2D, texture->first.texture);
} }

View File

@@ -1,23 +1,27 @@
#pragma once #pragma once
#include "image.h" #include "image.h"
#include "shader.h"
#include <entt/entt.hpp> #include <entt/entt.hpp>
#include <optional> #include <optional>
class ShaderProgram; class Shader;
struct Material struct Material
{ {
std::optional<entt::resource<Image>> base_color_texture; std::optional<entt::resource<Image>> base_color_texture;
std::optional<entt::resource<Image>> normal_map_texture; std::optional<entt::resource<Image>> normal_map_texture;
static constexpr std::string_view SHADER_NAME{"standard_material"};
entt::resource<Shader> shader;
}; };
struct GpuMaterial struct GpuMaterial
{ {
GpuMaterial(Material const &material); GpuMaterial(Material const &material);
void bind(ShaderProgram const &shader_program) const; void bind() const;
struct Binding struct Binding
{ {
@@ -27,4 +31,6 @@ struct GpuMaterial
std::optional<std::pair<GpuImage, Binding>> base_color_texture; std::optional<std::pair<GpuImage, Binding>> base_color_texture;
std::optional<std::pair<GpuImage, Binding>> normal_map_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"; std::string uniformName = "u_skybox";
shaderProgram->setUniform(uniformName, 0); shaderProgram->set_uniform(uniformName, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId); 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);
}
};