如何在Vulkan游戏引擎中从帧缓冲读取自定义实体ID数据
Vulkan鼠标拾取:解决片段着色器输出无匹配附件问题
我正在Vulkan游戏引擎中实现鼠标拾取功能,需要从帧缓冲读取存储实体ID的特定附件。目前已成功读取RGBA数据,但片段着色器输出的实体ID没有对应的帧缓冲附件,触发了验证层警告。
片段着色器代码
#version 450 core struct VertexInput { vec4 Color; vec2 TexCoord; float TilingFactor; }; // Inputs layout(location = 0) in VertexInput Input; layout(location = 3) in flat uint in_TexIndex; layout(location = 4) in flat int in_EntityID; layout(binding = 1) uniform sampler2D u_Samplers[10]; // Outputs layout(location = 0) out vec4 o_Color; layout(location = 1) out int o_EntityID; // 需要存储的实体ID void main() { o_EntityID = in_EntityID; o_Color = Input.Color * texture(u_Samplers[in_TexIndex], Input.TexCoord * Input.TilingFactor); }
触发的验证层警告
Validation layer: Validation Warning: [ UNASSIGNED-CoreValidation-Shader-OutputNotConsumed ] Object 0: handle = 0x5dbcf90000000065, type = VK_OBJECT_TYPE_SHADER_MODULE; | MessageID = 0x609a13b | fragment shader writes to output location 1 with no matching attachment
解决思路与步骤
核心问题
警告的本质是片段着色器向location=1输出数据,但当前渲染使用的帧缓冲没有对应位置的颜色附件,导致输出没有接收目标。
1. 创建存储实体ID的图像资源
需要创建一个整数格式的单通道图像,避免实体ID因浮点精度丢失:
- 格式选择:匹配着色器输出类型,用
VK_FORMAT_R32_SINT(对应int类型)或VK_FORMAT_R32_UINT(对应uint类型) - 图像用法:必须包含
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT(作为颜色附件),如果需要CPU读取,加上VK_IMAGE_USAGE_TRANSFER_SRC_BIT - 内存属性:基础需求是
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT(GPU可访问);若要CPU读取,额外添加VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
2. 创建对应图像视图
为上述图像创建图像视图,格式与图像保持一致,视图类型设为VK_IMAGE_VIEW_TYPE_2D。
3. 更新渲染通道(Render Pass)
在渲染通道的颜色附件描述中添加第二个条目:
- 设置
location=1,对应着色器的输出位置 - 格式与图像/图像视图一致
- 加载操作:选
VK_ATTACHMENT_LOAD_OP_CLEAR(每次渲染前清空,避免残留旧ID) - 存储操作:选
VK_ATTACHMENT_STORE_OP_STORE(保留数据供后续读取) - 初始布局:
VK_IMAGE_LAYOUT_UNDEFINED - 最终布局:若要CPU读取,设为
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;若仅GPU内使用,设为VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
同时,在子通道描述的pColorAttachments数组中,添加这个新附件的引用。
4. 更新帧缓冲(Framebuffer)
将新创建的图像视图添加到帧缓冲的附件列表中,位置要和渲染通道中第二个颜色附件的索引对应。
5. 关联图形管线
确保你的图形管线使用的是更新后的渲染通道,管线会自动关联渲染通道的附件与着色器输出位置。
6. 读取实体ID数据
- GPU内读取:可在后续着色器中直接采样这个颜色附件
- CPU读取:发起图像拷贝操作,将GPU内存中的图像数据复制到CPU可见内存,再读取鼠标对应坐标的像素值(注意Vulkan图像坐标原点通常为左上角,需和屏幕坐标做转换)
额外注意事项
- 如果实体ID是无符号整数,需将着色器中的
int改为uint,对应格式切换为VK_FORMAT_R32_UINT - 若使用多采样,图像和附件都要设置对应采样数
- 清空附件时,清除值要设为无效实体ID(比如-1或0),方便区分未渲染区域
内容的提问来源于stack exchange,提问作者ezyn
相关产品推荐
相关产品推荐

