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
相关产品推荐
相关产品推荐

