From c493ba559b4635c5e8b1fedfdefa0ec1c226600e Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Tue, 20 Dec 2022 23:51:04 +0000 Subject: [PATCH] Add mesh renderer --- CMakeLists.txt | 4 +++ include/application.hpp | 4 +++ include/ecs/ecs_system.hpp | 13 ++++++++ include/ecs/mesh_renderer.hpp | 39 ++++++++++++++++++++--- include/resource_manager.hpp | 16 ++++++---- include/resources/material.hpp | 24 ++++++++++++++ include/resources/mesh.hpp | 58 ++++++++++++++++++++++++++++++++++ include/resources/shader.hpp | 35 ++++++++++++++++++++ include/scene.hpp | 13 ++++++-- include/scene_manager.hpp | 7 ++-- res/engine/shaders/basic.frag | 36 +++++++++++++++++++++ res/engine/shaders/basic.vert | 28 ++++++++++++++++ src/application.cpp | 10 ++++-- src/gfx_device_vulkan.cpp | 5 +-- src/resources/material.cpp | 18 +++++++++++ src/scene.cpp | 7 ++-- src/scene_manager.cpp | 6 ++-- test/src/game.cpp | 52 +++++++++++++++++++++--------- 18 files changed, 337 insertions(+), 38 deletions(-) create mode 100644 include/resources/material.hpp create mode 100644 include/resources/mesh.hpp create mode 100644 include/resources/shader.hpp create mode 100644 res/engine/shaders/basic.frag create mode 100644 res/engine/shaders/basic.vert create mode 100644 src/resources/material.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f2d95c9..964f8ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(SRC_FILES "src/scene_manager.cpp" "src/resources/texture.cpp" + "src/resources/material.cpp" "src/gfx_device_vulkan.cpp" @@ -38,7 +39,10 @@ set(INCLUDE_FILES "include/scene_manager.hpp" "include/resource_manager.hpp" + "include/resources/material.hpp" "include/resources/texture.hpp" + "include/resources/shader.hpp" + "include/resources/mesh.hpp" "include/gfx.hpp" "include/gfx_device.hpp" diff --git a/include/application.hpp b/include/application.hpp index 9a8cc6f..61d92f7 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -22,6 +22,8 @@ namespace engine { /* methods */ void gameLoop(); + void setFrameLimiter(bool on) { m_enableFrameLimiter = on; } + /* getters */ Window* window() { return m_window.get(); } GFXDevice* gfx() { return m_gfx.get(); } @@ -38,6 +40,8 @@ namespace engine { std::filesystem::path m_resourcesPath; + bool m_enableFrameLimiter = true; + }; } diff --git a/include/ecs/ecs_system.hpp b/include/ecs/ecs_system.hpp index 4ad605a..aafa4d6 100644 --- a/include/ecs/ecs_system.hpp +++ b/include/ecs/ecs_system.hpp @@ -5,10 +5,23 @@ namespace engine { + class Scene; + template class EcsSystem { public: + EcsSystem(Scene* scene) + : m_scene(scene) + { + + } + ~EcsSystem() {} + EcsSystem(const EcsSystem&) = delete; + EcsSystem& operator=(const EcsSystem&) = delete; + + Scene* const m_scene; + std::map m_components{}; virtual void onUpdate(float ts) = 0; diff --git a/include/ecs/mesh_renderer.hpp b/include/ecs/mesh_renderer.hpp index cb4a5ce..b2c14e1 100644 --- a/include/ecs/mesh_renderer.hpp +++ b/include/ecs/mesh_renderer.hpp @@ -2,24 +2,55 @@ #include "ecs_system.hpp" -#include "resources/texture.hpp" +#include "resources/material.hpp" +#include "resources/shader.hpp" +#include "resources/mesh.hpp" #include "log.hpp" +#include "scene.hpp" +#include "application.hpp" +#include "gfx_device.hpp" + +#include + namespace engine::ecs { struct MeshRendererComponent { - int number; - const resources::Texture* texture; + std::shared_ptr material; + std::shared_ptr mesh; }; class RendererSystem : public EcsSystem { public: + RendererSystem(Scene* scene) + : EcsSystem(scene) + { + + } + void onUpdate(float ts) override { for (const auto& [id, data] : m_components) { DEBUG("rendering entity {}\tts={}", id, ts); - DEBUG(" with texture: {}, number = {}", (void*)data.texture, data.number); + DEBUG("material shader addr: {}", (void*)data.material->getShader()); + + assert(data.material != nullptr); + assert(data.mesh != nullptr); + + struct { + glm::mat4 model; + glm::mat4 view; + } pushConsts{}; + pushConsts.model = glm::mat4{1.0f}; + pushConsts.view = glm::mat4{1.0f}; + + m_scene->app()->gfx()->draw( + data.material->getShader()->getPipeline(), + data.mesh->getVB(), + data.mesh->getIB(), + data.mesh->getCount(), + &pushConsts, sizeof(pushConsts), nullptr); } } }; diff --git a/include/resource_manager.hpp b/include/resource_manager.hpp index ec93e43..769c650 100644 --- a/include/resource_manager.hpp +++ b/include/resource_manager.hpp @@ -16,27 +16,31 @@ namespace engine { ResourceManager(const ResourceManager&) = delete; ResourceManager& operator=(const ResourceManager&) = delete; - T* add(const std::string& name, std::unique_ptr&& resource) + std::shared_ptr add(const std::string& name, std::unique_ptr&& resource) { if (m_resources.contains(name) == false) { - m_resources.emplace(name, std::move(resource)); + std::shared_ptr resourceSharedPtr(std::move(resource)); + m_resources.emplace(name, resourceSharedPtr); + return resourceSharedPtr; } else { throw std::runtime_error("Cannot add a resource which already exists"); } - return m_resources.at(name).get(); } - T* get(const std::string& name) + std::shared_ptr get(const std::string& name) { if (m_resources.contains(name)) { - return m_resources.at(name).get(); + std::weak_ptr ptr = m_resources.at(name); + if (ptr.expired() == false) { + return ptr.lock(); + } } return {}; } private: - std::unordered_map> m_resources{}; + std::unordered_map> m_resources{}; }; diff --git a/include/resources/material.hpp b/include/resources/material.hpp new file mode 100644 index 0000000..4c9f310 --- /dev/null +++ b/include/resources/material.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace engine::resources { + + class Shader; + + class Material { + + public: + Material(std::shared_ptr shader); + ~Material(); + Material(const Material&) = delete; + Material& operator=(const Material&) = delete; + + Shader* getShader() { return m_shader.get(); } + + private: + const std::shared_ptr m_shader; + + }; + +} diff --git a/include/resources/mesh.hpp b/include/resources/mesh.hpp new file mode 100644 index 0000000..9a4258d --- /dev/null +++ b/include/resources/mesh.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "gfx.hpp" +#include "gfx_device.hpp" + +#include +#include + +#include + +namespace engine { + struct Vertex { + glm::vec3 pos; + glm::vec3 norm; + glm::vec2 uv; + }; +} + +namespace engine::resources { + +class Mesh { + +public: + Mesh(GFXDevice* gfx, const std::vector& vertices) + : m_gfx(gfx) + { + m_count = vertices.size(); + + m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data()); + + std::vector indices(m_count); + for (int i = 0; i < m_count; i++) { + indices[i] = i; + } + m_ib = m_gfx->createBuffer(gfx::BufferType::INDEX, indices.size() * sizeof(uint32_t), indices.data()); + } + ~Mesh() + { + m_gfx->destroyBuffer(m_ib); + m_gfx->destroyBuffer(m_vb); + } + Mesh(const Mesh&) = delete; + Mesh& operator=(const Mesh&) = delete; + + auto getVB() { return m_vb; } + auto getIB() { return m_ib; } + auto getCount() { return m_count; } + +private: + GFXDevice* const m_gfx; + + const gfx::Buffer* m_vb; + const gfx::Buffer* m_ib; + uint32_t m_count; + +}; + +} diff --git a/include/resources/shader.hpp b/include/resources/shader.hpp new file mode 100644 index 0000000..4ce0a3f --- /dev/null +++ b/include/resources/shader.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "gfx.hpp" +#include "gfx_device.hpp" + +#include + +#include + +namespace engine::resources { + +class Shader { + +public: + Shader(GFXDevice* gfx, const char* vertPath, const char* fragPath, const gfx::VertexFormat& vertFormat, bool alphaBlending, bool cullBackFace) + : m_gfx(gfx) + { + m_pipeline = m_gfx->createPipeline(vertPath, fragPath, vertFormat, sizeof(glm::mat4), alphaBlending, cullBackFace); + } + ~Shader() + { + m_gfx->destroyPipeline(m_pipeline); + } + Shader(const Shader&) = delete; + Shader& operator=(const Shader&) = delete; + + const gfx::Pipeline* getPipeline() { return m_pipeline; } + +private: + GFXDevice* const m_gfx; + const gfx::Pipeline* m_pipeline; + +}; + +} diff --git a/include/scene.hpp b/include/scene.hpp index a691121..8fcbf72 100644 --- a/include/scene.hpp +++ b/include/scene.hpp @@ -1,17 +1,21 @@ #pragma once -#include "ecs/mesh_renderer.hpp" - #include "log.hpp" #include namespace engine { + class Application; + + namespace ecs { + class RendererSystem; + } + class Scene { public: - Scene(); + Scene(Application* app); Scene(const Scene&) = delete; Scene& operator=(const Scene&) = delete; ~Scene(); @@ -25,7 +29,10 @@ namespace engine { std::unique_ptr m_renderSystem; + Application* app() { return m_app; } + private: + Application* const m_app; uint32_t m_nextEntityID = 1000; }; diff --git a/include/scene_manager.hpp b/include/scene_manager.hpp index ec0542c..cff85b7 100644 --- a/include/scene_manager.hpp +++ b/include/scene_manager.hpp @@ -7,6 +7,7 @@ namespace engine { + class Application; class Scene; // "scene.hpp" namespace resources { class Texture; @@ -15,12 +16,12 @@ namespace engine { class SceneManager { public: - SceneManager(); + SceneManager(Application* app); ~SceneManager(); SceneManager(const SceneManager&) = delete; SceneManager& operator=(const SceneManager&) = delete; - Scene* createScene(std::unique_ptr&& scene); + Scene* createScene(); void updateActiveScene(float ts); @@ -28,6 +29,8 @@ namespace engine { ResourceManager* getTextureManager() { return m_textureManager.get(); } private: + Application* const m_app; + std::vector> m_scenes; int m_activeSceneIndex = -1; diff --git a/res/engine/shaders/basic.frag b/res/engine/shaders/basic.frag new file mode 100644 index 0000000..991a945 --- /dev/null +++ b/res/engine/shaders/basic.frag @@ -0,0 +1,36 @@ +#version 450 + +layout(location = 0) in vec3 fragPos; +layout(location = 1) in vec3 fragNorm; +layout(location = 2) in vec2 fragUV; +layout(location = 3) in vec3 fragLightPos; + +layout(location = 0) out vec4 outColor; + +void main() { + + // constants + vec3 lightColor = vec3(1.0, 1.0, 1.0); + vec3 ambientColor = vec3(1.0, 1.0, 1.0); + float ambientStrength = 0.05; + vec3 baseColor = vec3(fragUV.x, 0.0, fragUV.y); + vec3 emission = vec3(0.0, 0.0, 0.0); + + // code + + vec3 norm = normalize(fragNorm); + vec3 lightDir = normalize(fragLightPos - fragPos); + + vec3 diffuse = max(dot(norm, lightDir), 0.0) * lightColor; + vec3 ambient = ambientColor * ambientStrength; + + vec3 viewDir = normalize(-fragPos); + vec3 reflectDir = reflect(-lightDir, norm); + + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = 0.5 * spec * lightColor; + + vec3 lighting = min(diffuse + ambient + specular, 1.0); + outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(1.0)); +} + diff --git a/res/engine/shaders/basic.vert b/res/engine/shaders/basic.vert new file mode 100644 index 0000000..6c63696 --- /dev/null +++ b/res/engine/shaders/basic.vert @@ -0,0 +1,28 @@ +#version 450 + +layout(binding = 0) uniform UBO { + mat4 proj; +} ubo; + +layout( push_constant ) uniform Constants { + mat4 model; + mat4 view; +} constants; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNorm; +layout(location = 2) in vec2 inUV; + +layout(location = 0) out vec3 fragPos; +layout(location = 1) out vec3 fragNorm; +layout(location = 2) out vec2 fragUV; +layout(location = 3) out vec3 fragLightPos; + +void main() { + gl_Position = ubo.proj * constants.view * constants.model * vec4(inPosition, 1.0); + fragPos = vec3(constants.view * constants.model * vec4(inPosition, 1.0)); + fragNorm = mat3(transpose(inverse(constants.view * constants.model))) * inNorm; + fragUV = inUV; + vec3 lightPos = vec3(-500.0, 500.0, 40.0); + fragLightPos = vec3(constants.view * vec4(lightPos, 1.0)); +} diff --git a/src/application.cpp b/src/application.cpp index 37a25ac..5b1c865 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -56,7 +56,7 @@ namespace engine { m_window = std::make_unique(appName, true, false); m_gfx = std::make_unique(appName, appVersion, m_window->getHandle()); m_inputManager = std::make_unique(window()); - m_sceneManager = std::make_unique(); + m_sceneManager = std::make_unique(this); // get base path for resources m_resourcesPath = getResourcesPath(); @@ -79,6 +79,10 @@ namespace engine { /* logic */ m_sceneManager->updateActiveScene(m_window->dt()); + if(m_window->getKeyPress(inputs::Key::K_L)) { + m_enableFrameLimiter = !m_enableFrameLimiter; + } + /* draw */ m_gfx->renderFrame(); @@ -86,7 +90,9 @@ namespace engine { m_window->getInputAndEvents(); /* fps limiter */ - std::this_thread::sleep_until(endFrame); + if (m_enableFrameLimiter) { + std::this_thread::sleep_until(endFrame); + } beginFrame = endFrame; endFrame = beginFrame + FRAMETIME_LIMIT; diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 489fdba..04293db 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -182,7 +182,7 @@ namespace engine { options.SetSourceLanguage(shaderc_source_language_glsl); options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); - options.SetOptimizationLevel(shaderc_optimization_level_zero); + options.SetOptimizationLevel(shaderc_optimization_level_performance); options.SetTargetSpirv(shaderc_spirv_version_1_6); options.SetAutoBindUniforms(false); @@ -199,7 +199,6 @@ namespace engine { // compile shaderc::SpvCompilationResult compiledShader = compiler.CompileGlslToSpv(shaderStr.c_str(), kind, filename, options); - if (compiledShader.GetCompilationStatus() != shaderc_compilation_status_success) { throw std::runtime_error("COMPILE ERR " + compiledShader.GetErrorMessage()); @@ -568,6 +567,8 @@ namespace engine { swapchain->surfaceFormat = format; // prefer using srgb non linear colors } } + INFO("surface format: {}", swapchain->surfaceFormat.format); + INFO("surface colorspace: {}", swapchain->surfaceFormat.colorSpace); swapchain->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available if (vsync == false) { diff --git a/src/resources/material.cpp b/src/resources/material.cpp new file mode 100644 index 0000000..6e8c0b6 --- /dev/null +++ b/src/resources/material.cpp @@ -0,0 +1,18 @@ +#include "resources/material.hpp" + +#include "resources/shader.hpp" + +namespace engine::resources { + + Material::Material(std::shared_ptr shader) + : m_shader(shader) + { + + } + + Material::~Material() + { + + } + +} diff --git a/src/scene.cpp b/src/scene.cpp index eb58c17..9f53be4 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -1,10 +1,13 @@ #include "scene.hpp" +#include "ecs/mesh_renderer.hpp" + namespace engine { - Scene::Scene() + Scene::Scene(Application* app) + : m_app(app) { - m_renderSystem = std::make_unique(); + m_renderSystem = std::make_unique(this); } Scene::~Scene() {} diff --git a/src/scene_manager.cpp b/src/scene_manager.cpp index 49055ba..0449809 100644 --- a/src/scene_manager.cpp +++ b/src/scene_manager.cpp @@ -7,15 +7,17 @@ namespace engine { - SceneManager::SceneManager() + SceneManager::SceneManager(Application* app) + : m_app(app) { m_textureManager = std::make_unique>(); } SceneManager::~SceneManager() {} - Scene* SceneManager::createScene(std::unique_ptr&& scene) + Scene* SceneManager::createScene() { + auto scene = std::make_unique(m_app); m_scenes.emplace_back(std::move(scene)); m_activeSceneIndex = m_scenes.size() - 1; return m_scenes.back().get(); diff --git a/test/src/game.cpp b/test/src/game.cpp index 421fd75..d0da0c4 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -4,6 +4,10 @@ #include "window.hpp" #include "scene_manager.hpp" #include "scene.hpp" +#include "resources/material.hpp" +#include "resources/shader.hpp" +#include "resources/texture.hpp" +#include "resources/mesh.hpp" #include "ecs/mesh_renderer.hpp" void playGame() @@ -13,22 +17,40 @@ void playGame() // configure window app.window()->setRelativeMouseMode(false); - auto myScene = std::make_unique(); + auto myScene = app.sceneManager()->createScene(); - auto entity1 = myScene->createEntity(); - - auto myTexture = std::make_unique(app.gfx(), app.getResourcePath("textures/grass.jpg")); - - app.sceneManager()->getTextureManager()->add("GRASS", std::move(myTexture)); - myScene->m_renderSystem->m_components.emplace( - entity1, - engine::ecs::MeshRendererComponent{ - .number = 69, - .texture = app.sceneManager()->getTextureManager()->get("GRASS"), - } - ); - - app.sceneManager()->createScene(std::move(myScene)); + { + auto entity1 = myScene->createEntity(); + engine::gfx::VertexFormat vertFormat{}; + vertFormat.stride = sizeof(float) * 8; + vertFormat.attributeDescriptions.emplace_back(0, engine::gfx::VertexAttribFormat::VEC3, 0); + vertFormat.attributeDescriptions.emplace_back(1, engine::gfx::VertexAttribFormat::VEC3, sizeof(float) * 3); + vertFormat.attributeDescriptions.emplace_back(2, engine::gfx::VertexAttribFormat::VEC2, sizeof(float) * 6); + auto myShader = std::make_unique( + app.gfx(), + app.getResourcePath("engine/shaders/basic.vert").c_str(), + app.getResourcePath("engine/shaders/basic.frag").c_str(), + vertFormat, + false, + false + ); + glm::mat4 uniformBuffer{1.0f}; + app.gfx()->updateUniformBuffer(myShader->getPipeline(), &uniformBuffer, sizeof(glm::mat4), 0); + auto myMaterial = std::make_unique(std::move(myShader)); + std::vector triVertices{ + { { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, + { { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, + { { 0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } }, + }; + auto myMesh = std::make_unique(app.gfx(), triVertices); + myScene->m_renderSystem->m_components.emplace( + entity1, + engine::ecs::MeshRendererComponent{ + std::move(myMaterial), + std::move(myMesh), + } + ); + } app.gameLoop(); }