diff --git a/modules/scene/include/vkcv/scene/Bounds.hpp b/modules/scene/include/vkcv/scene/Bounds.hpp index 43694aa80fd6ef7d389961c181aa20c7cf3d237b..07cdf88828d786982b0fe8e7919d543557794c42 100644 --- a/modules/scene/include/vkcv/scene/Bounds.hpp +++ b/modules/scene/include/vkcv/scene/Bounds.hpp @@ -1,5 +1,7 @@ #pragma once +#include <array> +#include <iostream> #include <glm/vec3.hpp> namespace vkcv::scene { @@ -11,6 +13,7 @@ namespace vkcv::scene { public: Bounds(); + Bounds(const glm::vec3& min, const glm::vec3& max); ~Bounds() = default; Bounds(const Bounds& other) = default; @@ -21,20 +24,46 @@ namespace vkcv::scene { void setMin(const glm::vec3& min); + [[nodiscard]] const glm::vec3& getMin() const; void setMax(const glm::vec3& max); + [[nodiscard]] const glm::vec3& getMax() const; void setCenter(const glm::vec3& center); + [[nodiscard]] glm::vec3 getCenter() const; void setSize(const glm::vec3& size); + [[nodiscard]] glm::vec3 getSize() const; + + [[nodiscard]] + std::array<glm::vec3, 8> getCorners() const; + + void extend(const glm::vec3& point); + + [[nodiscard]] + bool contains(const glm::vec3& point) const; + + [[nodiscard]] + bool contains(const Bounds& other) const; + + [[nodiscard]] + bool intersects(const Bounds& other) const; + + [[nodiscard]] + explicit operator bool() const; + + [[nodiscard]] + bool operator!() const; }; + std::ostream& operator << (std::ostream& out, const Bounds& bounds); + } diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp index 7416001edc185f3217950b1ff2b26cc65850d958..96d719b66c5fa21b1441ea5c4ac9499956f204b0 100644 --- a/modules/scene/include/vkcv/scene/Mesh.hpp +++ b/modules/scene/include/vkcv/scene/Mesh.hpp @@ -24,7 +24,9 @@ namespace vkcv::scene { void load(const asset::Scene& scene, const asset::Mesh& mesh); - void recordDrawcalls(std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls); + void recordDrawcalls(const glm::mat4& viewProjection, + std::vector<glm::mat4>& matrices, + std::vector<DrawcallInfo>& drawcalls); public: ~Mesh(); diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp index 70ff7efcba4bf27a7d152c36782ccbe2953475d9..4b64d1d07e9cea7e29c6daf689c87b553e3fe562 100644 --- a/modules/scene/include/vkcv/scene/MeshPart.hpp +++ b/modules/scene/include/vkcv/scene/MeshPart.hpp @@ -43,6 +43,9 @@ namespace vkcv::scene { [[nodiscard]] const material::Material& getMaterial() const; + [[nodiscard]] + const Bounds& getBounds() 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 3aa0caebeb826f93a386a76562ab8bc451e193be..58cef8f3622a721bda66286dcfa7b7ac65bcbd13 100644 --- a/modules/scene/include/vkcv/scene/Node.hpp +++ b/modules/scene/include/vkcv/scene/Node.hpp @@ -23,7 +23,9 @@ namespace vkcv::scene { void loadMesh(const asset::Scene& asset_scene, const asset::Mesh& asset_mesh); - void recordDrawcalls(std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls); + void recordDrawcalls(const glm::mat4& viewProjection, + std::vector<glm::mat4>& matrices, + std::vector<DrawcallInfo>& drawcalls); public: ~Node(); diff --git a/modules/scene/src/vkcv/scene/Bounds.cpp b/modules/scene/src/vkcv/scene/Bounds.cpp index 39d8ae345abe891a3390b31e6cbcfc359b55b100..731d81e928deae4c27f5c857de5b94dc3180888b 100644 --- a/modules/scene/src/vkcv/scene/Bounds.cpp +++ b/modules/scene/src/vkcv/scene/Bounds.cpp @@ -6,6 +6,11 @@ namespace vkcv::scene { Bounds::Bounds() : m_min(glm::vec3(0)), m_max(glm::vec3(0)) {} + + Bounds::Bounds(const glm::vec3 &min, const glm::vec3 &max) : + m_min(min), + m_max(max) + {} void Bounds::setMin(const glm::vec3 &min) { m_min = min; @@ -42,5 +47,80 @@ namespace vkcv::scene { glm::vec3 Bounds::getSize() const { return (m_max - m_min); } - + + std::array<glm::vec3, 8> Bounds::getCorners() const { + return { + m_min, + glm::vec3(m_min[0], m_min[1], m_max[2]), + glm::vec3(m_min[0], m_max[1], m_min[2]), + glm::vec3(m_min[0], m_max[1], m_max[2]), + glm::vec3(m_max[0], m_min[1], m_min[2]), + glm::vec3(m_max[0], m_min[1], m_max[2]), + glm::vec3(m_max[0], m_max[1], m_min[2]), + m_max + }; + } + + void Bounds::extend(const glm::vec3 &point) { + m_min = glm::vec3( + std::min(m_min[0], point[0]), + std::min(m_min[1], point[1]), + std::min(m_min[2], point[2]) + ); + + m_max = glm::vec3( + std::max(m_max[0], point[0]), + std::max(m_max[1], point[1]), + std::max(m_max[2], point[2]) + ); + } + + bool Bounds::contains(const glm::vec3 &point) const { + return ( + (point[0] >= m_min[0]) && (point[0] <= m_max[0]) && + (point[1] >= m_min[1]) && (point[1] <= m_max[1]) && + (point[2] >= m_min[2]) && (point[2] <= m_max[2]) + ); + } + + bool Bounds::contains(const Bounds &other) const { + return ( + (other.m_min[0] >= m_min[0]) && (other.m_max[0] <= m_max[0]) && + (other.m_min[1] >= m_min[1]) && (other.m_max[1] <= m_max[1]) && + (other.m_min[2] >= m_min[2]) && (other.m_max[2] <= m_max[2]) + ); + } + + bool Bounds::intersects(const Bounds &other) const { + return ( + (other.m_max[0] >= m_min[0]) && (other.m_min[0] <= m_max[0]) && + (other.m_max[1] >= m_min[1]) && (other.m_min[1] <= m_max[1]) && + (other.m_max[2] >= m_min[2]) && (other.m_min[2] <= m_max[2]) + ); + } + + Bounds::operator bool() const { + return ( + (m_min[0] <= m_max[0]) && + (m_min[1] <= m_max[1]) && + (m_min[2] <= m_max[2]) + ); + } + + bool Bounds::operator!() const { + return ( + (m_min[0] > m_max[0]) || + (m_min[1] > m_max[1]) || + (m_min[2] > m_max[2]) + ); + } + + std::ostream& operator << (std::ostream& out, const Bounds& bounds) { + const auto& min = bounds.getMin(); + const auto& max = bounds.getMax(); + + return out << "[Bounds: (" << min[0] << ", " << min[1] << ", " << min[2] << ") (" + << max[0] << ", " << max[1] << ", " << max[2] << ") ]"; + } + } diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp index 6668b8b522d440ee1e50986b4b14e63bf2f63cbe..38e42666d4134b87c2c292e0ae3207a3581923c5 100644 --- a/modules/scene/src/vkcv/scene/Mesh.cpp +++ b/modules/scene/src/vkcv/scene/Mesh.cpp @@ -79,14 +79,50 @@ namespace vkcv::scene { return *this; } - void Mesh::recordDrawcalls(std::vector<glm::mat4>& matrices, + static glm::vec3 projectPoint(const glm::mat4& transform, const glm::vec3& point) { + const glm::vec4 position = transform * glm::vec4(point, 1.0f); + + return glm::vec3( + position[0] / position[3], + position[1] / position[3], + position[2] / position[3] + ); + } + + static bool checkFrustum(const Bounds& bounds) { + static Bounds frustum ( + glm::vec3(-1.0f, -1.0f, -0.0f), + glm::vec3(+1.0f, +1.0f, +1.0f) + ); + + return frustum.intersects(bounds); + } + + void Mesh::recordDrawcalls(const glm::mat4& viewProjection, + std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls) { - for (const auto& part : m_parts) { - matrices.push_back(m_transform); - } + const glm::mat4 transform = viewProjection * m_transform; - for (const auto& drawcall : m_drawcalls) { - drawcalls.push_back(drawcall); + for (size_t i = 0; i < m_parts.size(); i++) { + const MeshPart& part = m_parts[i]; + const Bounds& bounds = part.getBounds(); + const auto corners = bounds.getCorners(); + + auto projected = projectPoint(transform, corners[0]); + + Bounds aabb (projected, projected); + + for (size_t j = 1; j < corners.size(); j++) { + projected = projectPoint(transform, corners[j]); + aabb.extend(projected); + } + + if (!checkFrustum(aabb)) { + continue; + } + + matrices.push_back(transform); + drawcalls.push_back(m_drawcalls[i]); } } diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp index 316cf673b2525eafaba20abc2f7ad867482cd6da..acaa14e01ee318e04e057befa2b41cf7e0d4dbcf 100644 --- a/modules/scene/src/vkcv/scene/MeshPart.cpp +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -267,5 +267,9 @@ namespace vkcv::scene { (!m_indices) ); } - + + const Bounds &MeshPart::getBounds() const { + return m_bounds; + } + } diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp index a2f30bb9fed0ba330afb2cf4033ae47ccaf6abe5..9e7347036cec6a81797c33458bd7def645a8a3cd 100644 --- a/modules/scene/src/vkcv/scene/Node.cpp +++ b/modules/scene/src/vkcv/scene/Node.cpp @@ -55,14 +55,15 @@ namespace vkcv::scene { return m_nodes.back(); } - void Node::recordDrawcalls(std::vector<glm::mat4>& matrices, + void Node::recordDrawcalls(const glm::mat4& viewProjection, + std::vector<glm::mat4>& matrices, std::vector<DrawcallInfo>& drawcalls) { for (auto& mesh : m_meshes) { - mesh.recordDrawcalls(matrices, drawcalls); + mesh.recordDrawcalls(viewProjection, matrices, drawcalls); } for (auto& node : m_nodes) { - node.recordDrawcalls(matrices, drawcalls); + node.recordDrawcalls(viewProjection, matrices, drawcalls); } } diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index c58125b779232b90634bf6b0dde3a9ffcee13651..ad75ae799b0e75ab71cfe18530a6ecdf859f96fa 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -74,12 +74,10 @@ namespace vkcv::scene { std::vector<glm::mat4> matrices; std::vector<DrawcallInfo> drawcalls; - for (auto& node : m_nodes) { - node.recordDrawcalls(matrices, drawcalls); - } + const glm::mat4 viewProjection = camera.getMVP(); - for (auto& matrix : matrices) { - matrix = camera.getMVP() * matrix; + for (auto& node : m_nodes) { + node.recordDrawcalls(viewProjection, matrices, drawcalls); } PushConstantData pushConstantData (matrices.data(), sizeof(glm::mat4));