From 8048598a795500630cc40adcc88f553c7268e840 Mon Sep 17 00:00:00 2001 From: Sebastian Gaida <gaida@ca-digit.com> Date: Tue, 20 Jul 2021 12:20:05 +0200 Subject: [PATCH] [#87] init meshlet module --- modules/CMakeLists.txt | 1 + modules/meshlet/CMakeLists.txt | 36 ++++ modules/meshlet/config/GLM.cmake | 23 +++ .../meshlet/include/vkcv/meshlet/Meshlet.hpp | 43 +++++ modules/meshlet/src/vkcv/meshlet/Meshlet.cpp | 138 +++++++++++++++ modules/meshlet/src/vkcv/meshlet/Tipsify.cpp | 4 + modules/scene/CMakeLists.txt | 2 - modules/scene/include/vkcv/scene/Meshlet.hpp | 161 ------------------ projects/mesh_shader/CMakeLists.txt | 4 +- .../mesh_shader/resources/shaders/shader.frag | 4 +- projects/mesh_shader/src/main.cpp | 16 +- 11 files changed, 258 insertions(+), 174 deletions(-) create mode 100644 modules/meshlet/CMakeLists.txt create mode 100644 modules/meshlet/config/GLM.cmake create mode 100644 modules/meshlet/include/vkcv/meshlet/Meshlet.hpp create mode 100644 modules/meshlet/src/vkcv/meshlet/Meshlet.cpp create mode 100644 modules/meshlet/src/vkcv/meshlet/Tipsify.cpp delete mode 100644 modules/scene/include/vkcv/scene/Meshlet.hpp diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 802200ad..72d94364 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(asset_loader) add_subdirectory(camera) add_subdirectory(gui) add_subdirectory(material) +add_subdirectory(meshlet) add_subdirectory(scene) add_subdirectory(shader_compiler) add_subdirectory(testing) diff --git a/modules/meshlet/CMakeLists.txt b/modules/meshlet/CMakeLists.txt new file mode 100644 index 00000000..d85b4602 --- /dev/null +++ b/modules/meshlet/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.16) +project(vkcv_meshlet) + +# setting c++ standard for the module +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(vkcv_meshlet_source ${PROJECT_SOURCE_DIR}/src) +set(vkcv_meshlet_include ${PROJECT_SOURCE_DIR}/include) + +# Add source and header files to the module +set(vkcv_meshlet_sources + ${vkcv_meshlet_include}/vkcv/meshlet/Meshlet.hpp + ${vkcv_meshlet_source}/vkcv/meshlet/Meshlet.cpp +# ${vkcv_meshlet_include}/vkcv/meshlet/Tipsify.hpp +# ${vkcv_meshlet_source}/vkcv/meshlet/Tipsify.cpp +) + +# adding source files to the module +add_library(vkcv_meshlet STATIC ${vkcv_meshlet_sources}) + +# Setup some path variables to load libraries +set(vkcv_meshlet_lib lib) +set(vkcv_meshlet_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_meshlet_lib}) + +# link the required libraries to the module +target_link_libraries(vkcv_meshlet vkcv ${vkcv_libraries}) + +# including headers of dependencies and the VkCV framework +target_include_directories(vkcv_meshlet SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) + +# add the own include directory for public headers +target_include_directories(vkcv_meshlet BEFORE PUBLIC ${vkcv_meshlet_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(vkcv_meshlet vkcv vkcv_asset_loader) diff --git a/modules/meshlet/config/GLM.cmake b/modules/meshlet/config/GLM.cmake new file mode 100644 index 00000000..50793345 --- /dev/null +++ b/modules/meshlet/config/GLM.cmake @@ -0,0 +1,23 @@ + +find_package(glm QUIET) + +if (glm_FOUND) + list(APPEND vkcv_meshlet_includes ${GLM_INCLUDE_DIRS}) + list(APPEND vkcv_meshlet_libraries glm) +else() + if (EXISTS "${vkcv_meshlet_lib_path}/glm") + add_subdirectory(${vkcv_meshlet_lib}/glm) + + list(APPEND vkcv_meshlet_includes ${vkcv_meshlet_lib_path}/glm) + list(APPEND vkcv_meshlet_libraries glm) + else() + message(WARNING "GLM is required..! Update the submodules!") + endif () +endif () + +list(APPEND vkcv_meshlet_definitions GLM_DEPTH_ZERO_TO_ONE) +list(APPEND vkcv_meshlet_definitions GLM_FORCE_LEFT_HANDED) + +if ((WIN32) AND (${CMAKE_SIZEOF_VOID_P} MATCHES 4)) + list(APPEND vkcv_meshlet_definitions GLM_ENABLE_EXPERIMENTAL) +endif() diff --git a/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp b/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp new file mode 100644 index 00000000..44761802 --- /dev/null +++ b/modules/meshlet/include/vkcv/meshlet/Meshlet.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include <vector> +#include <map> +#include <glm/glm.hpp> + +namespace vkcv::meshlet { + + struct Vertex { + glm::vec3 position; + float padding0; + glm::vec3 normal; + float padding1; + }; + + struct Meshlet { + uint32_t vertexOffset; + uint32_t vertexCount; + uint32_t indexOffset; + uint32_t indexCount; + }; + + struct MeshShaderModelData { + std::vector<Vertex> vertices; + std::vector<uint32_t> localIndices; + std::vector<Meshlet> meshlets; + }; + + std::vector<Vertex> convertToVertices( + const std::vector<uint8_t>& vertexData, + const uint64_t vertexCount, + const vkcv::asset::VertexAttribute& positionAttribute, + const vkcv::asset::VertexAttribute& normalAttribute); + + MeshShaderModelData createMeshShaderModelData( + const std::vector<Vertex>& inVertices, + const std::vector<uint32_t>& inIndices); + + std::vector<uint32_t> assetLoaderIndicesTo32BitIndices( + const std::vector<uint8_t>& indexData, + vkcv::asset::IndexType indexType); + +} \ No newline at end of file diff --git a/modules/meshlet/src/vkcv/meshlet/Meshlet.cpp b/modules/meshlet/src/vkcv/meshlet/Meshlet.cpp new file mode 100644 index 00000000..542dcf7d --- /dev/null +++ b/modules/meshlet/src/vkcv/meshlet/Meshlet.cpp @@ -0,0 +1,138 @@ + +#include "vkcv/meshlet/Meshlet.hpp" +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/Logger.hpp> +#include <cassert> + +namespace vkcv::meshlet { + +std::vector<vkcv::meshlet::Vertex> convertToVertices( + const std::vector<uint8_t>& vertexData, + const uint64_t vertexCount, + const vkcv::asset::VertexAttribute& positionAttribute, + const vkcv::asset::VertexAttribute& normalAttribute) { + + assert(positionAttribute.type == vkcv::asset::PrimitiveType::POSITION); + assert(normalAttribute.type == vkcv::asset::PrimitiveType::NORMAL); + + std::vector<vkcv::meshlet::Vertex> vertices; + vertices.reserve(vertexCount); + + const size_t positionStepSize = positionAttribute.stride == 0 ? sizeof(glm::vec3) : positionAttribute.stride; + const size_t normalStepSize = normalAttribute.stride == 0 ? sizeof(glm::vec3) : normalAttribute.stride; + + for (int i = 0; i < vertexCount; i++) { + Vertex v; + + const size_t positionOffset = positionAttribute.offset + positionStepSize * i; + const size_t normalOffset = normalAttribute.offset + normalStepSize * i; + + v.position = *reinterpret_cast<const glm::vec3*>(&(vertexData[positionOffset])); + v.normal = *reinterpret_cast<const glm::vec3*>(&(vertexData[normalOffset])); + vertices.push_back(v); + } + return vertices; +} + +MeshShaderModelData createMeshShaderModelData( + const std::vector<Vertex>& inVertices, + const std::vector<uint32_t>& inIndices) { + + MeshShaderModelData data; + size_t currentIndex = 0; + + const size_t maxVerticesPerMeshlet = 64; + const size_t maxIndicesPerMeshlet = 126 * 3; + + bool indicesAreLeft = true; + + while (indicesAreLeft) { + Meshlet meshlet; + + meshlet.indexCount = 0; + meshlet.vertexCount = 0; + + meshlet.indexOffset = data.localIndices.size(); + meshlet.vertexOffset = data.vertices.size(); + + std::map<uint32_t, uint32_t> globalToLocalIndexMap; + std::vector<uint32_t> globalIndicesOrdered; + + while (true) { + + indicesAreLeft = currentIndex + 1 <= inIndices.size(); + if (!indicesAreLeft) { + break; + } + + bool enoughSpaceForIndices = meshlet.indexCount + 3 < maxIndicesPerMeshlet; + if (!enoughSpaceForIndices) { + break; + } + + size_t vertexCountToAdd = 0; + for (int i = 0; i < 3; i++) { + const uint32_t globalIndex = inIndices[currentIndex + i]; + const bool containsVertex = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end(); + if (!containsVertex) { + vertexCountToAdd++; + } + } + + bool enoughSpaceForVertices = meshlet.vertexCount + vertexCountToAdd < maxVerticesPerMeshlet; + if (!enoughSpaceForVertices) { + break; + } + + for (int i = 0; i < 3; i++) { + const uint32_t globalIndex = inIndices[currentIndex + i]; + + uint32_t localIndex; + const bool indexAlreadyExists = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end(); + if (indexAlreadyExists) { + localIndex = globalToLocalIndexMap[globalIndex]; + } + else { + localIndex = globalToLocalIndexMap.size(); + globalToLocalIndexMap[globalIndex] = localIndex; + globalIndicesOrdered.push_back(globalIndex); + } + + data.localIndices.push_back(localIndex); + } + + meshlet.indexCount += 3; + currentIndex += 3; + meshlet.vertexCount += vertexCountToAdd; + } + + for (const uint32_t globalIndex : globalIndicesOrdered) { + const Vertex v = inVertices[globalIndex]; + data.vertices.push_back(v); + } + + data.meshlets.push_back(meshlet); + } + + return data; +} + +std::vector<uint32_t> assetLoaderIndicesTo32BitIndices(const std::vector<uint8_t>& indexData, vkcv::asset::IndexType indexType) { + std::vector<uint32_t> indices; + if (indexType == vkcv::asset::IndexType::UINT16) { + for (int i = 0; i < indexData.size(); i += 2) { + const uint16_t index16Bit = *reinterpret_cast<const uint16_t *>(&(indexData[i])); + const uint32_t index32Bit = static_cast<uint32_t>(index16Bit); + indices.push_back(index32Bit); + } + } else if (indexType == vkcv::asset::IndexType::UINT32) { + for (int i = 0; i < indexData.size(); i += 4) { + const uint32_t index32Bit = *reinterpret_cast<const uint32_t *>(&(indexData[i])); + indices.push_back(index32Bit); + } + } else { + vkcv_log(vkcv::LogLevel::ERROR, "Unsupported index type"); + } + return indices; +} +} \ No newline at end of file diff --git a/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp b/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp new file mode 100644 index 00000000..281830b9 --- /dev/null +++ b/modules/meshlet/src/vkcv/meshlet/Tipsify.cpp @@ -0,0 +1,4 @@ +// +// Created by Dradozer on 20.07.2021. +// + diff --git a/modules/scene/CMakeLists.txt b/modules/scene/CMakeLists.txt index b948a0ed..5edf9a29 100644 --- a/modules/scene/CMakeLists.txt +++ b/modules/scene/CMakeLists.txt @@ -22,8 +22,6 @@ set(vkcv_scene_sources ${vkcv_scene_include}/vkcv/scene/Mesh.hpp ${vkcv_scene_source}/vkcv/scene/Mesh.cpp - ${vkcv_scene_include}/vkcv/scene/Meshlet.hpp - ${vkcv_scene_include}/vkcv/scene/Node.hpp ${vkcv_scene_source}/vkcv/scene/Node.cpp diff --git a/modules/scene/include/vkcv/scene/Meshlet.hpp b/modules/scene/include/vkcv/scene/Meshlet.hpp deleted file mode 100644 index c4990169..00000000 --- a/modules/scene/include/vkcv/scene/Meshlet.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include <vector> -#include <map> -#include <glm/glm.hpp> - -namespace vkcv::scene { - - struct Vertex { - glm::vec3 position; - float padding0; - glm::vec3 normal; - float padding1; - }; - - struct Meshlet { - uint32_t vertexOffset; - uint32_t vertexCount; - uint32_t indexOffset; - uint32_t indexCount; - }; - - struct MeshShaderModelData { - std::vector<Vertex> vertices; - std::vector<uint32_t> localIndices; - std::vector<Meshlet> meshlets; - }; - - std::vector<Vertex> convertToVertices( - const std::vector<uint8_t>& vertexData, - const uint64_t vertexCount, - const vkcv::asset::VertexAttribute& positionAttribute, - const vkcv::asset::VertexAttribute& normalAttribute) { - - assert(positionAttribute.type == vkcv::asset::PrimitiveType::POSITION); - assert(normalAttribute.type == vkcv::asset::PrimitiveType::NORMAL); - - std::vector<Vertex> vertices; - vertices.reserve(vertexCount); - - const size_t positionStepSize = positionAttribute.stride == 0 ? sizeof(glm::vec3) : positionAttribute.stride; - const size_t normalStepSize = normalAttribute.stride == 0 ? sizeof(glm::vec3) : normalAttribute.stride; - - for (int i = 0; i < vertexCount; i++) { - Vertex v; - - const size_t positionOffset = positionAttribute.offset + positionStepSize * i; - const size_t normalOffset = normalAttribute.offset + normalStepSize * i; - - v.position = *reinterpret_cast<const glm::vec3*>(&(vertexData[positionOffset])); - v.normal = *reinterpret_cast<const glm::vec3*>(&(vertexData[normalOffset])); - vertices.push_back(v); - } - return vertices; - } - - MeshShaderModelData createMeshShaderModelData( - const std::vector<Vertex>& inVertices, - const std::vector<uint32_t>& inIndices) { - - MeshShaderModelData data; - size_t currentIndex = 0; - - const size_t maxVerticesPerMeshlet = 64; - const size_t maxIndicesPerMeshlet = 126 * 3; - - bool indicesAreLeft = true; - - while (indicesAreLeft) { - Meshlet meshlet; - - meshlet.indexCount = 0; - meshlet.vertexCount = 0; - - meshlet.indexOffset = data.localIndices.size(); - meshlet.vertexOffset = data.vertices.size(); - - std::map<uint32_t, uint32_t> globalToLocalIndexMap; - std::vector<uint32_t> globalIndicesOrdered; - - while (true) { - - indicesAreLeft = currentIndex + 1 <= inIndices.size(); - if (!indicesAreLeft) { - break; - } - - bool enoughSpaceForIndices = meshlet.indexCount + 3 < maxIndicesPerMeshlet; - if (!enoughSpaceForIndices) { - break; - } - - size_t vertexCountToAdd = 0; - for (int i = 0; i < 3; i++) { - const uint32_t globalIndex = inIndices[currentIndex + i]; - const bool containsVertex = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end(); - if (!containsVertex) { - vertexCountToAdd++; - } - } - - bool enoughSpaceForVertices = meshlet.vertexCount + vertexCountToAdd < maxVerticesPerMeshlet; - if (!enoughSpaceForVertices) { - break; - } - - for (int i = 0; i < 3; i++) { - const uint32_t globalIndex = inIndices[currentIndex + i]; - - uint32_t localIndex; - const bool indexAlreadyExists = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end(); - if (indexAlreadyExists) { - localIndex = globalToLocalIndexMap[globalIndex]; - } - else { - localIndex = globalToLocalIndexMap.size(); - globalToLocalIndexMap[globalIndex] = localIndex; - globalIndicesOrdered.push_back(globalIndex); - } - - data.localIndices.push_back(localIndex); - } - - meshlet.indexCount += 3; - currentIndex += 3; - meshlet.vertexCount += vertexCountToAdd; - } - - for (const uint32_t globalIndex : globalIndicesOrdered) { - const Vertex v = inVertices[globalIndex]; - data.vertices.push_back(v); - } - - data.meshlets.push_back(meshlet); - } - - return data; - } - - std::vector<uint32_t> assetLoaderIndicesTo32BitIndices(const std::vector<uint8_t>& indexData, vkcv::asset::IndexType indexType) { - std::vector<uint32_t> indices; - if (indexType == vkcv::asset::IndexType::UINT16) { - for (int i = 0; i < indexData.size(); i += 2) { - const uint16_t index16Bit = *reinterpret_cast<const uint16_t*>(&(indexData[i])); - const uint32_t index32Bit = static_cast<uint32_t>(index16Bit); - indices.push_back(index32Bit); - } - } - else if (indexType == vkcv::asset::IndexType::UINT32) { - for (int i = 0; i < indexData.size(); i += 4) { - const uint32_t index32Bit = *reinterpret_cast<const uint32_t*>(&(indexData[i])); - indices.push_back(index32Bit); - } - } - else { - vkcv_log(vkcv::LogLevel::ERROR, "Unsupported index type"); - } - return indices; - } - -} \ No newline at end of file diff --git a/projects/mesh_shader/CMakeLists.txt b/projects/mesh_shader/CMakeLists.txt index 1e1d2e86..1aa5d5ff 100644 --- a/projects/mesh_shader/CMakeLists.txt +++ b/projects/mesh_shader/CMakeLists.txt @@ -24,7 +24,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(mesh_shader SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) +target_include_directories(mesh_shader SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_meshlet_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(mesh_shader vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_testing vkcv_camera vkcv_scene vkcv_shader_compiler vkcv_gui) \ No newline at end of file +target_link_libraries(mesh_shader vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_testing vkcv_camera vkcv_meshlet vkcv_shader_compiler vkcv_gui) \ No newline at end of file diff --git a/projects/mesh_shader/resources/shaders/shader.frag b/projects/mesh_shader/resources/shaders/shader.frag index 17bf8f96..34f78313 100644 --- a/projects/mesh_shader/resources/shaders/shader.frag +++ b/projects/mesh_shader/resources/shaders/shader.frag @@ -27,6 +27,6 @@ vec3 colorFromIndex(uint i){ } void main() { - outColor = normalize(passNormal) * 0.5 + 0.5; - //outColor = colorFromIndex(passTaskIndex); + //outColor = normalize(passNormal) * 0.5 + 0.5; + outColor = colorFromIndex(passTaskIndex); } \ No newline at end of file diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index f48d30f1..40ae9ce2 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -7,7 +7,8 @@ #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/gui/GUI.hpp> #include <vkcv/asset/asset_loader.hpp> -#include <vkcv/scene/Meshlet.hpp> +#include <vkcv/meshlet/Meshlet.hpp> +#include <vkcv/meshlet/Tipsify.hpp> int main(int argc, const char** argv) { const char* applicationName = "Mesh shader"; @@ -70,14 +71,15 @@ int main(int argc, const char** argv) { vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; const auto& bunny = mesh.vertexGroups[0]; - const std::vector<vkcv::scene::Vertex> interleavedVertices = vkcv::scene::convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]); - + std::vector<vkcv::meshlet::Vertex> interleavedVertices = vkcv::meshlet::convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]); // mesh shader buffers const auto& assetLoaderIndexBuffer = mesh.vertexGroups[0].indexBuffer; - const std::vector<uint32_t> indexBuffer32Bit = vkcv::scene::assetLoaderIndicesTo32BitIndices(assetLoaderIndexBuffer.data, assetLoaderIndexBuffer.type); - const auto meshShaderModelData = createMeshShaderModelData(interleavedVertices, indexBuffer32Bit); + std::vector<uint32_t> indexBuffer32Bit = vkcv::meshlet::assetLoaderIndicesTo32BitIndices(assetLoaderIndexBuffer.data, assetLoaderIndexBuffer.type); +// std::vector<uint32_t> reorderedIndexBuffer32Bit = vkcv::meshlet::tipsifyMesh(indexBuffer32Bit, interleavedVertices.size(), 2); + + const auto meshShaderModelData = createMeshShaderModelData(interleavedVertices, indexBuffer32Bit); - auto meshShaderVertexBuffer = core.createBuffer<vkcv::scene::Vertex>( + auto meshShaderVertexBuffer = core.createBuffer<vkcv::meshlet::Vertex>( vkcv::BufferType::STORAGE, meshShaderModelData.vertices.size()); meshShaderVertexBuffer.fill(meshShaderModelData.vertices); @@ -87,7 +89,7 @@ int main(int argc, const char** argv) { meshShaderModelData.localIndices.size()); meshShaderIndexBuffer.fill(meshShaderModelData.localIndices); - auto meshletBuffer = core.createBuffer<vkcv::scene::Meshlet>( + auto meshletBuffer = core.createBuffer<vkcv::meshlet::Meshlet>( vkcv::BufferType::STORAGE, meshShaderModelData.meshlets.size(), vkcv::BufferMemoryType::DEVICE_LOCAL -- GitLab