diff --git a/Src/Client/Vulkan/Abstract.hpp b/Src/Client/Vulkan/Abstract.hpp index f51e4c3..e753a21 100644 --- a/Src/Client/Vulkan/Abstract.hpp +++ b/Src/Client/Vulkan/Abstract.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include /* Воксели рендерятся точками, которые распаковываются в квадратные плоскости @@ -28,6 +29,8 @@ struct VoxelVertexPoint { Максимальный размер меша 14^3 м от центра ноды Координатное пространство то же, что и у вокселей + 8 позиций с двух сторон Рисуется полигонами + + В будущем - хранить данные освещения в отдельных буферах. Основные данные пусть спокойно индексируются */ struct NodeVertexStatic { @@ -38,6 +41,12 @@ struct NodeVertexStatic { Tex : 18, // Текстура N2 : 14, // Не занято TU : 16, TV : 16; // UV на текстуре + + bool operator==(const NodeVertexStatic& other) const { + return std::memcmp(this, &other, sizeof(*this)) == 0; + } + + bool operator<=>(const NodeVertexStatic&) const = default; }; } \ No newline at end of file diff --git a/Src/Client/Vulkan/VertexPool.hpp b/Src/Client/Vulkan/VertexPool.hpp index a54aee2..25e4071 100644 --- a/Src/Client/Vulkan/VertexPool.hpp +++ b/Src/Client/Vulkan/VertexPool.hpp @@ -15,7 +15,7 @@ namespace LV::Client::VK { Получаемые вершины сначала пишутся в общий буфер, потом передаются на устройство */ // Нужна реализация индексного буфера -template +template class VertexPool { static constexpr size_t HC_Buffer_Size = size_t(PerBlock)*size_t(PerPool); @@ -36,7 +36,7 @@ class VertexPool { Pool(Vulkan* inst) : DeviceBuff(inst, sizeof(Vertex)*size_t(PerBlock)*size_t(PerPool)+4 /* Для vkCmdFillBuffer */, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + (IsIndex ? VK_BUFFER_USAGE_INDEX_BUFFER_BIT : VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { Allocation.set(); @@ -327,5 +327,7 @@ public: } }; +template +using IndexPool = VertexPool; } \ No newline at end of file diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index b54bea8..eb193f5 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,19 @@ #include #include +namespace std { + template<> + struct hash { + size_t operator()(const LV::Client::VK::NodeVertexStatic& v) const { + const uint32_t* ptr = reinterpret_cast(&v); + size_t h1 = std::hash{}(ptr[0]); + size_t h2 = std::hash{}(ptr[1]); + size_t h3 = std::hash{}(ptr[2]); + + return h1 ^ (h2 << 1) ^ (h3 << 2); + } + }; +} namespace LV::Client::VK { @@ -271,6 +285,7 @@ void ChunkMeshGenerator::run(uint8_t id) { // Генерация вершин нод { NodeVertexStatic v; + std::memset(&v, 0, sizeof(v)); // Сбор вершин for(int z = 0; z < 16; z++) @@ -497,8 +512,35 @@ void ChunkMeshGenerator::run(uint8_t id) { // Вычислить индексы и сократить вершины { + uint32_t nextIndex = 0; + std::vector vertexes; + std::unordered_map vertexTable; std::vector indexes; + for(const NodeVertexStatic& vertex : result.NodeVertexs) { + auto iter = vertexTable.find(vertex); + if(iter == vertexTable.end()) { + vertexTable.insert({vertex, nextIndex}); + vertexes.push_back(vertex); + indexes.push_back(nextIndex); + nextIndex += 1; + } else { + indexes.push_back(iter->second); + } + } + + result.NodeVertexs = std::move(vertexes); + + if(nextIndex <= (1 << 16)) { + std::vector indexes16; + indexes16.reserve(indexes.size()); + for(size_t iter = 0; iter < indexes.size(); iter++) + indexes16.push_back(indexes[iter]); + + result.NodeIndexes = std::move(indexes16); + } else { + result.NodeIndexes = std::move(indexes); + } } } @@ -522,7 +564,7 @@ void ChunkMeshGenerator::run(uint8_t id) { std::pair< std::vector, uint32_t>>, - std::vector, uint32_t>> + std::vector, std::pair, bool, uint32_t>> > ChunkPreparator::getChunksForRender( WorldId_t worldId, Pos::Object pos, uint8_t distance, glm::mat4 projView, Pos::GlobalRegion x64offset ) { @@ -530,7 +572,7 @@ std::pair< Pos::GlobalRegion center = playerChunk >> 2; std::vector, uint32_t>> vertexVoxels; - std::vector, uint32_t>> vertexNodes; + std::vector, std::pair, bool, uint32_t>> vertexNodes; auto iterWorld = ChunksMesh.find(worldId); if(iterWorld == ChunksMesh.end()) @@ -576,37 +618,56 @@ std::pair< } if(chunk.NodePointer) { - vertexNodes.emplace_back(distance, local+Pos::GlobalChunk(localPos), VertexPool_Nodes.map(chunk.NodePointer), chunk.NodePointer.VertexCount); + vertexNodes.emplace_back( + distance, local+Pos::GlobalChunk(localPos), + VertexPool_Nodes.map(chunk.NodePointer), + chunk.NodeIndexes.index() == 0 + ? IndexPool_Nodes_16.map(std::get<0>(chunk.NodeIndexes)) + : IndexPool_Nodes_32.map(std::get<1>(chunk.NodeIndexes)) + , chunk.NodeIndexes.index() == 0, + std::visit([](const auto& val) -> uint32_t { return val.VertexCount; }, chunk.NodeIndexes)); } } } } } - auto sortByDistance = [] - ( - const std::tuple, uint32_t>& a, - const std::tuple, uint32_t>& b - ) { - return std::get<0>(a) < std::get<0>(b); - }; - - std::sort(vertexVoxels.begin(), vertexVoxels.end(), sortByDistance); - std::sort(vertexNodes.begin(), vertexNodes.end(), sortByDistance); + { + auto sortByDistance = [] + ( + const std::tuple, uint32_t>& a, + const std::tuple, uint32_t>& b + ) { + return std::get<0>(a) < std::get<0>(b); + }; + + std::sort(vertexVoxels.begin(), vertexVoxels.end(), sortByDistance); + } + + { + auto sortByDistance = [] + ( + const std::tuple, std::pair, bool, uint32_t>& a, + const std::tuple, std::pair, bool, uint32_t>& b + ) { + return std::get<0>(a) < std::get<0>(b); + }; + std::sort(vertexNodes.begin(), vertexNodes.end(), sortByDistance); + } std::vector, uint32_t>> resVertexVoxels; - std::vector, uint32_t>> resVertexNodes; + std::vector, std::pair, bool, uint32_t>> resVertexNodes; resVertexVoxels.reserve(vertexVoxels.size()); resVertexNodes.reserve(vertexNodes.size()); - for(const auto& [d, pos, ptr, count] : vertexVoxels) - resVertexVoxels.emplace_back(pos, ptr, count); + for(auto& [d, pos, ptr, count] : vertexVoxels) + resVertexVoxels.emplace_back(pos, std::move(ptr), count); - for(const auto& [d, pos, ptr, count] : vertexNodes) - resVertexNodes.emplace_back(pos, ptr, count); + for(auto& [d, pos, ptr, ptr2, type, count] : vertexNodes) + resVertexNodes.emplace_back(pos, std::move(ptr), std::move(ptr2), type, count); - return std::pair{resVertexVoxels, resVertexNodes}; + return std::pair{std::move(resVertexVoxels), std::move(resVertexNodes)}; } VulkanRenderSession::VulkanRenderSession(Vulkan *vkInst, IServerSession *serverSession) @@ -1433,22 +1494,24 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff size_t count = 0; glm::mat4 orig = PCO.Model; - for(auto& [chunkPos, vertexs, vertexCount] : nodeVertexs) { + for(auto& [chunkPos, vertexs, indexes, type, vertexCount] : nodeVertexs) { count += vertexCount; glm::vec3 cpos(chunkPos-x64offset); PCO.Model = glm::translate(orig, cpos*16.f); - auto [vkBufferN, offset] = vertexs; + auto [vkBufferV, offsetV] = vertexs; + auto [vkBufferI, offsetI] = indexes; vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model); - if(vkBufferN != vkBuffer) { - vkBuffer = vkBufferN; - vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets); - } + VkDeviceSize offset = offsetV*sizeof(NodeVertexStatic); + vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBufferV, &offset); + offset = offsetI * (type ? 2 : 4); + vkCmdBindIndexBuffer(drawCmd, vkBufferI, offset, type ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); - vkCmdDraw(drawCmd, vertexCount, 1, offset, 0); + vkCmdDrawIndexed(drawCmd, vertexCount, 1, 0, 0, 0); + //vkCmdDraw(drawCmd, vertexCount, 1, 0, 0); } PCO.Model = orig; diff --git a/Src/Client/Vulkan/VulkanRenderSession.hpp b/Src/Client/Vulkan/VulkanRenderSession.hpp index 2dc061a..1d942c0 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.hpp +++ b/Src/Client/Vulkan/VulkanRenderSession.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "Abstract.hpp" #include "TOSLib.hpp" @@ -288,12 +289,22 @@ public: rChunk.VoxelPointer = VertexPool_Voxels.pushVertexs(std::move(chunk.VoxelVertexs)); rChunk.Nodes = std::move(chunk.NodeDefines); if(!chunk.NodeVertexs.empty()) - rChunk.NodePointer = VertexPool_Nodes.pushVertexs(std::move(chunk.NodeVertexs)); + rChunk.NodePointer = VertexPool_Nodes.pushVertexs(std::move(chunk.NodeVertexs)); + + if(std::vector* ptr = std::get_if>(&chunk.NodeIndexes)) { + if(!ptr->empty()) + rChunk.NodeIndexes = IndexPool_Nodes_16.pushVertexs(std::move(*ptr)); + } else if(std::vector* ptr = std::get_if>(&chunk.NodeIndexes)) { + if(!ptr->empty()) + rChunk.NodeIndexes = IndexPool_Nodes_32.pushVertexs(std::move(*ptr)); + } } } VertexPool_Voxels.update(CMDPool); VertexPool_Nodes.update(CMDPool); + IndexPool_Nodes_16.update(CMDPool); + IndexPool_Nodes_32.update(CMDPool); CMG.endTickSync(); } @@ -310,9 +321,9 @@ public: for(auto& pointer : VPN_ToFree[FrameRoulette]) { VertexPool_Nodes.dropVertexs(std::get<0>(pointer)); - if(VertexPool::Pointer* ind = std::get_if::Pointer>(&std::get<1>(pointer))) { + if(IndexPool::Pointer* ind = std::get_if::Pointer>(&std::get<1>(pointer))) { IndexPool_Nodes_16.dropVertexs(*ind); - } else if(VertexPool::Pointer* ind = std::get_if::Pointer>(&std::get<1>(pointer))) { + } else if(IndexPool::Pointer* ind = std::get_if::Pointer>(&std::get<1>(pointer))) { IndexPool_Nodes_32.dropVertexs(*ind); } } @@ -323,7 +334,7 @@ public: // Выдаёт буферы для рендера в порядке от ближнего к дальнему. distance - радиус в регионах std::pair< std::vector, uint32_t>>, - std::vector, uint32_t>> + std::vector, std::pair, bool, uint32_t>> > getChunksForRender(WorldId_t worldId, Pos::Object pos, uint8_t distance, glm::mat4 projView, Pos::GlobalRegion x64offset); private: @@ -338,15 +349,15 @@ private: // Буферы для хранения вершин VertexPool VertexPool_Voxels; VertexPool VertexPool_Nodes; - VertexPool IndexPool_Nodes_16; - VertexPool IndexPool_Nodes_32; + IndexPool IndexPool_Nodes_16; + IndexPool IndexPool_Nodes_32; struct ChunkObj_t { std::vector Voxels; VertexPool::Pointer VoxelPointer; std::vector Nodes; VertexPool::Pointer NodePointer; - std::variant::Pointer, VertexPool::Pointer> NodeIndexes; + std::variant::Pointer, IndexPool::Pointer> NodeIndexes; }; // Склад указателей на вершины чанков @@ -359,7 +370,7 @@ private: std::vector::Pointer> VPV_ToFree[FRAME_COUNT_RESOURCE_LATENCY]; std::vector::Pointer, - std::variant::Pointer, VertexPool::Pointer> + std::variant::Pointer, IndexPool::Pointer> >> VPN_ToFree[FRAME_COUNT_RESOURCE_LATENCY]; // Следующий идентификатор запроса