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

LWJGL Vulkan添加第二个顶点缓冲区后无画面显示问题求助

问题分析与解决方案

看起来你在拆分顶点缓冲区时踩了几个常见的Vulkan坑,我来帮你逐一排查:

1. 绑定描述对象创建错误(最关键)

你代码里用VkVertexInputAttributeDescription.calloc(2)来创建绑定描述的缓冲区,这完全错了!绑定描述应该用VkVertexInputBindingDescription.calloc(2),这两个是不同的结构体,类型不匹配会导致Vulkan无法正确解析你的顶点输入设置,这大概率是画面消失的核心原因。

2. 绑定描述的赋值方式错误

你的链式调用写法会覆盖第一个绑定的设置:

// 错误写法:链式调用返回的是同一个对象,binding(1)会覆盖之前的binding(0)
bindingDescriptor.binding(0).stride(2 * 4).inputRate(...).binding(1)...

正确的做法是分别操作缓冲区里的每个元素:

VkVertexInputBindingDescription.Buffer bindingDescriptor = VkVertexInputBindingDescription.calloc(2);
// 设置位置缓冲区的绑定(binding=0)
bindingDescriptor.get(0)
    .binding(0)
    .stride(2 * 4) // vec2占8字节
    .inputRate(VK_VERTEX_INPUT_RATE_VERTEX);
// 设置颜色缓冲区的绑定(binding=1)
bindingDescriptor.get(1)
    .binding(1)
    .stride(3 * 4) // vec3占12字节
    .inputRate(VK_VERTEX_INPUT_RATE_VERTEX);
// 一定要rewind,让缓冲区指针回到起始位置,否则Vulkan读不到正确的数据
bindingDescriptor.rewind();

3. 属性描述的收尾工作

你的属性描述代码大致正确,但同样要记得调用rewind()重置缓冲区位置,确保Vulkan能读取到两个属性的设置:

VkVertexInputAttributeDescription.Buffer attributeDescription = VkVertexInputAttributeDescription.calloc(2);
// 位置属性(location=0,绑定到binding=0)
attributeDescription.get(0)
    .binding(0)
    .location(0)
    .format(VK_FORMAT_R32G32_SFLOAT)
    .offset(0);
// 颜色属性(location=1,绑定到binding=1)
attributeDescription.get(1)
    .binding(1)
    .location(1)
    .format(VK_FORMAT_R32G32B32_SFLOAT)
    .offset(0);
// 重置缓冲区指针
attributeDescription.rewind();

4. 管线状态要正确传入新的顶点输入设置

创建管线时,必须把这两个绑定描述和属性描述都传入VkPipelineVertexInputStateCreateInfo,不能只传原来的单缓冲区设置:

VkPipelineVertexInputStateCreateInfo vertexInputInfo = VkPipelineVertexInputStateCreateInfo.calloc();
vertexInputInfo.sType(VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
// 传入绑定描述的数量和缓冲区
vertexInputInfo.vertexBindingDescriptionCount(bindingDescriptor.remaining());
vertexInputInfo.pVertexBindingDescriptions(bindingDescriptor);
// 传入属性描述的数量和缓冲区
vertexInputInfo.vertexAttributeDescriptionCount(attributeDescription.remaining());
vertexInputInfo.pVertexAttributeDescriptions(attributeDescription);

5. 检查第二个缓冲区的完整性

除了绑定,还要确保你的colorBuf是完全有效的:

  • 创建缓冲区时,必须包含VK_BUFFER_USAGE_VERTEX_BUFFER_BIT使用标志
  • 内存分配时,属性要正确(如果是主机写入数据,需要VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
  • 颜色数据已经正确复制到缓冲区中(比如用vkMapMemory写入,或者通过staging buffer复制)

6. 着色器要对应修改

顶点着色器必须接收两个输入变量,location要和属性描述里的一致:

#version 450
layout(location = 0) in vec2 inPosition; // 对应binding=0,location=0
layout(location = 1) in vec3 inColor;    // 对应binding=1,location=1

layout(location = 0) out vec3 fragColor;

void main() {
    gl_Position = vec4(inPosition, 0.0, 1.0);
    fragColor = inColor;
}

7. 命令缓冲区绑定的小细节

你的vkCmdBindVertexBuffers代码看起来没问题,但记得给offsets和pBuffers调用rewind(),确保缓冲区指针在起始位置:

LongBuffer offsets = memAllocLong(2);
offsets.put(0, 0L);
offsets.put(1, 0L);
offsets.rewind();

LongBuffer pBuffers = memAllocLong(2);
pBuffers.put(0, verticesBuf);
pBuffers.put(1, colorBuf);
pBuffers.rewind();

vkCmdBindVertexBuffers(renderCommandBuffers[i], 0, pBuffers, offsets);

按照上面的步骤修正后,应该就能正常显示彩色三角形了。多个顶点缓冲区的使用其实没有特别复杂的要求,核心就是保证绑定描述、属性描述、管线设置、缓冲区创建、着色器输入这几个环节完全匹配,任何一环出错都会导致渲染失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:44:56