From 0a199eb0d4bcbc8c2b3bed0f992827e1b10fb11e Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Wed, 30 Jun 2021 02:18:09 +0200 Subject: [PATCH] [#56] Added rendering for basic scenes Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- include/vkcv/Image.hpp | 4 +- .../material/src/vkcv/material/Material.cpp | 30 +- modules/scene/CMakeLists.txt | 3 + modules/scene/include/vkcv/scene/Bounds.hpp | 2 +- modules/scene/include/vkcv/scene/Mesh.hpp | 55 +--- modules/scene/include/vkcv/scene/MeshPart.hpp | 51 ++++ modules/scene/include/vkcv/scene/Node.hpp | 14 +- modules/scene/include/vkcv/scene/Scene.hpp | 22 +- modules/scene/src/vkcv/scene/Bounds.cpp | 4 + modules/scene/src/vkcv/scene/Mesh.cpp | 211 ++++---------- modules/scene/src/vkcv/scene/MeshPart.cpp | 271 ++++++++++++++++++ modules/scene/src/vkcv/scene/Node.cpp | 50 +++- modules/scene/src/vkcv/scene/Scene.cpp | 81 +++++- projects/first_scene/CMakeLists.txt | 4 +- projects/first_scene/src/main.cpp | 154 +--------- src/vkcv/Handles.cpp | 8 +- src/vkcv/Image.cpp | 2 +- 17 files changed, 605 insertions(+), 361 deletions(-) create mode 100644 modules/scene/include/vkcv/scene/MeshPart.hpp create mode 100644 modules/scene/src/vkcv/scene/MeshPart.cpp diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 33f0047c..4db642f4 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -31,7 +31,7 @@ namespace vkcv { uint32_t getDepth() const; [[nodiscard]] - vkcv::ImageHandle getHandle() const; + const vkcv::ImageHandle& getHandle() const; [[nodiscard]] uint32_t getMipCount() const; @@ -45,7 +45,7 @@ namespace vkcv { // TODO: const qualifier removed, very hacky!!! // Else you cannot recreate an image. Pls fix. ImageManager* m_manager; - ImageHandle m_handle; + ImageHandle m_handle; Image(ImageManager* manager, const ImageHandle& handle); diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp index d16555ad..aaf2e130 100644 --- a/modules/material/src/vkcv/material/Material.cpp +++ b/modules/material/src/vkcv/material/Material.cpp @@ -45,6 +45,16 @@ namespace vkcv::material { } } + static void fillImage(Image& image, float data [4]) { + std::vector<float> vec (image.getWidth() * image.getHeight() * image.getDepth() * 4); + + for (size_t i = 0; i < vec.size(); i++) { + vec[i] = data[i % 4]; + } + + image.fill(data); + } + Material Material::createPBR(Core &core, const ImageHandle &colorImg, const SamplerHandle &colorSmp, const ImageHandle &normalImg, const SamplerHandle &normalSmp, @@ -66,37 +76,37 @@ namespace vkcv::material { }; if (!colorImg) { - vkcv::Image defaultColor = core.createImage(vk::Format::eR8G8B8A8Srgb, 1, 1); + vkcv::Image defaultColor = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); float colorData [4] = { 228, 51, 255, 1 }; - defaultColor.fill(&colorData); + fillImage(defaultColor, colorData); images[0] = defaultColor.getHandle(); } if (!normalImg) { - vkcv::Image defaultNormal = core.createImage(vk::Format::eR8G8B8A8Srgb, 1, 1); + vkcv::Image defaultNormal = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); float normalData [4] = { 0, 0, 1, 0 }; - defaultNormal.fill(&normalData); + fillImage(defaultNormal, normalData); images[1] = defaultNormal.getHandle(); } if (!metRoughImg) { - vkcv::Image defaultRough = core.createImage(vk::Format::eR8G8B8A8Srgb, 1, 1); + vkcv::Image defaultRough = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); float roughData [4] = { 228, 51, 255, 1 }; - defaultRough.fill(&roughData); + fillImage(defaultRough, roughData); images[2] = defaultRough.getHandle(); } if (!occlusionImg) { - vkcv::Image defaultOcclusion = core.createImage(vk::Format::eR8G8B8A8Srgb, 1, 1); + vkcv::Image defaultOcclusion = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); float occlusionData [4] = { 228, 51, 255, 1 }; - defaultOcclusion.fill(&occlusionData); + fillImage(defaultOcclusion, occlusionData); images[3] = defaultOcclusion.getHandle(); } if (!emissiveImg) { - vkcv::Image defaultEmissive = core.createImage(vk::Format::eR8G8B8A8Srgb, 1, 1); + vkcv::Image defaultEmissive = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); float emissiveData [4] = { 0, 0, 0, 1 }; - defaultEmissive.fill(&emissiveData); + fillImage(defaultEmissive, emissiveData); images[4] = defaultEmissive.getHandle(); } diff --git a/modules/scene/CMakeLists.txt b/modules/scene/CMakeLists.txt index 8e742d92..cd2aff71 100644 --- a/modules/scene/CMakeLists.txt +++ b/modules/scene/CMakeLists.txt @@ -13,6 +13,9 @@ set(vkcv_scene_sources ${vkcv_scene_include}/vkcv/scene/Bounds.hpp ${vkcv_scene_source}/vkcv/scene/Bounds.cpp + ${vkcv_scene_include}/vkcv/scene/MeshPart.hpp + ${vkcv_scene_source}/vkcv/scene/MeshPart.cpp + ${vkcv_scene_include}/vkcv/scene/Mesh.hpp ${vkcv_scene_source}/vkcv/scene/Mesh.cpp diff --git a/modules/scene/include/vkcv/scene/Bounds.hpp b/modules/scene/include/vkcv/scene/Bounds.hpp index 474eb4f5..43694aa8 100644 --- a/modules/scene/include/vkcv/scene/Bounds.hpp +++ b/modules/scene/include/vkcv/scene/Bounds.hpp @@ -11,7 +11,7 @@ namespace vkcv::scene { public: Bounds(); - ~Bounds(); + ~Bounds() = default; Bounds(const Bounds& other) = default; Bounds(Bounds&& other) = default; diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp index 94c505a0..7416001e 100644 --- a/modules/scene/include/vkcv/scene/Mesh.hpp +++ b/modules/scene/include/vkcv/scene/Mesh.hpp @@ -1,48 +1,13 @@ #pragma once -#include <memory> -#include <vector> +#include <glm/mat4x4.hpp> -#include <vkcv/Buffer.hpp> -#include <vkcv/material/Material.hpp> -#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/camera/Camera.hpp> -#include "Bounds.hpp" +#include "MeshPart.hpp" namespace vkcv::scene { - class Scene; - class Mesh; - - class MeshPart { - friend class Mesh; - - private: - Scene* m_scene; - BufferHandle m_vertices; - BufferHandle m_indices; - Bounds m_bounds; - size_t m_materialIndex; - - explicit MeshPart(Scene* scene); - - void load(const asset::Scene& scene, - const asset::VertexGroup& vertexGroup); - - public: - ~MeshPart(); - - MeshPart(const MeshPart& other) = default; - MeshPart(MeshPart&& other) = default; - - MeshPart& operator=(const MeshPart& other) = default; - MeshPart& operator=(MeshPart&& other) = default; - - [[nodiscard]] - const material::Material& getMaterial() const; - - }; - class Node; class Mesh { @@ -51,20 +16,24 @@ namespace vkcv::scene { private: Scene* m_scene; std::vector<MeshPart> m_parts; + std::vector<DrawcallInfo> m_drawcalls; + glm::mat4 m_transform; explicit Mesh(Scene* scene); void load(const asset::Scene& scene, const asset::Mesh& mesh); + + void recordDrawcalls(std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls); public: - ~Mesh() = default; + ~Mesh(); - Mesh(const Mesh& other) = default; - Mesh(Mesh&& other) = default; + Mesh(const Mesh& other); + Mesh(Mesh&& other) noexcept; - Mesh& operator=(const Mesh& other) = default; - Mesh& operator=(Mesh&& other) = default; + Mesh& operator=(const Mesh& other); + Mesh& operator=(Mesh&& other) noexcept; }; diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp new file mode 100644 index 00000000..70ff7efc --- /dev/null +++ b/modules/scene/include/vkcv/scene/MeshPart.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include <vector> + +#include <vkcv/Buffer.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/material/Material.hpp> + +#include "Bounds.hpp" + +namespace vkcv::scene { + + class Scene; + class Mesh; + + class MeshPart { + friend class Mesh; + + private: + Scene* m_scene; + BufferHandle m_vertices; + std::vector<VertexBufferBinding> m_vertexBindings; + BufferHandle m_indices; + size_t m_indexCount; + Bounds m_bounds; + size_t m_materialIndex; + + explicit MeshPart(Scene* scene); + + void load(const asset::Scene& scene, + const asset::VertexGroup& vertexGroup, + std::vector<DrawcallInfo>& drawcalls); + + public: + ~MeshPart(); + + MeshPart(const MeshPart& other); + MeshPart(MeshPart&& other) noexcept; + + MeshPart& operator=(const MeshPart& other); + MeshPart& operator=(MeshPart&& other) noexcept; + + [[nodiscard]] + const material::Material& getMaterial() const; + + explicit operator bool() const; + bool operator!() const; + + }; + +} diff --git a/modules/scene/include/vkcv/scene/Node.hpp b/modules/scene/include/vkcv/scene/Node.hpp index c5d24fc1..3aa0caeb 100644 --- a/modules/scene/include/vkcv/scene/Node.hpp +++ b/modules/scene/include/vkcv/scene/Node.hpp @@ -2,6 +2,8 @@ #include <vector> +#include <vkcv/camera/Camera.hpp> + #include "Mesh.hpp" namespace vkcv::scene { @@ -20,15 +22,17 @@ namespace vkcv::scene { explicit Node(Scene* scene); void loadMesh(const asset::Scene& asset_scene, const asset::Mesh& asset_mesh); + + void recordDrawcalls(std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls); public: - ~Node() = default; + ~Node(); - Node(const Node& other) = default; - Node(Node&& other) = default; + Node(const Node& other); + Node(Node&& other) noexcept; - Node& operator=(const Node& other) = default; - Node& operator=(Node&& other) = default; + Node& operator=(const Node& other); + Node& operator=(Node&& other) noexcept; Node& addNode(); diff --git a/modules/scene/include/vkcv/scene/Scene.hpp b/modules/scene/include/vkcv/scene/Scene.hpp index c41fada0..6320d3db 100644 --- a/modules/scene/include/vkcv/scene/Scene.hpp +++ b/modules/scene/include/vkcv/scene/Scene.hpp @@ -3,6 +3,7 @@ #include <filesystem> #include <vkcv/Core.hpp> +#include <vkcv/camera/Camera.hpp> #include <vkcv/material/Material.hpp> #include "Node.hpp" @@ -26,16 +27,27 @@ namespace vkcv::scene { explicit Scene(Core* core); public: - ~Scene() = default; + ~Scene(); - Scene(const Scene& other) = default; - Scene(Scene&& other) = default; + Scene(const Scene& other); + Scene(Scene&& other) noexcept; - Scene& operator=(const Scene& other) = default; - Scene& operator=(Scene&& other) = default; + Scene& operator=(const Scene& other); + Scene& operator=(Scene&& other) noexcept; Node& addNode(); + size_t getMaterialCount() const; + + [[nodiscard]] + const material::Material& getMaterial(size_t index) const; + + void recordDrawcalls(CommandStreamHandle &cmdStream, + const camera::Camera &camera, + const PassHandle &pass, + const PipelineHandle &pipeline, + const std::vector<ImageHandle> &renderTargets); + static Scene create(Core& core); static Scene load(Core& core, const std::filesystem::path &path); diff --git a/modules/scene/src/vkcv/scene/Bounds.cpp b/modules/scene/src/vkcv/scene/Bounds.cpp index a25a825c..39d8ae34 100644 --- a/modules/scene/src/vkcv/scene/Bounds.cpp +++ b/modules/scene/src/vkcv/scene/Bounds.cpp @@ -2,6 +2,10 @@ #include "vkcv/scene/Bounds.hpp" namespace vkcv::scene { + + Bounds::Bounds() : + m_min(glm::vec3(0)), + m_max(glm::vec3(0)) {} void Bounds::setMin(const glm::vec3 &min) { m_min = min; diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp index 3a2dd9c7..6668b8b5 100644 --- a/modules/scene/src/vkcv/scene/Mesh.cpp +++ b/modules/scene/src/vkcv/scene/Mesh.cpp @@ -4,174 +4,89 @@ namespace vkcv::scene { - MeshPart::MeshPart(Scene* scene) : + Mesh::Mesh(Scene* scene) : m_scene(scene) {} - void loadImage(Core& core, const asset::Scene& asset_scene, - const asset::Texture& asset_texture, - const vk::Format& format, - ImageHandle& image, SamplerHandle& sampler) { - asset::Sampler* asset_sampler = nullptr; - - if ((asset_texture.sampler >= 0) && (asset_texture.sampler < asset_scene.samplers.size())) { - //asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); // TODO - } - - Image img = core.createImage(format, asset_texture.w, asset_texture.h, 1, true); - img.fill(asset_texture.data.data()); - image = img.getHandle(); - - if (asset_sampler) { - //sampler = core.createSampler(asset_sampler) // TODO - } - } - - material::Material loadMaterial(Core& core, const asset::Scene& scene, - const asset::Material& material) { - ImageHandle diffuseImg; - SamplerHandle diffuseSmp; - - if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { - loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, - diffuseImg,diffuseSmp); - } - - ImageHandle normalImg; - SamplerHandle normalSmp; - - if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { - loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, - diffuseImg,diffuseSmp); - } - - ImageHandle metalRoughImg; - SamplerHandle metalRoughSmp; - - if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { - loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, - diffuseImg,diffuseSmp); - } - - ImageHandle occlusionImg; - SamplerHandle occlusionSmp; - - if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { - loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, - diffuseImg,diffuseSmp); - } + static glm::mat4 arrayTo4x4Matrix(const std::array<float,16>& array){ + glm::mat4 matrix; - ImageHandle emissionImg; - SamplerHandle emissionSmp; - - if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { - loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, - diffuseImg,diffuseSmp); + for (int i = 0; i < 4; i++){ + for (int j = 0; j < 4; j++){ + matrix[i][j] = array[j * 4 + i]; + } } - const float colorFactors [4] = { - material.baseColorFactor.r, - material.baseColorFactor.g, - material.baseColorFactor.b, - material.baseColorFactor.a - }; - - const float emissionFactors[4] = { - material.emissiveFactor.r, - material.emissiveFactor.g, - material.emissiveFactor.b - }; - - return material::Material::createPBR( - core, - diffuseImg, diffuseSmp, - normalImg, normalSmp, - metalRoughImg, metalRoughSmp, - occlusionImg, occlusionSmp, - emissionImg, emissionSmp, - colorFactors, - material.normalScale, - material.metallicFactor, - material.roughnessFactor, - material.occlusionStrength, - emissionFactors - ); + return matrix; } - void MeshPart::load(const asset::Scene& scene, - const asset::VertexGroup &vertexGroup) { - Core& core = *(m_scene->m_core); - - auto vertexBuffer = core.createBuffer<uint8_t>( - BufferType::VERTEX, vertexGroup.vertexBuffer.data.size() - ); - - vertexBuffer.fill(vertexGroup.vertexBuffer.data); - m_vertices = vertexBuffer.getHandle(); - - auto indexBuffer = core.createBuffer<uint8_t>( - BufferType::INDEX, vertexGroup.indexBuffer.data.size() - ); - - indexBuffer.fill(vertexGroup.indexBuffer.data); - m_indices = indexBuffer.getHandle(); - - m_bounds.setMin(glm::vec3( - vertexGroup.min.x, - vertexGroup.min.y, - vertexGroup.min.z - )); - - m_bounds.setMax(glm::vec3( - vertexGroup.max.x, - vertexGroup.max.y, - vertexGroup.max.z - )); + void Mesh::load(const asset::Scene &scene, const asset::Mesh &mesh) { + m_drawcalls.clear(); - if ((vertexGroup.materialIndex >= 0) && - (vertexGroup.materialIndex < scene.materials.size())) { - m_materialIndex = vertexGroup.materialIndex; + for (const auto& vertexGroupIndex : mesh.vertexGroups) { + if ((vertexGroupIndex < 0) || (vertexGroupIndex >= scene.vertexGroups.size())) { + continue; + } - auto& material = m_scene->m_materials[m_materialIndex]; + MeshPart part (m_scene); + part.load(scene, scene.vertexGroups[vertexGroupIndex], m_drawcalls); - if (0 == material.m_usages++) { - material.m_data = loadMaterial(core, scene, scene.materials[vertexGroup.materialIndex]); + if (!part) { + continue; } - } else { - m_materialIndex = std::numeric_limits<size_t>::max(); + + m_parts.push_back(part); } + + m_transform = arrayTo4x4Matrix(mesh.modelMatrix); } - MeshPart::~MeshPart() { - if (m_materialIndex < std::numeric_limits<size_t>::max()) { - auto& material = m_scene->m_materials[m_materialIndex]; - - if (material.m_usages > 0) { - material.m_usages--; - } - } + Mesh::~Mesh() { + m_drawcalls.clear(); + m_parts.clear(); } - const material::Material & MeshPart::getMaterial() const { - if (m_materialIndex < std::numeric_limits<size_t>::max()) { - return m_scene->m_materials[m_materialIndex].m_data; - } else { - static material::Material noMaterial; - return noMaterial; + Mesh::Mesh(const Mesh &other) : + m_scene(other.m_scene), + m_parts(other.m_parts), + m_drawcalls(other.m_drawcalls), + m_transform(other.m_transform) {} + + Mesh::Mesh(Mesh &&other) noexcept : + m_scene(other.m_scene), + m_parts(other.m_parts), + m_drawcalls(other.m_drawcalls), + m_transform(other.m_transform) {} + + Mesh &Mesh::operator=(const Mesh &other) { + if (&other == this) { + return *this; } + + m_scene = other.m_scene; + m_parts = std::vector<MeshPart>(other.m_parts); + m_drawcalls = std::vector<DrawcallInfo>(other.m_drawcalls); + m_transform = other.m_transform; + + return *this; } - Mesh::Mesh(Scene* scene) : - m_scene(scene) {} + Mesh &Mesh::operator=(Mesh &&other) noexcept { + m_scene = other.m_scene; + m_parts = std::move(other.m_parts); + m_drawcalls = std::move(other.m_drawcalls); + m_transform = other.m_transform; + + return *this; + } - void Mesh::load(const asset::Scene &scene, const asset::Mesh &mesh) { - for (const auto& vertexGroupIndex : mesh.vertexGroups) { - if ((vertexGroupIndex < 0) || (vertexGroupIndex >= scene.vertexGroups.size())) { - continue; - } - - MeshPart part (m_scene); - part.load(scene, scene.vertexGroups[vertexGroupIndex]); - m_parts.push_back(part); + void Mesh::recordDrawcalls(std::vector<glm::mat4>& matrices, + std::vector<DrawcallInfo>& drawcalls) { + for (const auto& part : m_parts) { + matrices.push_back(m_transform); + } + + for (const auto& drawcall : m_drawcalls) { + drawcalls.push_back(drawcall); } } diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp new file mode 100644 index 00000000..316cf673 --- /dev/null +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -0,0 +1,271 @@ + +#include "vkcv/scene/MeshPart.hpp" +#include "vkcv/scene/Scene.hpp" + +namespace vkcv::scene { + + MeshPart::MeshPart(Scene* scene) : + m_scene(scene), + m_vertices(), + m_vertexBindings(), + m_indices(), + m_indexCount(0), + m_bounds(), + m_materialIndex(std::numeric_limits<size_t>::max()) {} + + static void loadImage(Core& core, const asset::Scene& asset_scene, + const asset::Texture& asset_texture, + const vk::Format& format, + ImageHandle& image, SamplerHandle& sampler) { + asset::Sampler* asset_sampler = nullptr; + + if ((asset_texture.sampler >= 0) && (asset_texture.sampler < asset_scene.samplers.size())) { + //asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); // TODO + } + + Image img = core.createImage(format, asset_texture.w, asset_texture.h); + img.fill(asset_texture.data.data()); + image = img.getHandle(); + + if (asset_sampler) { + //sampler = core.createSampler(asset_sampler) // TODO + } else { + sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + } + } + + static material::Material loadMaterial(Core& core, const asset::Scene& scene, + const asset::Material& material) { + ImageHandle diffuseImg; + SamplerHandle diffuseSmp; + + if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { + loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, + diffuseImg,diffuseSmp); + } + + ImageHandle normalImg; + SamplerHandle normalSmp; + + if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { + loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, + diffuseImg,diffuseSmp); + } + + ImageHandle metalRoughImg; + SamplerHandle metalRoughSmp; + + if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { + loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, + diffuseImg,diffuseSmp); + } + + ImageHandle occlusionImg; + SamplerHandle occlusionSmp; + + if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { + loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, + diffuseImg,diffuseSmp); + } + + ImageHandle emissionImg; + SamplerHandle emissionSmp; + + if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) { + loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb, + diffuseImg,diffuseSmp); + } + + const float colorFactors [4] = { + material.baseColorFactor.r, + material.baseColorFactor.g, + material.baseColorFactor.b, + material.baseColorFactor.a + }; + + const float emissionFactors[4] = { + material.emissiveFactor.r, + material.emissiveFactor.g, + material.emissiveFactor.b + }; + + return material::Material::createPBR( + core, + diffuseImg, diffuseSmp, + normalImg, normalSmp, + metalRoughImg, metalRoughSmp, + occlusionImg, occlusionSmp, + emissionImg, emissionSmp, + colorFactors, + material.normalScale, + material.metallicFactor, + material.roughnessFactor, + material.occlusionStrength, + emissionFactors + ); + } + + void MeshPart::load(const asset::Scene& scene, + const asset::VertexGroup &vertexGroup, + std::vector<DrawcallInfo>& drawcalls) { + Core& core = *(m_scene->m_core); + + auto vertexBuffer = core.createBuffer<uint8_t>( + BufferType::VERTEX, vertexGroup.vertexBuffer.data.size() + ); + + vertexBuffer.fill(vertexGroup.vertexBuffer.data); + m_vertices = vertexBuffer.getHandle(); + + auto attributes = vertexGroup.vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + + for (const auto& attribute : attributes) { + m_vertexBindings.emplace_back(attribute.offset, vertexBuffer.getVulkanHandle()); + } + + auto indexBuffer = core.createBuffer<uint8_t>( + BufferType::INDEX, vertexGroup.indexBuffer.data.size() + ); + + indexBuffer.fill(vertexGroup.indexBuffer.data); + m_indices = indexBuffer.getHandle(); + m_indexCount = vertexGroup.numIndices; + + m_bounds.setMin(glm::vec3( + vertexGroup.min.x, + vertexGroup.min.y, + vertexGroup.min.z + )); + + m_bounds.setMax(glm::vec3( + vertexGroup.max.x, + vertexGroup.max.y, + vertexGroup.max.z + )); + + if ((vertexGroup.materialIndex >= 0) && + (vertexGroup.materialIndex < scene.materials.size())) { + m_materialIndex = vertexGroup.materialIndex; + + auto& material = m_scene->m_materials[m_materialIndex]; + + if (0 == material.m_usages++) { + material.m_data = loadMaterial(core, scene, scene.materials[vertexGroup.materialIndex]); + } + } else { + m_materialIndex = std::numeric_limits<size_t>::max(); + } + + if (*this) { + const auto& material = getMaterial(); + const auto& descriptorSet = core.getDescriptorSet(material.getDescriptorSet()); + + drawcalls.push_back(DrawcallInfo( + vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount), + { DescriptorSetUsage(0, descriptorSet.vulkanHandle) } + )); + } + } + + MeshPart::~MeshPart() { + if ((m_scene->m_core) && (m_materialIndex < m_scene->m_materials.size())) { + auto& material = m_scene->m_materials[m_materialIndex]; + + if (material.m_usages > 0) { + material.m_usages--; + } + } + } + + MeshPart::MeshPart(const MeshPart &other) : + m_scene(other.m_scene), + m_vertices(other.m_vertices), + m_vertexBindings(other.m_vertexBindings), + m_indices(other.m_indices), + m_indexCount(other.m_indexCount), + m_bounds(other.m_bounds), + m_materialIndex(other.m_materialIndex) { + if (m_materialIndex < std::numeric_limits<size_t>::max()) { + auto& material = m_scene->m_materials[m_materialIndex]; + + material.m_usages++; + } + } + + MeshPart::MeshPart(MeshPart &&other) noexcept : + m_scene(other.m_scene), + m_vertices(other.m_vertices), + m_vertexBindings(other.m_vertexBindings), + m_indices(other.m_indices), + m_indexCount(other.m_indexCount), + m_bounds(other.m_bounds), + m_materialIndex(other.m_materialIndex) { + other.m_materialIndex = std::numeric_limits<size_t>::max(); + } + + MeshPart &MeshPart::operator=(const MeshPart &other) { + if (&other == this) { + return *this; + } + + m_scene = other.m_scene; + m_vertices = other.m_vertices; + m_vertexBindings = other.m_vertexBindings; + m_indices = other.m_indices; + m_indexCount = other.m_indexCount; + m_bounds = other.m_bounds; + m_materialIndex = other.m_materialIndex; + + return *this; + } + + MeshPart &MeshPart::operator=(MeshPart &&other) noexcept { + m_scene = other.m_scene; + m_vertices = other.m_vertices; + m_vertexBindings = other.m_vertexBindings; + m_indices = other.m_indices; + m_indexCount = other.m_indexCount; + m_bounds = other.m_bounds; + m_materialIndex = other.m_materialIndex; + + other.m_materialIndex = std::numeric_limits<size_t>::max(); + + return *this; + } + + const material::Material & MeshPart::getMaterial() const { + static material::Material noMaterial; + + if (m_materialIndex < m_scene->m_materials.size()) { + return m_scene->m_materials[m_materialIndex].m_data; + } else { + return noMaterial; + } + } + + MeshPart::operator bool() const { + return ( + (m_materialIndex < m_scene->m_materials.size()) && + (m_vertices) && + (m_indices) + ); + } + + bool MeshPart::operator!() const { + return ( + (m_materialIndex >= m_scene->m_materials.size()) || + (!m_vertices) || + (!m_indices) + ); + } + +} diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp index c88c9141..a2f30bb9 100644 --- a/modules/scene/src/vkcv/scene/Node.cpp +++ b/modules/scene/src/vkcv/scene/Node.cpp @@ -4,7 +4,44 @@ namespace vkcv::scene { Node::Node(Scene* scene) : - m_scene(scene) {} + m_scene(scene), + m_meshes(), + m_nodes() {} + + Node::~Node() { + m_nodes.clear(); + m_meshes.clear(); + } + + Node::Node(const Node &other) : + m_scene(other.m_scene), + m_meshes(other.m_meshes), + m_nodes(other.m_nodes) {} + + Node::Node(Node &&other) noexcept : + m_scene(other.m_scene), + m_meshes(other.m_meshes), + m_nodes(other.m_nodes) {} + + Node &Node::operator=(const Node &other) { + if (&other == this) { + return *this; + } + + m_scene = other.m_scene; + m_meshes = std::vector<Mesh>(other.m_meshes); + m_nodes = std::vector<Node>(other.m_nodes); + + return *this; + } + + Node &Node::operator=(Node &&other) noexcept { + m_scene = other.m_scene; + m_meshes = std::move(other.m_meshes); + m_nodes = std::move(other.m_nodes); + + return *this; + } void Node::loadMesh(const asset::Scene &asset_scene, const asset::Mesh &asset_mesh) { Mesh mesh (m_scene); @@ -17,5 +54,16 @@ namespace vkcv::scene { m_nodes.push_back(node); return m_nodes.back(); } + + void Node::recordDrawcalls(std::vector<glm::mat4>& matrices, + std::vector<DrawcallInfo>& drawcalls) { + for (auto& mesh : m_meshes) { + mesh.recordDrawcalls(matrices, drawcalls); + } + + for (auto& node : m_nodes) { + node.recordDrawcalls(matrices, drawcalls); + } + } } diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index 8ee56ca7..c58125b7 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -7,7 +7,44 @@ namespace vkcv::scene { Scene::Scene(Core* core) : - m_core(core) {} + m_core(core), + m_nodes(), + m_materials() {} + + Scene::~Scene() { + m_nodes.clear(); + m_materials.clear(); + } + + Scene::Scene(const Scene &other) : + m_core(other.m_core), + m_materials(other.m_materials), + m_nodes(other.m_nodes) {} + + Scene::Scene(Scene &&other) noexcept : + m_core(other.m_core), + m_materials(other.m_materials), + m_nodes(other.m_nodes) {} + + Scene &Scene::operator=(const Scene &other) { + if (&other == this) { + return *this; + } + + m_core = other.m_core; + m_materials = std::vector<Material>(other.m_materials); + m_nodes = std::vector<Node>(other.m_nodes); + + return *this; + } + + Scene &Scene::operator=(Scene &&other) noexcept { + m_core = other.m_core; + m_materials = std::move(other.m_materials); + m_nodes = std::move(other.m_nodes); + + return *this; + } Node& Scene::addNode() { Node node (this); @@ -15,6 +52,48 @@ namespace vkcv::scene { return m_nodes.back(); } + size_t Scene::getMaterialCount() const { + return m_materials.size(); + } + + const material::Material & Scene::getMaterial(size_t index) const { + static material::Material noMaterial; + + if (index >= m_materials.size()) { + return noMaterial; + } + + return m_materials[index].m_data; + } + + void Scene::recordDrawcalls(CommandStreamHandle &cmdStream, + const camera::Camera &camera, + const PassHandle &pass, + const PipelineHandle &pipeline, + const std::vector<ImageHandle> &renderTargets) { + std::vector<glm::mat4> matrices; + std::vector<DrawcallInfo> drawcalls; + + for (auto& node : m_nodes) { + node.recordDrawcalls(matrices, drawcalls); + } + + for (auto& matrix : matrices) { + matrix = camera.getMVP() * matrix; + } + + PushConstantData pushConstantData (matrices.data(), sizeof(glm::mat4)); + + m_core->recordDrawcallsToCmdStream( + cmdStream, + pass, + pipeline, + pushConstantData, + drawcalls, + renderTargets + ); + } + Scene Scene::create(Core& core) { return Scene(&core); } diff --git a/projects/first_scene/CMakeLists.txt b/projects/first_scene/CMakeLists.txt index 8b907397..467663dc 100644 --- a/projects/first_scene/CMakeLists.txt +++ b/projects/first_scene/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) +target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) +target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene) diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 420400cd..919dc7dd 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -5,16 +5,9 @@ #include <chrono> #include <vkcv/asset/asset_loader.hpp> #include <vkcv/Logger.hpp> +#include <vkcv/scene/Scene.hpp> + -glm::mat4 arrayTo4x4Matrix(std::array<float,16> array){ - glm::mat4 matrix; - for (int i = 0; i < 4; i++){ - for (int j = 0; j < 4; j++){ - matrix[i][j] = array[j * 4 + i]; - } - } - return matrix; -} int main(int argc, const char** argv) { const char* applicationName = "First Scene"; @@ -46,66 +39,10 @@ int main(int argc, const char** argv) { {}, { "VK_KHR_swapchain" } ); - - vkcv::asset::Scene scene; - - const char* path = argc > 1 ? argv[1] : "resources/Sponza/Sponza.gltf"; - int result = vkcv::asset::loadScene(path, scene); - - if (result == 1) { - std::cout << "Mesh loading successful!" << std::endl; - } - else { - std::cout << "Mesh loading failed: " << result << std::endl; - return 1; - } - - assert(!scene.vertexGroups.empty()); - std::vector<std::vector<uint8_t>> vBuffers; - std::vector<std::vector<uint8_t>> iBuffers; - - std::vector<vkcv::VertexBufferBinding> vBufferBindings; - std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings; - std::vector<vkcv::asset::VertexAttribute> vAttributes; - - for (int i = 0; i < scene.vertexGroups.size(); i++) { - - vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data); - iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data); - - auto& attributes = scene.vertexGroups[i].vertexBuffer.attributes; - - std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { - return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); - }); - } - - std::vector<vkcv::Buffer<uint8_t>> vertexBuffers; - for (const vkcv::asset::VertexGroup& group : scene.vertexGroups) { - vertexBuffers.push_back(core.createBuffer<uint8_t>( - vkcv::BufferType::VERTEX, - group.vertexBuffer.data.size())); - vertexBuffers.back().fill(group.vertexBuffer.data); - } - - std::vector<vkcv::Buffer<uint8_t>> indexBuffers; - for (const auto& dataBuffer : iBuffers) { - indexBuffers.push_back(core.createBuffer<uint8_t>( - vkcv::BufferType::INDEX, - dataBuffer.size())); - indexBuffers.back().fill(dataBuffer); - } - - int vertexBufferIndex = 0; - for (const auto& vertexGroup : scene.vertexGroups) { - for (const auto& attribute : vertexGroup.vertexBuffer.attributes) { - vAttributes.push_back(attribute); - vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle())); - } - vertexBufferBindings.push_back(vBufferBindings); - vBufferBindings.clear(); - vertexBufferIndex++; - } + + vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( + argc > 1 ? argv[1] : "resources/Sponza/Sponza.gltf" + )); const vkcv::AttachmentDescription present_color_attachment( vkcv::AttachmentOperation::STORE, @@ -138,41 +75,8 @@ int main(int argc, const char** argv) { } const vkcv::VertexLayout sceneLayout(bindings); - - uint32_t setID = 0; - - std::vector<vkcv::DescriptorBinding> descriptorBindings = { sceneShaderProgram.getReflectedDescriptors()[setID] }; - - vkcv::SamplerHandle sampler = core.createSampler( - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::REPEAT - ); - - std::vector<vkcv::Image> sceneImages; - std::vector<vkcv::DescriptorSetHandle> descriptorSets; - for (const auto& vertexGroup : scene.vertexGroups) { - descriptorSets.push_back(core.createDescriptorSet(descriptorBindings)); - - const auto& material = scene.materials[vertexGroup.materialIndex]; - - int baseColorIndex = material.baseColor; - if (baseColorIndex < 0) { - vkcv_log(vkcv::LogLevel::WARNING, "Material lacks base color"); - baseColorIndex = 0; - } - - vkcv::asset::Texture& sceneTexture = scene.textures[baseColorIndex]; - - sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, sceneTexture.w, sceneTexture.h)); - sceneImages.back().fill(sceneTexture.data.data()); - - vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, sceneImages.back().getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; - core.writeDescriptorSet(descriptorSets.back(), setWrites); - } + + const auto& material0 = scene.getMaterial(0); const vkcv::PipelineConfig scenePipelineDefsinition{ sceneShaderProgram, @@ -180,7 +84,7 @@ int main(int argc, const char** argv) { UINT32_MAX, scenePass, {sceneLayout}, - { core.getDescriptorSet(descriptorSets[0]).layout }, + { core.getDescriptorSet(material0.getDescriptorSet()).layout }, true }; vkcv::PipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefsinition); @@ -193,25 +97,6 @@ int main(int argc, const char** argv) { const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); - std::vector<vkcv::DrawcallInfo> drawcalls; - for(int i = 0; i < scene.vertexGroups.size(); i++){ - vkcv::Mesh renderMesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices); - - vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSets[i]).vulkanHandle); - - drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage})); - } - - std::vector<glm::mat4> modelMatrices; - modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f)); - for (const auto &mesh : scene.meshes) { - const glm::mat4 m = arrayTo4x4Matrix(mesh.modelMatrix); - for (const auto &vertexGroupIndex : mesh.vertexGroups) { - modelMatrices[vertexGroupIndex] = m; - } - } - std::vector<glm::mat4> mvp; - auto start = std::chrono::system_clock::now(); while (window.isWindowOpen()) { vkcv::Window::pollEvents(); @@ -236,25 +121,16 @@ int main(int argc, const char** argv) { start = end; cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); - glm::mat4 vp = cameraManager.getActiveCamera().getMVP(); - - mvp.clear(); - for (const auto& m : modelMatrices) { - mvp.push_back(vp * m); - } - - vkcv::PushConstantData pushConstantData((void*)mvp.data(), sizeof(glm::mat4)); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - core.recordDrawcallsToCmdStream( - cmdStream, - scenePass, - scenePipeline, - pushConstantData, - drawcalls, - renderTargets); + scene.recordDrawcalls(cmdStream, + cameraManager.getActiveCamera(), + scenePass, + scenePipeline, + renderTargets); + core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); core.endFrame(); diff --git a/src/vkcv/Handles.cpp b/src/vkcv/Handles.cpp index 02048941..65fc02de 100644 --- a/src/vkcv/Handles.cpp +++ b/src/vkcv/Handles.cpp @@ -1,5 +1,7 @@ #include "vkcv/Handles.hpp" +#include <iostream> + namespace vkcv { Handle::Handle() : @@ -11,7 +13,7 @@ namespace vkcv { {} Handle::~Handle() { - if ((m_rc) && (--(*m_rc) == 0)) { + if ((m_rc) && (*m_rc > 0) && (--(*m_rc) == 0)) { if (m_destroy) { m_destroy(m_id); } @@ -82,9 +84,9 @@ namespace vkcv { std::ostream& operator << (std::ostream& out, const Handle& handle) { if (handle) { - return out << "[Handle: " << handle.getId() << ":" << handle.getRC() << "]"; + return out << "[" << typeid(handle).name() << ": " << handle.getId() << ":" << handle.getRC() << "]"; } else { - return out << "[Handle: none]"; + return out << "[" << typeid(handle).name() << ": none]"; } } diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index 4b43b129..e97e31b5 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -53,7 +53,7 @@ namespace vkcv{ m_manager->switchImageLayoutImmediate(m_handle, newLayout); } - vkcv::ImageHandle Image::getHandle() const { + const vkcv::ImageHandle& Image::getHandle() const { return m_handle; } -- GitLab