You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vulkan顶点缓冲区渲染三角形与预期顶点不符求助

问题排查请求

此前通过gl_VertexIndex可以正常渲染三角形,改用顶点缓冲区实现后,渲染出的三角形形态异常。以下是相关代码,请帮忙排查原因。

缓冲区创建与更新代码

VulkanBuffer createVulkanBuffer(VulkanContext* context, uint32_t size) {
    VulkanBuffer output = {};

    VkBufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
    createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; // i
    createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    createInfo.size = size;

    vkCreateBuffer(context->device, &createInfo, nullptr, &output.buffer);

    VkBufferMemoryRequirementsInfo2 requirementsInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 };
    requirementsInfo.buffer = output.buffer;

    VkMemoryRequirements2 memoryRequirements = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 };
    vkGetBufferMemoryRequirements2(context->device, &requirementsInfo, &memoryRequirements);

    VkPhysicalDeviceMemoryProperties2 memoryProperties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 };
    vkGetPhysicalDeviceMemoryProperties2(context->physicalDevice, &memoryProperties);

    int32_t memoryTypeIndex = findMemoryTypeIndex(&memoryProperties.memoryProperties, memoryRequirements.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

    VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
    allocInfo.allocationSize = memoryRequirements.memoryRequirements.size;
    allocInfo.memoryTypeIndex = memoryTypeIndex;

    vkAllocateMemory(context->device, &allocInfo, nullptr, &output.deviceMemory);

    VkBindBufferMemoryInfo memoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO };
    memoryInfo.buffer = output.buffer;
    memoryInfo.memory = output.deviceMemory;
    memoryInfo.memoryOffset = 0;
    vkBindBufferMemory2(context->device, 1, &memoryInfo);
    
    return output;
}

void updateBuffer(VulkanContext* context, VulkanBuffer* buffer, void* data, uint32_t sizeOfData) {
    void* pData;
    vkMapMemory(context->device, buffer->deviceMemory, 0, sizeOfData, 0, &pData);
    memcpy(pData, data, static_cast<size_t>(sizeOfData));
    vkUnmapMemory(context->device, buffer->deviceMemory);
}

三角形顶点数据

mathfu是仅头文件的数学库。

std::vector<mathfu::vec3> createTriangle2() {
    std::vector<mathfu::vec3> vertices;
    vertices.resize(3);

    vertices[0] = mathfu::vec3(-1.f, -1.f, 0.f);
    vertices[1] = mathfu::vec3(1.f, -1.f, 0.f);
    vertices[2] = mathfu::vec3(0.f, 1.f, 0.f);

    return vertices;
}

管线创建用顶点描述符

VulkanVertexDescriptor createVertexDescriptor(uint32_t stride) {
    VulkanVertexDescriptor descriptor = {};
    descriptor.bindingDescriptors.resize(1);
    descriptor.attributeDescriptors.resize(1);

    descriptor.bindingDescriptors[0].binding = 0;
    descriptor.bindingDescriptors[0].stride = stride;
    descriptor.bindingDescriptors[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

    descriptor.attributeDescriptors[0].binding = 0;
    descriptor.attributeDescriptors[0].location = 0;
    descriptor.attributeDescriptors[0].offset = 0;
    descriptor.attributeDescriptors[0].format = VK_FORMAT_R32G32B32_SFLOAT;

    return descriptor;
}

函数调用代码

VkViewport viewport = { 0.f, (float)swapchain.height, (float)swapchain.width, -(float)swapchain.height, 0.f, 0.f };

// vertex data
auto triangle = createTriangle2();
uint32_t vsize = sizeof(mathfu::vec3);
uint32_t sizeOfTriangle = vsize * triangle.size();
VulkanBuffer buffer = createVulkanBuffer(context, sizeOfTriangle);
updateBuffer(context, &buffer, triangle.data(), sizeOfTriangle);

VulkanVertexDescriptor descriptor = createVertexDescriptor(vsize);
VulkanPipeline pipeline = createGraphicsPipeline(context, renderpass, viewport, "../assets/shaders/spv/triangle_vert.spv", "../assets/shaders/spv/triangle_frag.spv", descriptor);

顶点与片段着色器

#version 460
layout(location = 0) in vec3 position;

layout(location = 0) out vec3 color;

vec3 positions[3] = vec3[] (
vec3(-1.0, -1.0, 0.0),
vec3(1.0, -1.0, 0.0),
vec3(0.0, 1.0, 0.0)
);

void main() {
gl_Position = vec4(position.xyz * 0.5, 1.0);
color = abs(position.xyz);
//gl_Position = vec4(positions[gl_VertexIndex].xyz, 1.0);
}

#version 460
layout(location = 0) in vec3 color;
layout(location = 0) out vec4 finalColor;

void main() {
finalColor = vec4(color, 1.0);
}

核心排查方向

  1. Viewport翻转问题:当前Viewport设置为{0.f, (float)swapchain.height, (float)swapchain.width, -(float)swapchain.height, 0.f, 0.f},Y轴起始点在Swapchain底部且高度为负,会导致画面垂直翻转。之前用gl_VertexIndex时着色器硬编码顶点,翻转后视觉上兼容,现在用缓冲区顶点后,翻转会直接导致三角形形态扭曲。
  2. 顶点内存对齐问题:确认mathfu::vec3的内存布局是否与VK_FORMAT_R32G32B32_SFLOAT完全匹配——是否是连续的三个32位浮点数,无额外padding。部分数学库会为内存对齐在vec3后追加一个float,导致stride计算错误,顶点数据读取错位。
  3. 绘制命令参数错误:检查绘制调用时是否传入了正确的顶点数量(应为3),若误用索引绘制且索引缓冲区异常,或顶点数传递错误,也会导致渲染异常。
  4. 缓冲区内存可见性:虽然使用了VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,部分驱动仍需显式调用vkFlushMappedMemoryRanges确保主机写入的数据被设备可见,可尝试添加该操作验证。

内容的提问来源于stack exchange,提问作者Miso_Soup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:07:41