Add mesh renderer

This commit is contained in:
Bailey Harrison 2022-12-20 23:51:04 +00:00
parent 2f880981ac
commit c493ba559b
18 changed files with 337 additions and 38 deletions

View File

@ -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"

View File

@ -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;
};
}

View File

@ -5,10 +5,23 @@
namespace engine {
class Scene;
template <class T>
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<uint32_t, T> m_components{};
virtual void onUpdate(float ts) = 0;

View File

@ -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 <glm/mat4x4.hpp>
namespace engine::ecs {
struct MeshRendererComponent {
int number;
const resources::Texture* texture;
std::shared_ptr<resources::Material> material;
std::shared_ptr<resources::Mesh> mesh;
};
class RendererSystem : public EcsSystem<MeshRendererComponent> {
public:
RendererSystem(Scene* scene)
: EcsSystem<MeshRendererComponent>(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);
}
}
};

View File

@ -16,27 +16,31 @@ namespace engine {
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager&) = delete;
T* add(const std::string& name, std::unique_ptr<T>&& resource)
std::shared_ptr<T> add(const std::string& name, std::unique_ptr<T>&& resource)
{
if (m_resources.contains(name) == false) {
m_resources.emplace(name, std::move(resource));
std::shared_ptr<T> 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<T> get(const std::string& name)
{
if (m_resources.contains(name)) {
return m_resources.at(name).get();
std::weak_ptr<T> ptr = m_resources.at(name);
if (ptr.expired() == false) {
return ptr.lock();
}
}
return {};
}
private:
std::unordered_map<std::string, std::unique_ptr<T>> m_resources{};
std::unordered_map<std::string, std::weak_ptr<T>> m_resources{};
};

View File

@ -0,0 +1,24 @@
#pragma once
#include <memory>
namespace engine::resources {
class Shader;
class Material {
public:
Material(std::shared_ptr<Shader> shader);
~Material();
Material(const Material&) = delete;
Material& operator=(const Material&) = delete;
Shader* getShader() { return m_shader.get(); }
private:
const std::shared_ptr<Shader> m_shader;
};
}

View File

@ -0,0 +1,58 @@
#pragma once
#include "gfx.hpp"
#include "gfx_device.hpp"
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <string>
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<Vertex>& vertices)
: m_gfx(gfx)
{
m_count = vertices.size();
m_vb = m_gfx->createBuffer(gfx::BufferType::VERTEX, vertices.size() * sizeof(Vertex), vertices.data());
std::vector<uint32_t> 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;
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "gfx.hpp"
#include "gfx_device.hpp"
#include <glm/mat4x4.hpp>
#include <string>
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;
};
}

View File

@ -1,17 +1,21 @@
#pragma once
#include "ecs/mesh_renderer.hpp"
#include "log.hpp"
#include <cstdint>
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<ecs::RendererSystem> m_renderSystem;
Application* app() { return m_app; }
private:
Application* const m_app;
uint32_t m_nextEntityID = 1000;
};

View File

@ -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);
Scene* createScene();
void updateActiveScene(float ts);
@ -28,6 +29,8 @@ namespace engine {
ResourceManager<resources::Texture>* getTextureManager() { return m_textureManager.get(); }
private:
Application* const m_app;
std::vector<std::unique_ptr<Scene>> m_scenes;
int m_activeSceneIndex = -1;

View File

@ -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));
}

View File

@ -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));
}

View File

@ -56,7 +56,7 @@ namespace engine {
m_window = std::make_unique<Window>(appName, true, false);
m_gfx = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle());
m_inputManager = std::make_unique<InputManager>(window());
m_sceneManager = std::make_unique<SceneManager>();
m_sceneManager = std::make_unique<SceneManager>(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;

View File

@ -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) {

View File

@ -0,0 +1,18 @@
#include "resources/material.hpp"
#include "resources/shader.hpp"
namespace engine::resources {
Material::Material(std::shared_ptr<Shader> shader)
: m_shader(shader)
{
}
Material::~Material()
{
}
}

View File

@ -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<ecs::RendererSystem>();
m_renderSystem = std::make_unique<ecs::RendererSystem>(this);
}
Scene::~Scene() {}

View File

@ -7,15 +7,17 @@
namespace engine {
SceneManager::SceneManager()
SceneManager::SceneManager(Application* app)
: m_app(app)
{
m_textureManager = std::make_unique<ResourceManager<resources::Texture>>();
}
SceneManager::~SceneManager() {}
Scene* SceneManager::createScene(std::unique_ptr<Scene>&& scene)
Scene* SceneManager::createScene()
{
auto scene = std::make_unique<Scene>(m_app);
m_scenes.emplace_back(std::move(scene));
m_activeSceneIndex = m_scenes.size() - 1;
return m_scenes.back().get();

View File

@ -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<engine::Scene>();
auto myScene = app.sceneManager()->createScene();
auto entity1 = myScene->createEntity();
auto myTexture = std::make_unique<engine::resources::Texture>(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<engine::resources::Shader>(
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<engine::resources::Material>(std::move(myShader));
std::vector<engine::Vertex> 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<engine::resources::Mesh>(app.gfx(), triVertices);
myScene->m_renderSystem->m_components.emplace(
entity1,
engine::ecs::MeshRendererComponent{
std::move(myMaterial),
std::move(myMesh),
}
);
}
app.gameLoop();
}