Буферы вершин
This commit is contained in:
43
Src/Client/Vulkan/Abstract.hpp
Normal file
43
Src/Client/Vulkan/Abstract.hpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Воксели рендерятся точками, которые распаковываются в квадратные плоскости
|
||||||
|
|
||||||
|
В чанке по оси 256 вокселей, и 257 позиций вершин (включая дальнюю границу чанка)
|
||||||
|
9 бит на позицию *3 оси = 27 бит
|
||||||
|
Указание материала 16 бит
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LV::Client::VK {
|
||||||
|
|
||||||
|
struct VoxelVertexPoint {
|
||||||
|
uint32_t
|
||||||
|
FX : 9, FY : 9, FZ : 9, // Позиция
|
||||||
|
Place : 3, // Положение распространения xz, xy, zy, и обратные
|
||||||
|
N1 : 1, // Не занято
|
||||||
|
LS : 1, // Масштаб карты освещения (1м/16 или 1м)
|
||||||
|
TX : 8, TY : 8, // Размер+1
|
||||||
|
VoxMtl : 16, // Материал вокселя DefVoxelId_t
|
||||||
|
LU : 14, LV : 14, // Позиция на карте освещения
|
||||||
|
N2 : 2; // Не занято
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Максимальный размер меша 14^3 м от центра ноды
|
||||||
|
Координатное пространство то же, что и у вокселей + 8 позиций с двух сторон
|
||||||
|
Рисуется полигонами
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct NodeVertexStatic {
|
||||||
|
uint32_t
|
||||||
|
FX : 9, FY : 9, FZ : 9, // Позиция 15 -120 ~ 240 360 15 / 16
|
||||||
|
N1 : 4, // Не занято
|
||||||
|
LS : 1, // Масштаб карты освещения (1м/16 или 1м)
|
||||||
|
Tex : 18, // Текстура
|
||||||
|
N2 : 14, // Не занято
|
||||||
|
TU : 16, TV : 16; // UV на текстуре
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
283
Src/Client/Vulkan/VertexPool.hpp
Normal file
283
Src/Client/Vulkan/VertexPool.hpp
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vulkan.hpp"
|
||||||
|
#include <bitset>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace LV::Client::VK {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Память на устройстве выделяется пулами
|
||||||
|
Для массивов вершин память выделяется блоками по PerBlock вершин в каждом
|
||||||
|
Размер пулла sizeof(Vertex)*PerBlock*PerPool
|
||||||
|
|
||||||
|
Получаемые вершины сначала пишутся в общий буфер, потом передаются на устройство
|
||||||
|
*/
|
||||||
|
template<typename Vertex, uint16_t PerBlock = 1 << 10, uint16_t PerPool = 1 << 12>
|
||||||
|
class VertexPool {
|
||||||
|
static constexpr size_t HC_Buffer_Size = size_t(PerBlock)*size_t(PerPool);
|
||||||
|
|
||||||
|
Vulkan *Inst;
|
||||||
|
|
||||||
|
// Память, доступная для обмена с устройством
|
||||||
|
Buffer HostCoherent;
|
||||||
|
Vertex *HCPtr = nullptr;
|
||||||
|
size_t WritePos = 0;
|
||||||
|
|
||||||
|
struct Pool {
|
||||||
|
// Память на устройстве
|
||||||
|
Buffer DeviceBuff;
|
||||||
|
// Свободные блоки
|
||||||
|
std::bitset<PerPool> Allocation;
|
||||||
|
|
||||||
|
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,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
||||||
|
{
|
||||||
|
Allocation.set();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Pool> Pools;
|
||||||
|
|
||||||
|
struct Task {
|
||||||
|
std::vector<Vertex> Data;
|
||||||
|
size_t Pos = -1; // Если данные уже записаны, то будет указана позиция в буфере общения
|
||||||
|
uint8_t PoolId; // Куда потом направить
|
||||||
|
uint16_t BlockId; // И в какой блок
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Перед следующим обновлением буфер общения заполняется с начала и до конца
|
||||||
|
Если место закончится, будет дослано в следующем обновлении
|
||||||
|
*/
|
||||||
|
std::queue<Task> TasksWait, TasksPostponed;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void pushData(std::vector<Vertex>&& data, uint8_t poolId, uint16_t blockId) {
|
||||||
|
if(HC_Buffer_Size-WritePos >= data.size()) {
|
||||||
|
// Пишем в общий буфер, TasksWait
|
||||||
|
Vertex *ptr = HCPtr+WritePos;
|
||||||
|
std::copy(data.begin(), data.end(), ptr);
|
||||||
|
TasksWait.push({std::move(data), WritePos, poolId, blockId});
|
||||||
|
WritePos += data.size();
|
||||||
|
} else {
|
||||||
|
// Отложим запись на следующий такт
|
||||||
|
TasksPostponed.push(Task(std::move(data), -1, poolId, blockId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
VertexPool(Vulkan* inst)
|
||||||
|
: Inst(inst),
|
||||||
|
HostCoherent(inst,
|
||||||
|
sizeof(Vertex)*HC_Buffer_Size+4 /* Для vkCmdFillBuffer */,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
||||||
|
{
|
||||||
|
Pools.reserve(16);
|
||||||
|
HCPtr = (Vertex*) HostCoherent.mapMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
~VertexPool() {
|
||||||
|
if(HCPtr)
|
||||||
|
HostCoherent.unMapMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Pointer {
|
||||||
|
uint32_t PoolId : 8, BlockId : 16, VertexCount = 0;
|
||||||
|
|
||||||
|
operator bool() const { return VertexCount; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Переносит вершины на устройство, заранее передаёт указатель на область в памяти
|
||||||
|
Надеемся что к следующему кадру данные будут переданы
|
||||||
|
*/
|
||||||
|
Pointer pushVertexs(std::vector<Vertex>&& data) {
|
||||||
|
if(data.empty())
|
||||||
|
return {0, 0, 0};
|
||||||
|
|
||||||
|
// Необходимое количество блоков
|
||||||
|
uint16_t blocks = data.size() / size_t(PerBlock);
|
||||||
|
assert(blocks <= PerPool);
|
||||||
|
|
||||||
|
// Нужно найти пулл в котором будет свободно blocks количество блоков или создать новый
|
||||||
|
for(size_t iterPool = 0; iterPool < Pools.size(); iterPool++) {
|
||||||
|
Pool &pool = Pools[iterPool];
|
||||||
|
size_t pos = pool.Allocation._Find_first();
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
int countEmpty = 1;
|
||||||
|
for(size_t pos2 = pos+1; pos2 < PerPool && pool.Allocation.test(pos2) && countEmpty < blocks; pos2++, countEmpty++);
|
||||||
|
|
||||||
|
if(countEmpty == blocks) {
|
||||||
|
for(int block = 0; block < blocks; block++)
|
||||||
|
pool.Allocation.reset(pos+block);
|
||||||
|
|
||||||
|
size_t count = data.size();
|
||||||
|
pushData(std::move(data), iterPool, pos);
|
||||||
|
|
||||||
|
return Pointer(iterPool, pos, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += countEmpty;
|
||||||
|
|
||||||
|
if(pos >= PerPool)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = pool.Allocation._Find_next(pos+countEmpty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Не нашлось подходящего пула, создаём новый
|
||||||
|
assert(Pools.size() < 256);
|
||||||
|
|
||||||
|
Pools.emplace_back(Inst);
|
||||||
|
Pool &last = Pools.back();
|
||||||
|
// vkCmdFillBuffer(nullptr, last.DeviceBuff, 0, last.DeviceBuff.getSize() & ~0x3, 0);
|
||||||
|
for(int block = 0; block < blocks; block++)
|
||||||
|
last.Allocation.reset(block);
|
||||||
|
|
||||||
|
size_t count = data.size();
|
||||||
|
pushData(std::move(data), Pools.size()-1, 0);
|
||||||
|
|
||||||
|
return Pointer(Pools.size()-1, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Освобождает указатель
|
||||||
|
*/
|
||||||
|
void dropVertexs(const Pointer &pointer) {
|
||||||
|
if(!pointer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(pointer.PoolId < Pools.size());
|
||||||
|
assert(pointer.BlockId < PerPool);
|
||||||
|
|
||||||
|
Pool &pool = Pools[pointer.PoolId];
|
||||||
|
int blocks = (pointer.VertexCount+PerBlock-1) / PerBlock;
|
||||||
|
for(int indexBlock = 0; indexBlock < blocks; indexBlock++) {
|
||||||
|
assert(!pool.Allocation.test(pointer.BlockId+indexBlock));
|
||||||
|
pool.Allocation.set(pointer.BlockId+indexBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dropVertexs(Pointer &pointer) {
|
||||||
|
dropVertexs(const_cast<const Pointer&>(pointer));
|
||||||
|
pointer.VertexCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Перевыделяет память под новые данные
|
||||||
|
*/
|
||||||
|
void relocate(Pointer& pointer, std::vector<Vertex>&& data) {
|
||||||
|
if(data.empty()) {
|
||||||
|
if(!pointer)
|
||||||
|
return;
|
||||||
|
else {
|
||||||
|
dropVertexs(pointer);
|
||||||
|
pointer.VertexCount = 0;
|
||||||
|
}
|
||||||
|
} else if(!pointer) {
|
||||||
|
pointer = pushVertexs(std::move(data));
|
||||||
|
} else {
|
||||||
|
int needBlocks = (data.size()+PerBlock-1) / PerBlock;
|
||||||
|
|
||||||
|
if((pointer.VertexCount+PerBlock-1) / PerBlock == needBlocks) {
|
||||||
|
pointer.VertexCount = data.size();
|
||||||
|
pushData(std::move(data), pointer.PoolId, pointer.BlockId);
|
||||||
|
} else {
|
||||||
|
dropVertexs(pointer);
|
||||||
|
pointer = pushVertexs(std::move(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Транслирует локальный указатель в буффер и позицию вершины в нём
|
||||||
|
*/
|
||||||
|
std::pair<VkBuffer, int> map(const Pointer pointer) {
|
||||||
|
assert(pointer.PoolId < Pools.size());
|
||||||
|
assert(pointer.BlockId < PerPool);
|
||||||
|
|
||||||
|
return {Pools[pointer.PoolId].DeviceBuff.getBuffer(), pointer.BlockId*PerBlock};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Должно вызываться после приёма всех данных и перед рендером
|
||||||
|
*/
|
||||||
|
void update(VkCommandPool commandPool) {
|
||||||
|
if(TasksWait.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo allocInfo {
|
||||||
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||||
|
nullptr,
|
||||||
|
commandPool,
|
||||||
|
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
VkCommandBuffer commandBuffer;
|
||||||
|
vkAllocateCommandBuffers(Inst->Graphics.Device, &allocInfo, &commandBuffer);
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo beginInfo {
|
||||||
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||||
|
nullptr,
|
||||||
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||||
|
|
||||||
|
while(!TasksWait.empty()) {
|
||||||
|
Task& task = TasksWait.front();
|
||||||
|
|
||||||
|
VkBufferCopy copyRegion {
|
||||||
|
task.Pos*sizeof(Vertex),
|
||||||
|
task.BlockId*sizeof(Vertex)*size_t(PerBlock),
|
||||||
|
task.Data.size()*sizeof(Vertex)
|
||||||
|
};
|
||||||
|
|
||||||
|
vkCmdCopyBuffer(commandBuffer, HostCoherent.getBuffer(), Pools[task.PoolId].DeviceBuff.getBuffer(),
|
||||||
|
1, ©Region);
|
||||||
|
|
||||||
|
TasksWait.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
vkEndCommandBuffer(commandBuffer);
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo {
|
||||||
|
VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||||
|
nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
nullptr,
|
||||||
|
1,
|
||||||
|
&commandBuffer,
|
||||||
|
0,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
vkQueueSubmit(Inst->Graphics.DeviceQueueGraphic, 1, &submitInfo, VK_NULL_HANDLE);
|
||||||
|
vkQueueWaitIdle(Inst->Graphics.DeviceQueueGraphic);
|
||||||
|
vkFreeCommandBuffers(Inst->Graphics.Device, commandPool, 1, &commandBuffer);
|
||||||
|
|
||||||
|
std::queue<Task> postponed = std::move(TasksPostponed);
|
||||||
|
WritePos = 0;
|
||||||
|
|
||||||
|
while(!postponed.empty()) {
|
||||||
|
Task& task = TasksWait.front();
|
||||||
|
pushData(std::move(task.Data), task.PoolId, task.BlockId);
|
||||||
|
TasksWait.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -625,28 +625,19 @@ void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered
|
|||||||
const auto &chunk = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z];
|
const auto &chunk = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z];
|
||||||
|
|
||||||
if(chunk.Voxels.empty()) {
|
if(chunk.Voxels.empty()) {
|
||||||
std::get<0>(buffers) = nullptr;
|
VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(buffers));
|
||||||
} else {
|
} else {
|
||||||
std::vector<VoxelVertexPoint> vertexs = generateMeshForVoxelChunks(chunk.Voxels);
|
std::vector<VoxelVertexPoint> vertexs = generateMeshForVoxelChunks(chunk.Voxels);
|
||||||
|
|
||||||
if(!vertexs.empty()) {
|
|
||||||
auto &voxels = std::get<0>(buffers);
|
auto &voxels = std::get<0>(buffers);
|
||||||
voxels = std::make_unique<Buffer>(VkInst, vertexs.size()*sizeof(VoxelVertexPoint));
|
VKCTX->VertexPool_Voxels.relocate(voxels, std::move(vertexs));
|
||||||
std::copy(vertexs.data(), vertexs.data()+vertexs.size(), (VoxelVertexPoint*) voxels->mapMemory());
|
|
||||||
voxels->unMapMemory();
|
|
||||||
} else {
|
|
||||||
std::get<0>(buffers) = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes);
|
std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes);
|
||||||
if(vertexs2.empty()) {
|
if(vertexs2.empty()) {
|
||||||
std::get<1>(buffers) = nullptr;
|
VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(buffers));
|
||||||
} else {
|
} else {
|
||||||
auto &nodes = std::get<1>(buffers);
|
auto &nodes = std::get<1>(buffers);
|
||||||
nodes = std::make_unique<Buffer>(VkInst, vertexs2.size()*sizeof(NodeVertexStatic));
|
VKCTX->VertexPool_Nodes.relocate(nodes, std::move(vertexs2));
|
||||||
std::copy(vertexs2.data(), vertexs2.data()+vertexs2.size(), (NodeVertexStatic*) nodes->mapMemory());
|
|
||||||
nodes->unMapMemory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!std::get<0>(buffers) && !std::get<1>(buffers)) {
|
if(!std::get<0>(buffers) && !std::get<1>(buffers)) {
|
||||||
@@ -661,10 +652,13 @@ void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered
|
|||||||
for(int y = 0; y < 4; y++)
|
for(int y = 0; y < 4; y++)
|
||||||
for(int x = 0; x < 4; x++) {
|
for(int x = 0; x < 4; x++) {
|
||||||
auto iter = table.find((Pos::GlobalChunk(pos) << 2) + Pos::GlobalChunk(x, y, z));
|
auto iter = table.find((Pos::GlobalChunk(pos) << 2) + Pos::GlobalChunk(x, y, z));
|
||||||
if(iter != table.end())
|
if(iter != table.end()) {
|
||||||
|
VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(iter->second));
|
||||||
|
VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(iter->second));
|
||||||
table.erase(iter);
|
table.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(table.empty())
|
if(table.empty())
|
||||||
External.ChunkVoxelMesh.erase( External.ChunkVoxelMesh.find(worldId));
|
External.ChunkVoxelMesh.erase( External.ChunkVoxelMesh.find(worldId));
|
||||||
@@ -680,6 +674,8 @@ void VulkanRenderSession::beforeDraw() {
|
|||||||
if(VKCTX) {
|
if(VKCTX) {
|
||||||
VKCTX->MainTest.atlasUpdateDynamicData();
|
VKCTX->MainTest.atlasUpdateDynamicData();
|
||||||
VKCTX->LightDummy.atlasUpdateDynamicData();
|
VKCTX->LightDummy.atlasUpdateDynamicData();
|
||||||
|
VKCTX->VertexPool_Voxels.update(VkInst->Graphics.Pool);
|
||||||
|
VKCTX->VertexPool_Nodes.update(VkInst->Graphics.Pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,12 +738,12 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
|
|||||||
if(auto& voxels = std::get<0>(pair.second)) {
|
if(auto& voxels = std::get<0>(pair.second)) {
|
||||||
glm::vec3 cpos(pair.first.x, pair.first.y, pair.first.z);
|
glm::vec3 cpos(pair.first.x, pair.first.y, pair.first.z);
|
||||||
PCO.Model = glm::translate(orig, cpos*16.f);
|
PCO.Model = glm::translate(orig, cpos*16.f);
|
||||||
vkBuffer = *voxels;
|
auto [vkBuffer, offset] = VKCTX->VertexPool_Voxels.map(voxels);
|
||||||
|
|
||||||
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
||||||
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
||||||
vkCmdDraw(drawCmd, voxels->getSize() / sizeof(VoxelVertexPoint), 1, 0, 0);
|
vkCmdDraw(drawCmd, voxels.VertexCount, 1, offset, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,12 +767,12 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
|
|||||||
if(auto& nodes = std::get<1>(pair.second)) {
|
if(auto& nodes = std::get<1>(pair.second)) {
|
||||||
glm::vec3 cpos(pair.first.x, pair.first.y, pair.first.z);
|
glm::vec3 cpos(pair.first.x, pair.first.y, pair.first.z);
|
||||||
PCO.Model = glm::translate(orig, cpos*16.f);
|
PCO.Model = glm::translate(orig, cpos*16.f);
|
||||||
vkBuffer = *nodes;
|
auto [vkBuffer, offset] = VKCTX->VertexPool_Nodes.map(nodes);
|
||||||
|
|
||||||
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
||||||
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
||||||
vkCmdDraw(drawCmd, nodes->getSize() / sizeof(NodeVertexStatic), 1, 0, 0);
|
vkCmdDraw(drawCmd, nodes.VertexCount, 1, offset, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#include "Abstract.hpp"
|
||||||
|
#include "VertexPool.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
У движка есть один текстурный атлас VK_IMAGE_VIEW_TYPE_2D_ARRAY(RGBA_UINT) и к нему Storage с инфой о положении текстур
|
У движка есть один текстурный атлас VK_IMAGE_VIEW_TYPE_2D_ARRAY(RGBA_UINT) и к нему Storage с инфой о положении текстур
|
||||||
@@ -28,6 +29,8 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace LV::Client::VK {
|
namespace LV::Client::VK {
|
||||||
|
|
||||||
struct WorldPCO {
|
struct WorldPCO {
|
||||||
@@ -36,41 +39,6 @@ struct WorldPCO {
|
|||||||
|
|
||||||
static_assert(sizeof(WorldPCO) == 128);
|
static_assert(sizeof(WorldPCO) == 128);
|
||||||
|
|
||||||
/*
|
|
||||||
Воксели рендерятся точками, которые распаковываются в квадратные плоскости
|
|
||||||
|
|
||||||
В чанке по оси 256 вокселей, и 257 позиций вершин (включая дальнюю границу чанка)
|
|
||||||
9 бит на позицию *3 оси = 27 бит
|
|
||||||
Указание материала 16 бит
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct VoxelVertexPoint {
|
|
||||||
uint32_t
|
|
||||||
FX : 9, FY : 9, FZ : 9, // Позиция
|
|
||||||
Place : 3, // Положение распространения xz, xy, zy, и обратные
|
|
||||||
N1 : 1, // Не занято
|
|
||||||
LS : 1, // Масштаб карты освещения (1м/16 или 1м)
|
|
||||||
TX : 8, TY : 8, // Размер+1
|
|
||||||
VoxMtl : 16, // Материал вокселя DefVoxelId_t
|
|
||||||
LU : 14, LV : 14, // Позиция на карте освещения
|
|
||||||
N2 : 2; // Не занято
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Максимальный размер меша 14^3 м от центра ноды
|
|
||||||
Координатное пространство то же, что и у вокселей + 8 позиций с двух сторон
|
|
||||||
Рисуется полигонами
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct NodeVertexStatic {
|
|
||||||
uint32_t
|
|
||||||
FX : 9, FY : 9, FZ : 9, // Позиция 15 -120 ~ 240 360 15 / 16
|
|
||||||
N1 : 4, // Не занято
|
|
||||||
LS : 1, // Масштаб карты освещения (1м/16 или 1м)
|
|
||||||
Tex : 18, // Текстура
|
|
||||||
N2 : 14, // Не занято
|
|
||||||
TU : 16, TV : 16; // UV на текстуре
|
|
||||||
};
|
|
||||||
|
|
||||||
class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
||||||
VK::Vulkan *VkInst = nullptr;
|
VK::Vulkan *VkInst = nullptr;
|
||||||
@@ -87,9 +55,15 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
Buffer TestQuad;
|
Buffer TestQuad;
|
||||||
std::optional<Buffer> TestVoxel;
|
std::optional<Buffer> TestVoxel;
|
||||||
|
|
||||||
|
|
||||||
|
VertexPool<VoxelVertexPoint> VertexPool_Voxels;
|
||||||
|
VertexPool<NodeVertexStatic> VertexPool_Nodes;
|
||||||
|
|
||||||
VulkanContext(Vulkan *vkInst)
|
VulkanContext(Vulkan *vkInst)
|
||||||
: MainTest(vkInst), LightDummy(vkInst),
|
: MainTest(vkInst), LightDummy(vkInst),
|
||||||
TestQuad(vkInst, sizeof(NodeVertexStatic)*6)
|
TestQuad(vkInst, sizeof(NodeVertexStatic)*6),
|
||||||
|
VertexPool_Voxels(vkInst),
|
||||||
|
VertexPool_Nodes(vkInst)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,13 +103,12 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
NodeStaticOpaquePipeline = VK_NULL_HANDLE,
|
NodeStaticOpaquePipeline = VK_NULL_HANDLE,
|
||||||
NodeStaticTransparentPipeline = VK_NULL_HANDLE;
|
NodeStaticTransparentPipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
|
||||||
std::map<BinTextureId_t, uint16_t> ServerToAtlas;
|
std::map<BinTextureId_t, uint16_t> ServerToAtlas;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
std::unordered_map<WorldId_t,
|
std::unordered_map<WorldId_t,
|
||||||
std::unordered_map<Pos::GlobalChunk,
|
std::unordered_map<Pos::GlobalChunk,
|
||||||
std::pair<std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> // Voxels, Nodes
|
std::pair<VertexPool<VoxelVertexPoint>::Pointer, VertexPool<NodeVertexStatic>::Pointer> // Voxels, Nodes
|
||||||
>
|
>
|
||||||
> ChunkVoxelMesh;
|
> ChunkVoxelMesh;
|
||||||
} External;
|
} External;
|
||||||
|
|||||||
Reference in New Issue
Block a user