Vulkan vkCmdDrawIndexed只使用了VertexBuffer中的第一个值

Vulkan vkCmdDrawIndexed used only first Value from VertexBuffer

本文关键字:第一个 VertexBuffer vkCmdDrawIndexed Vulkan      更新时间:2023-10-16

我正在尝试在Vulkan中实现实例化网格渲染。

我的问题是Vulkan只使用绑定的VertexBuffer中的第一个顶点,并复制所有索引的值。输出RenderDoc:

RenderDoc输出重复顶点输入

这些应该是正确的值{{<inPosition>}、{<inColor>}、{<inTexCoord>}}:

const vkf::Vertex vertices[] = {
{ { -0.2f, -0.5f, 0.0f },{ 1.0f, 0.0f, 0.0f },{ 1.0f, 0.0f } },
{ { 0.5f, -0.5f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f } },
{ { 0.5f, 0.5f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 0.0f, 1.0f } },
{ { -0.5f, 0.5f, 0.0f },{ 1.0f, 1.0f, 1.0f },{ 1.0f, 1.0f } }
};

我已经检查了多次"顶点缓冲区",它包含正确的值。

以下是从我的CommandBuffer创建截取的片段:

vkCmdBindPipeline(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.agents);
VkBuffer vertexBuffers[] = { models.agent.verticesBuffer };
VkBuffer instanceBuffers[] = { m_instanceBuffer.buffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(m_commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindVertexBuffers(m_commandBuffers[i], 1, 1, instanceBuffers, offsets);
vkCmdBindIndexBuffer(m_commandBuffers[i], models.agent.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(m_commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayouts.pipelineLayoutAgent, 0, 1, &descriptorSets.agent, 0, nullptr);
vkCmdDrawIndexed(m_commandBuffers[i], static_cast<uint32_t> (models.agent.indexCount), 5, 0, 0, 0); 

我的第一个假设是我的约束性描述是错误的。但我看不出错误:

bindingDescription = {};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

为什么只使用缓冲区中的第一个值?

编辑:

实例数据:

struct InstanceData
{
glm::vec3 pos;
glm::vec3 rot;
float scale;

static VkVertexInputBindingDescription getBindingDescription()
{
VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = INSTANCING_BIND_ID;
bindingDescription.stride = sizeof(InstanceData);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
return bindingDescription;
}
};

整个VkPipelineVertexInputStateCreateInfo:

std::vector<VkVertexInputBindingDescription> bindingDesciption = {};
std::vector<VkVertexInputAttributeDescription> attributeDescriptions = {};
bindingDesciption = { 
models.agent.bindingDescription,    
InstanceData::getBindingDescription() 
};
attributeDescriptions =
{
vertexInputAttributeDescription(VERTEX_BIND_ID, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vkf::Vertex, pos)),
vertexInputAttributeDescription(VERTEX_BIND_ID, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vkf::Vertex, color)),
vertexInputAttributeDescription(INSTANCING_BIND_ID, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, pos)),
vertexInputAttributeDescription(VERTEX_BIND_ID, 3, VK_FORMAT_R32G32_SFLOAT, offsetof(vkf::Vertex, texCoord))
};
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(bindingDesciption.size());
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
vertexInputInfo.pVertexBindingDescriptions = bindingDesciption.data();
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();

编辑2

#define VERTEX_BIND_ID 0
#define INSTANCING_BIND_ID 1

编辑3:我正在使用VulkanMemoryAllocator。创建暂存缓冲区

size_t vertexBufferSize = sizeof(vkf::Vertex) *_countof(vertices);
createStagingBuffer(vertexBufferSize );
VkBuffer createStagingBuffer(VkDeviceSize size)
{
VkBuffer buffer;
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = size;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_PERSISTENT_MAP_BIT;
VmaAllocationInfo allocInfo = {};
if (vmaCreateBuffer(m_allocator, &bufferInfo, &allocCreateInfo, &buffer, &m_allocation, &allocInfo) != VK_SUCCESS)
{
throw std::runtime_error("failed to create Buffer!");
}
return buffer;
}

复制顶点:

memcpy(mappedStaging, vertices, vertexBufferSize);

创建缓冲区:

createBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY);
VkBuffer createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage vmaUsage)
{
VkBuffer buffer;   
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = vmaUsage;
allocCreateInfo.flags = 0;
VmaAllocationInfo allocInfo;
if (vmaCreateBuffer(m_allocator, &bufferInfo, &allocCreateInfo, &buffer, &m_allocation, &allocInfo) != VK_SUCCESS)
{
throw std::runtime_error("failed to create Buffer!");
}    
return buffer;
}

这就是我如何从暂存转换缓冲区的方式:

copyBuffer(stagingVertexBuffer, verticesBuffer, vertexBufferSize);
void Base::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
{
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkBufferCopy copyRegion = {};
copyRegion.dstOffset = 0;
copyRegion.srcOffset = 0;
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
endSingleTimeCommands(commandBuffer);
}

我检查了好几次数据是否在staging Buffer中,在修改了createBuffer Prozess之后,数据也在verticalsBuffer中。它们正确地存储在那里。

我发现了错误。错误就在这里:

bindingDesciption = { 
models.agent.bindingDescription,    
InstanceData::getBindingDescription() 
};

绑定发生时,models.agent.bindingDescription尚未初始化。因此,VkVertexInputBindingDescription出现故障。models.agent.bindingDescription中填充了VkVertexInputBindingDescription:的标准值

binding = 0
stroke = 0
inputRate = VK_VERTEX_INPUT_RATE_VERTEX