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

Vulkan中片元着色器多输出记录及单独读取代码示例

Vulkan 片元着色器多输出实现方案

Vulkan 中单个片元着色器的多个输出,依靠*多渲染目标(MRT, Multiple Render Targets)*机制实现:着色器中layout(location = N)标记的输出,会和帧缓冲绑定的第N个颜色附件一一对应,每个输出写入独立的附件图像,渲染完成后分别从对应图像读取数据即可。


具体配置步骤

以给出的双输出片元着色器为例,outColor(location=0,vec4类型)、outID(location=1,float类型)的配置流程如下:

  • 配置渲染Pass的多颜色附件
    渲染Pass需要为每个输出定义独立的附件描述,附件格式和着色器输出类型匹配:outColor用VK_FORMAT_R8G8B8A8_UNORM(4通道8位归一化格式),outID用VK_FORMAT_R32_SFLOAT(单通道32位浮点数格式)。子pass中需要按location顺序配置颜色附件引用,和着色器输出点位一一对应。
    // 定义2个颜色附件
    VkAttachmentDescription colorAttachments[2] = {};
    // 附件0:对应location=0的outColor
    colorAttachments[0].format = VK_FORMAT_R8G8B8A8_UNORM;
    colorAttachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    colorAttachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachments[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
    // 附件1:对应location=1的outID
    colorAttachments[1].format = VK_FORMAT_R32_SFLOAT;
    colorAttachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    colorAttachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachments[1].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
    
    // 子pass颜色引用,顺序和location严格对应
    VkAttachmentReference colorRefs[2] = {};
    colorRefs[0].attachment = 0;
    colorRefs[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
    colorRefs[1].attachment = 1;
    colorRefs[1].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
    
    VkSubpassDescription subpass = {};
    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    subpass.colorAttachmentCount = 2; // 关键:声明使用2个颜色附件
    subpass.pColorAttachments = colorRefs;
    
  • 创建帧缓冲绑定对应图像
    分别创建两张和渲染尺寸一致的图像:一张RGBA8格式存储颜色结果,一张R32_SFLOAT格式存储ID结果,为两张图像分别创建图像视图,创建帧缓冲时按附件顺序传入两个视图。
    // 两个图像视图按附件顺序传入
    VkImageView fbAttachments[2] = {colorOutputImageView, idOutputImageView};
    VkFramebufferCreateInfo fbCreateInfo = {};
    fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
    fbCreateInfo.renderPass = renderPass;
    fbCreateInfo.attachmentCount = 2;
    fbCreateInfo.pAttachments = fbAttachments;
    fbCreateInfo.width = renderWidth;
    fbCreateInfo.height = renderHeight;
    fbCreateInfo.layers = 1;
    vkCreateFramebuffer(device, &fbCreateInfo, nullptr, &framebuffer);
    
  • 配置图形管线的颜色混合状态
    图形管线的颜色混合状态需要为每个附件单独配置,双输出场景需要传入2个混合状态结构体,不能只配置单附件。
    VkPipelineColorBlendAttachmentState blendStates[2] = {};
    // 附件0(outColor)写入配置:开启全部RGBA通道写入,关闭混合
    blendStates[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | 
                                    VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    blendStates[0].blendEnable = VK_FALSE;
    // 附件1(outID)写入配置:仅开启R通道写入,关闭混合
    blendStates[1].colorWriteMask = VK_COLOR_COMPONENT_R_BIT;
    blendStates[1].blendEnable = VK_FALSE;
    
    VkPipelineColorBlendStateCreateInfo blendCreateInfo = {};
    blendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    blendCreateInfo.attachmentCount = 2;
    blendCreateInfo.pAttachments = blendStates;
    
  • 分别读取两个输出的内容
    渲染完成后,将两张附件图像的布局切换为传输源,分别拷贝到对应的主机可见缓冲区,映射内存即可读取数据:
    • 读取outColor的逻辑和单输出场景完全一致,图像数据按像素存储为4个8位通道值,尺寸为(width, height, 4)
    • 读取outID时,映射对应缓冲区的内存,按单32位浮点数解析每个像素的值即可
    // 读取outID示例
    float* idDataPtr;
    vkMapMemory(device, idBufferMemory, 0, renderWidth * renderHeight * sizeof(float), 0, (void**)&idDataPtr);
    // 读取坐标(x,y)位置的outID值
    float currentPixelID = idDataPtr[y * renderWidth + x];
    vkUnmapMemory(device, idBufferMemory);
    

注意事项

  • 所有颜色附件的分辨率、采样数必须保持一致,格式可根据输出数据类型灵活调整:如果outID是整数类型,可将附件格式替换为VK_FORMAT_R32_UINT,着色器中对应把outID声明为uint类型即可。
  • 不要尝试把多个输出打包到同一张图像的不同通道,MRT的独立附件设计更灵活,也不会出现格式对齐、精度不匹配的问题。
  • 除颜色附件相关配置外,管线的顶点输入、光栅化、深度测试等其他配置和单输出场景完全一致,不需要额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:18:19