diff --git a/include/application.h b/include/application.h index 583aa51..85de224 100644 --- a/include/application.h +++ b/include/application.h @@ -1,18 +1,14 @@ #ifndef ENGINE_INCLUDE_APPLICATION_H_ #define ENGINE_INCLUDE_APPLICATION_H_ -#include - #include #include #include #include -#include - #include "gfx.h" -#include "renderer.h" #include "input_manager.h" +#include "renderer.h" #include "resource_manager.h" #include "scene_manager.h" #include "window.h" diff --git a/include/components/collider.h b/include/components/collider.h index 77ae051..45d4caf 100644 --- a/include/components/collider.h +++ b/include/components/collider.h @@ -1,23 +1,18 @@ -#ifndef ENGINE_INCLUDE_COMPONENTS_COLLIDER_H_ -#define ENGINE_INCLUDE_COMPONENTS_COLLIDER_H_ +#pragma once #include -#include - namespace engine { struct AABB { - glm::vec3 pos1; - glm::vec3 pos2; + glm::vec3 pos1; + glm::vec3 pos2; }; struct ColliderComponent { - bool is_static; - bool is_trigger; // entity receives an event on collision enter and exit - AABB aabb; // broad phase + bool is_static; + bool is_trigger; // entity receives an event on collision enter and exit + AABB aabb; // broad phase }; -} // namespace engine - -#endif \ No newline at end of file +} // namespace engine \ No newline at end of file diff --git a/include/components/transform.h b/include/components/transform.h index 40bf7c9..99f4e64 100644 --- a/include/components/transform.h +++ b/include/components/transform.h @@ -12,13 +12,14 @@ namespace engine { struct TransformComponent { + std::string tag; + glm::mat4 world_matrix; glm::quat rotation; glm::vec3 position; glm::vec3 scale; - std::string tag; Entity parent; bool is_static; diff --git a/include/log.h b/include/log.h index 5af706c..07be495 100644 --- a/include/log.h +++ b/include/log.h @@ -2,7 +2,8 @@ #define ENGINE_INCLUDE_LOG_H_ #ifdef NDEBUG -#define SPDLOG_ACTIVE_LEVEL 2 // info +//#define SPDLOG_ACTIVE_LEVEL 2 // info +#define SPDLOG_ACTIVE_LEVEL 0 // trace #else #define SPDLOG_ACTIVE_LEVEL 0 // trace #endif diff --git a/include/resources/mesh.h b/include/resources/mesh.h index 449b717..7b9a8d3 100644 --- a/include/resources/mesh.h +++ b/include/resources/mesh.h @@ -16,6 +16,7 @@ struct Vertex { glm::vec3 norm; glm::vec4 tangent; // w component flips binormal if -1. w should be 1 or -1 glm::vec2 uv; + static constexpr int FloatsPerVertex() { return static_cast(sizeof(Vertex) / sizeof(float)); } }; } // namespace engine diff --git a/include/systems/transform.h b/include/systems/transform.h index da8ebf6..a0baf34 100644 --- a/include/systems/transform.h +++ b/include/systems/transform.h @@ -5,17 +5,20 @@ namespace engine { - class TransformSystem : public System { +class TransformSystem : public System { - public: - TransformSystem(Scene* scene); + public: + TransformSystem(Scene* scene); - void OnUpdate(float ts) override; + void OnUpdate(float ts) override; - Entity GetChildEntity(Entity parent, const std::string& tag); + /* + * Linear-searches for an entity that matches the arguments' criteria. + * Take care not to create multiple entities under a parent with the same tag, as this search will only find the first in the list. + */ + Entity GetChildEntity(Entity parent, const std::string& tag); +}; - }; - -} +} // namespace engine #endif \ No newline at end of file diff --git a/res/engine/shaders/fancy.vert b/res/engine/shaders/fancy.vert index 0453082..47125e7 100644 --- a/res/engine/shaders/fancy.vert +++ b/res/engine/shaders/fancy.vert @@ -34,7 +34,7 @@ void main() { fragUV = inUV; fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition); fragViewPosTangentSpace = worldToTangentSpace * vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); - fragLightPosTangentSpace = worldToTangentSpace * vec3(59.0, -20.0, 10.0); + fragLightPosTangentSpace = worldToTangentSpace * vec3(59000.0, 0000.0, 10000.0); gl_Position.y *= -1.0; } diff --git a/res/engine/shaders/showNormals.frag b/res/engine/shaders/showNormals.frag index 5e54b52..fb9dfad 100644 --- a/res/engine/shaders/showNormals.frag +++ b/res/engine/shaders/showNormals.frag @@ -1,11 +1,25 @@ #version 450 -layout(location = 0) in vec3 fragNorm; +layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; +layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; +layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; +layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler; + +layout(location = 0) in vec2 fragUV; +layout(location = 1) in vec3 fragPosTangentSpace; +layout(location = 2) in vec3 fragViewPosTangentSpace; +layout(location = 3) in vec3 fragLightPosTangentSpace; layout(location = 0) out vec4 outColor; void main() { - vec3 baseColor = fragNorm; - outColor = vec4(baseColor, 1.0); + + vec3 norm = vec3(texture(materialSetNormalSampler, fragUV)); + //norm.y = 1.0 - norm.y; + norm = normalize(norm * 2.0 - 1.0); + norm.b = 0.0; + norm *= 100.0; + norm = clamp(norm, 0.0, 1.0); + outColor = vec4(norm, 1.0); } diff --git a/res/engine/shaders/showNormals.vert b/res/engine/shaders/showNormals.vert index b468b5f..47125e7 100644 --- a/res/engine/shaders/showNormals.vert +++ b/res/engine/shaders/showNormals.vert @@ -1,23 +1,40 @@ #version 450 +layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer { + mat4 proj; +} globalSetUniformBuffer; + +layout(set = 1, binding = 0) uniform FrameSetUniformBuffer { + mat4 view; +} frameSetUniformBuffer; + layout( push_constant ) uniform Constants { mat4 model; - mat4 view; } constants; -layout(set = 0, binding = 0) uniform SetZeroBuffer { - mat4 proj; - vec2 myValue; -} setZeroBuffer; - layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNorm; layout(location = 2) in vec4 inTangent; layout(location = 3) in vec2 inUV; -layout(location = 0) out vec3 fragNorm; +layout(location = 0) out vec2 fragUV; +layout(location = 1) out vec3 fragPosTangentSpace; +layout(location = 2) out vec3 fragViewPosTangentSpace; +layout(location = 3) out vec3 fragLightPosTangentSpace; void main() { - gl_Position = setZeroBuffer.proj * constants.view * constants.model * vec4(inPosition, 1.0); - fragNorm = mat3(transpose(inverse(constants.model))) * inNorm; + vec4 worldPosition = constants.model * vec4(inPosition, 1.0); + gl_Position = globalSetUniformBuffer.proj * frameSetUniformBuffer.view * worldPosition; + + vec3 T = normalize(vec3(constants.model * vec4(inTangent.xyz, 0.0))); + vec3 N = normalize(vec3(constants.model * vec4(inNorm, 0.0))); + vec3 B = cross(T, N) * inTangent.w; + mat3 worldToTangentSpace = transpose(mat3(T, B, N)); + + fragUV = inUV; + fragPosTangentSpace = worldToTangentSpace * vec3(worldPosition); + fragViewPosTangentSpace = worldToTangentSpace * vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0)); + fragLightPosTangentSpace = worldToTangentSpace * vec3(59000.0, 0000.0, 10000.0); + + gl_Position.y *= -1.0; } diff --git a/res/engine/shaders/standard.vert b/res/engine/shaders/standard.vert index d986b62..d318cb3 100644 --- a/res/engine/shaders/standard.vert +++ b/res/engine/shaders/standard.vert @@ -29,7 +29,7 @@ void main() { fragNorm = mat3(transpose(inverse(frameSetUniformBuffer.view * constants.model))) * inNorm; fragUV = inUV; - vec3 lightPos = vec3(59.0, -20.0, 10.0); + vec3 lightPos = vec3(5900.0, -2000.0, 1000.0); fragLightPos = vec3(frameSetUniformBuffer.view * vec4(lightPos, 1.0)); gl_Position.y *= -1.0; diff --git a/src/application.cpp b/src/application.cpp index 6de29d4..a8b46d1 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -103,6 +103,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph } /* default shaders */ +#if 0 { Shader::VertexParams vertParams{}; vertParams.has_normal = true; @@ -118,6 +119,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings); GetResourceManager()->AddPersistent("builtin.standard", std::move(texturedShader)); } +#endif { Shader::VertexParams vertParams{}; vertParams.has_normal = true; @@ -129,10 +131,11 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph shaderSettings.cull_backface = true; shaderSettings.write_z = true; shaderSettings.render_order = 0; - auto fancyShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/fancy.vert").c_str(), - GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings); + auto fancyShader = std::make_unique(renderer(), GetResourcePath("engine/shaders/showNormals.vert").c_str(), + GetResourcePath("engine/shaders/showNormals.frag").c_str(), shaderSettings); GetResourceManager()->AddPersistent("builtin.fancy", std::move(fancyShader)); } +#if 0 { Shader::VertexParams vertParams{}; vertParams.has_normal = true; @@ -148,6 +151,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings); GetResourceManager()->AddPersistent("builtin.skybox", std::move(skyboxShader)); } +#endif #if 0 { Shader::VertexParams vertParams{}; diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 2dba3e2..271e64a 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -514,7 +514,7 @@ GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* wi descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptorPoolInfo.pNext = nullptr; descriptorPoolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - descriptorPoolInfo.maxSets = 1000u; + descriptorPoolInfo.maxSets = 10000u; descriptorPoolInfo.poolSizeCount = (uint32_t)poolSizes.size(); descriptorPoolInfo.pPoolSizes = poolSizes.data(); VKCHECK(vkCreateDescriptorPool(pimpl->device.device, &descriptorPoolInfo, nullptr, &pimpl->descriptorPool)); diff --git a/src/systems/transform.cpp b/src/systems/transform.cpp index 29e5ea5..9ea05e6 100644 --- a/src/systems/transform.cpp +++ b/src/systems/transform.cpp @@ -7,47 +7,47 @@ namespace engine { -TransformSystem::TransformSystem(Scene* scene) - : System(scene, {typeid(TransformComponent).hash_code()}) {} +TransformSystem::TransformSystem(Scene* scene) : System(scene, {typeid(TransformComponent).hash_code()}) {} -void TransformSystem::OnUpdate(float ts) { - (void)ts; +void TransformSystem::OnUpdate(float ts) +{ + (void)ts; - for (Entity entity : entities_) { - auto t = scene_->GetComponent(entity); + for (Entity entity : entities_) { + auto t = scene_->GetComponent(entity); - glm::mat4 transform; + glm::mat4 transform; - // rotation - transform = glm::mat4_cast(t->rotation); - // position - reinterpret_cast(transform[3]) = t->position; - // scale (effectively applied first) - transform = glm::scale(transform, t->scale); + // rotation + transform = glm::mat4_cast(t->rotation); + // position + reinterpret_cast(transform[3]) = t->position; + // scale (effectively applied first) + transform = glm::scale(transform, t->scale); - if (t->parent != 0) { - auto parent_t = scene_->GetComponent(t->parent); - transform = parent_t->world_matrix * transform; + if (t->parent != 0) { + auto parent_t = scene_->GetComponent(t->parent); + transform = parent_t->world_matrix * transform; - // (debug builds only) ensure static objects have static parents - assert(t->is_static == false || parent_t->is_static == true); + // (debug builds only) ensure static objects have static parents + assert(t->is_static == false || parent_t->is_static == true); + } + + t->world_matrix = transform; } - - t->world_matrix = transform; - } } -Entity TransformSystem::GetChildEntity(Entity parent, - const std::string& tag) { - for (Entity entity : entities_) { - auto t = scene_->GetComponent(entity); - if (t->parent == parent) { - if (t->tag == tag) { - return entity; - } +Entity TransformSystem::GetChildEntity(Entity parent, const std::string& tag) +{ + for (Entity entity : entities_) { + auto t = scene_->GetComponent(entity); + if (t->parent == parent) { + if (t->tag == tag) { + return entity; + } + } } - } - return 0; + return 0; } -} // namespace engine +} // namespace engine diff --git a/src/util/gltf_loader.cpp b/src/util/gltf_loader.cpp index 59a1be6..327ab3b 100644 --- a/src/util/gltf_loader.cpp +++ b/src/util/gltf_loader.cpp @@ -24,13 +24,10 @@ struct Color { }; namespace std { - template <> - struct std::hash { - std::size_t operator()(const Color& k) const - { - return k.r << 24 | k.g << 16 | k.b << 8 | k.a; - } - }; +template <> +struct std::hash { + std::size_t operator()(const Color& k) const { return k.r << 24 | k.g << 16 | k.b << 8 | k.a; } +}; } // namespace std namespace tg = tinygltf; @@ -283,7 +280,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) if (primitive.attributes.contains("POSITION")) { const tg::Accessor& pos_accessor = model.accessors.at(primitive.attributes.at("POSITION")); - const size_t num_vertices = pos_accessor.count; + const size_t original_num_vertices = pos_accessor.count; bool generate_tangents = false; // generating tangents creates a new index list and therefore all attribute accessors must be reassigned @@ -373,6 +370,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) std::vector vertices; if (generate_tangents) { + LOG_DEBUG("Generating tangents... vtx count before: {} idx count before: {}", original_num_vertices, num_indices); // generate tangents if they're not in the file struct MeshData { Attribute* positions; @@ -396,7 +394,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) mts_interface.m_getNumFaces = [](const SMikkTSpaceContext* pContext) -> int { const MeshData* meshData = static_cast(pContext->m_pUserData); assert(meshData->num_indices % 3 == 0); - return meshData->num_indices / 3; + return static_cast(meshData->num_indices / 3); }; mts_interface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext*, const int) -> int { return 3; }; mts_interface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) -> void { @@ -452,19 +450,36 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic) bool tan_result = genTangSpaceDefault(&mts_context); if (tan_result == false) throw std::runtime_error("Failed to generate tangents!"); - // regenerate indices as simple ones - indices.clear(); - indices.reserve(meshData.new_vertices->size()); - // temp generate simple indices - for (uint32_t i = 0; i < meshData.new_vertices->size(); ++i) { - indices.push_back(i); + // vertices now contains new vertices (possibly with duplicates) + // use weldmesh to generate new index list without duplicates + + std::vector remap_table(num_indices); // initialised to zeros + std::vector vertex_data_out(num_indices); // initialised to zeros + + const int num_unq_vertices = WeldMesh(remap_table.data(), reinterpret_cast(vertex_data_out.data()), + reinterpret_cast(vertices.data()), static_cast(num_indices), Vertex::FloatsPerVertex()); + assert(num_unq_vertices >= 0); + + // get new vertices into the vector + vertices.resize(num_unq_vertices); + for (size_t i = 0; i < num_unq_vertices; ++i) { + vertices[i] = vertex_data_out[i]; } + + // get new indices into the vector + indices.resize(num_indices); // redundant, for clarity + for (size_t i = 0; i < num_indices; ++i) { + assert(remap_table[i] >= 0); + indices[i] = static_cast(remap_table[i]); + } + + LOG_DEBUG("vtx count after: {} idx count after: {}", vertices.size(), indices.size()); } else { // combine vertices into one array vertices.clear(); - vertices.reserve(num_vertices); - for (size_t i = 0; i < num_vertices; ++i) { + vertices.reserve(original_num_vertices); + for (size_t i = 0; i < original_num_vertices; ++i) { Vertex v{.pos = positions[i], .norm = normals[i], .tangent = tangents[i], .uv = uv0s[i]}; vertices.push_back(v); } diff --git a/test/res/models/bikepcb.glb b/test/res/models/bikepcb.glb new file mode 100644 index 0000000..9900a80 Binary files /dev/null and b/test/res/models/bikepcb.glb differ diff --git a/test/res/models/normalmaptest.glb b/test/res/models/normalmaptest.glb new file mode 100644 index 0000000..c598047 Binary files /dev/null and b/test/res/models/normalmaptest.glb differ diff --git a/test/res/models/normalmaptest_notang.glb b/test/res/models/normalmaptest_notang.glb new file mode 100644 index 0000000..afa7661 Binary files /dev/null and b/test/res/models/normalmaptest_notang.glb differ diff --git a/test/res/models/redcube.glb b/test/res/models/redcube.glb index 4b7520f..239d192 100644 Binary files a/test/res/models/redcube.glb and b/test/res/models/redcube.glb differ diff --git a/test/src/game.cpp b/test/src/game.cpp index f5983d6..a6ee3de 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -169,49 +169,46 @@ void PlayGame(GameSettings settings) { /* axes */ - // engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true); + auto axes = engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true); + scene2->GetComponent(axes)->position += glm::vec3{ 20.0f, 20.0f, 0.0f }; } { /* floor */ - - engine::Entity pivot = scene2->CreateEntity("pivot", 0, glm::vec3{0.0f, 0.0f, 0.0f}); - - engine::Entity wall2 = scene2->CreateEntity("floor", pivot, glm::vec3{-50.0f, -50.0f, 0.0f}); - auto wall_renderable = scene2->AddComponent(wall2); - wall_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 100.0f); - wall_renderable->material = std::make_unique(app.renderer(), app.GetResource("builtin.fancy")); - + engine::Entity floor = scene2->CreateEntity("floor", 0, glm::vec3{-50.0f, -50.0f, 0.0f}); + auto floor_renderable = scene2->AddComponent(floor); + floor_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 100.0f); + floor_renderable->material = std::make_unique(app.renderer(), app.GetResource("builtin.fancy")); std::shared_ptr albedo_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/brickwall_albedo.jpg"), engine::gfx::SamplerInfo{}, app.renderer()); std::shared_ptr normal_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/brickwall_normal.jpg"), engine::gfx::SamplerInfo{}, app.renderer(), false); - - wall_renderable->material->SetAlbedoTexture(albedo_texture); - wall_renderable->material->SetNormalTexture(normal_texture); + floor_renderable->material->SetAlbedoTexture(albedo_texture); + floor_renderable->material->SetNormalTexture(normal_texture); } - { /* light */ - engine::Entity light = scene2->CreateEntity("light", 0, glm::vec3{59.0f, -20.0f, 10.0f}); - auto wall_renderable = scene2->AddComponent(light); - wall_renderable->mesh = GenSphereMesh(app.renderer()->GetDevice(), 0.5f, 16, false, true); - wall_renderable->material = std::make_unique(app.renderer(), app.GetResource("builtin.standard")); - wall_renderable->material->SetAlbedoTexture(app.GetResource("builtin.white")); + { /* teapots */ + auto teapot = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot_with_tangents.glb")); + scene2->GetComponent(teapot)->scale *= 10.0f; + auto teapot2 = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot.glb")); + scene2->GetComponent(teapot2)->scale *= 10.0f; + scene2->GetComponent(teapot2)->position.y += 5.0f; + auto custom = scene2->AddComponent(teapot2); + custom->onInit = [](void) { return; }; + custom->onUpdate = [&](float dt) { + dt = 0.0f; + scene2->GetComponent(teapot2)->rotation *= glm::angleAxis(dt, glm::vec3{ 0.0f, 1.0f, 0.0f }); + scene2->GetComponent(teapot)->rotation *= glm::angleAxis(dt, glm::vec3{ 0.0f, 1.0f, 0.0f }); + }; } - //auto teapot = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot_with_tangents.glb")); - //scene2->GetComponent(teapot)->scale *= 10.0f; - auto teapot2 = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot.glb")); - scene2->GetComponent(teapot2)->scale *= 10.0f; - scene2->GetComponent(teapot2)->position.y += 5.0f; - auto custom = scene2->AddComponent(teapot2); - custom->onInit = [](void) { return; }; - custom->onUpdate = [&](float dt) { - scene2->GetComponent(teapot2)->rotation *= glm::angleAxis(dt, glm::vec3{0.0f, 1.0f, 0.0f}); - }; - // scene2->GetComponent(teapot2)->rotation = glm::angleAxis(glm::pi(), glm::vec3{ 0.0f, 0.0f, 1.0f }); - // scene2->GetComponent(teapot2)->rotation *= glm::angleAxis(glm::half_pi(), glm::vec3{1.0f, 0.0f, 0.0f}); - // auto walls = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/walls_with_tangents.glb")); - auto redcube = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/redcube.glb")); + { + auto redcube = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/redcube.glb")); + } + + auto normalmaptest = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/normalmaptest.glb")); + scene2->GetComponent(normalmaptest)->position += glm::vec3{ -10.0f, 0.0f, 1.0f }; + auto normalmaptest_notang = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/normalmaptest_notang.glb")); + scene2->GetComponent(normalmaptest_notang)->position += glm::vec3{ -10.0f, 10.0f, 1.0f }; } my_scene->GetSystem()->next_scene_ = scene2;