尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
VulkanSceneGraph学习教程(二十)
第 20 章 后处理效果摘要本章系统介绍了在 Vulkan Scene Graph (VSG) 中实现后处理效果的核心流程。后处理本质上是多通道渲染首先通过离屏 RenderGraph 将场景渲染到纹理然后通过全屏 RenderGraph 采样该纹理利用全屏四边形和自定义片段着色器如模糊、HDR、色调映射进行处理最终输出到屏幕。文章详细阐述了离屏 Framebuffer 的创建、全屏处理 Pass 的构建、以及通过 CommandGraph 串联多个 RenderGraph 以实现正确的执行顺序与资源依赖。同时提供了常见问题的排查思路与解决方案为读者掌握 VSG 后处理技术提供了清晰的实践路径。本章定位模糊、HDR、色调映射等效果都依赖「先把场景渲染到离屏纹理再用全屏四边形采样处理」。这正是第 12 章多RenderGraph串联的用武之地。20.1 本章目标理解后处理的「多通道」本质离屏 → 全屏处理 → 呈现用两个RenderGraph串联实现后处理知道全屏四边形 采样离屏纹理的标准套路。20.2 前置准备第 12 章RenderGraph/CommandGraph已读第 10 章描述符/纹理已读。20.3 多通道管线长什么样场景图 │ RenderGraph A离屏 Framebuffer ▼ 渲染到 colorImage离屏纹理 全屏四边形采样 colorImage │ RenderGraph B窗口 ▼ 后处理 shader → 屏幕关键点RenderGraph A 渲染到离屏Framebuffer不是窗口RenderGraph B 渲染到窗口并用一个全屏四边形采样 A 的输出纹理在片段着色器里做模糊/HDR。20.4 离屏 RenderGraphRenderGraph既可以绑定window渲染到屏幕也可以绑定framebuffer渲染到离屏图像。创建离屏Framebuffer含 color depth 图像后auto offscreenFB createOffscreenFramebuffer(window, extent); // 见下方说明 auto scenePass vsg::RenderGraph::create(offscreenFB); // 渲染到离屏 scenePass-setClearValues(VkClearColorValue{{0.2f, 0.2f, 0.4f, 1.0f}}); auto view vsg::View::create(camera, scenegraph); scenePass-addChild(view);下面是一个完整的createOffscreenFramebuffer工具函数实现包含创建 color 和 depth 的vsg::Image、vsg::ImageView以及vsg::Framebuffer// 创建离屏 Framebuffer含 color 和 depth 附件 vsg::ref_ptrvsg::Framebuffer createOffscreenFramebuffer(vsg::ref_ptrvsg::Window window, VkExtent2D extent) { auto device window-getOrCreateDevice(); auto physicalDevice device-getPhysicalDevice(); // 1. 创建 color 图像作为渲染目标同时可采样 auto colorImage vsg::Image::create(); colorImage-imageType VK_IMAGE_TYPE_2D; colorImage-format VK_FORMAT_R8G8B8A8_UNORM; // 常用 8 位 RGBA colorImage-extent {extent.width, extent.height, 1}; colorImage-mipLevels 1; colorImage-arrayLayers 1; colorImage-samples VK_SAMPLE_COUNT_1_BIT; colorImage-tiling VK_IMAGE_TILING_OPTIMAL; colorImage-usage VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // 关键既能作附件又能被采样 colorImage-initialLayout VK_IMAGE_LAYOUT_UNDEFINED; colorImage-sharingMode VK_SHARING_MODE_EXCLUSIVE; auto colorImageMemory vsg::DeviceMemory::create(device, colorImage-getMemoryRequirements(physicalDevice)); colorImage-bind(colorImageMemory, 0); // 2. 创建 color 图像视图 auto colorImageView vsg::ImageView::create(colorImage, VK_IMAGE_VIEW_TYPE_2D); colorImageView-viewType VK_IMAGE_VIEW_TYPE_2D; colorImageView-format colorImage-format; colorImageView-subresourceRange {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; // 3. 创建 depth 图像深度测试用 auto depthImage vsg::Image::create(); depthImage-imageType VK_IMAGE_TYPE_2D; depthImage-format VK_FORMAT_D32_SFLOAT; // 常用 32 位深度 depthImage-extent {extent.width, extent.height, 1}; depthImage-mipLevels 1; depthImage-arrayLayers 1; depthImage-samples VK_SAMPLE_COUNT_1_BIT; depthImage-tiling VK_IMAGE_TILING_OPTIMAL; depthImage-usage VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; depthImage-initialLayout VK_IMAGE_LAYOUT_UNDEFINED; depthImage-sharingMode VK_SHARING_MODE_EXCLUSIVE; auto depthImageMemory vsg::DeviceMemory::create(device, depthImage-getMemoryRequirements(physicalDevice)); depthImage-bind(depthImageMemory, 0); // 4. 创建 depth 图像视图 auto depthImageView vsg::ImageView::create(depthImage, VK_IMAGE_VIEW_TYPE_2D); depthImageView-viewType VK_IMAGE_VIEW_TYPE_2D; depthImageView-format depthImage-format; depthImageView-subresourceRange {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; // 5. 创建 RenderPass与窗口兼容的简单单次渲染 auto renderPass vsg::createRenderPass(device, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_D32_SFLOAT); // 6. 组装 Framebuffer vsg::ImageViews attachments {colorImageView, depthImageView}; auto framebuffer vsg::Framebuffer::create(renderPass, attachments, extent.width, extent.height, 1); return framebuffer; }关键参数说明VK_FORMAT_R8G8B8A8_UNORMcolor 附件格式8 位 RGBA适合后处理采样。VK_FORMAT_D32_SFLOATdepth 附件格式32 位浮点深度。VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BITcolor 图像必须同时具备「颜色附件」和「可采样」两种用途否则后续全屏 Pass 无法读取。VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BITdepth 图像仅用作深度/模板附件无需采样。extent与窗口或期望的离屏分辨率一致确保附件尺寸匹配。vsg::createRenderPass创建与窗口兼容的 RenderPass确保 color/depth 附件格式正确。使用此函数后offscreenFB即可作为vsg::RenderGraph::create(offscreenFB)的参数将场景渲染到离屏纹理。离屏Framebuffer的创建涉及vsg::Framebuffervsg::Imagevsg::ImageView含 color/depth 附件。其具体构造可封装成工具函数核心是把渲染结果「留」在一张可读的Image上。20.5 全屏处理 Pass第二个RenderGraph渲染到窗口内部只画一个全屏四边形片段着色器采样离屏colorImage// 离屏结果作为纹理DescriptorImage auto input vsg::DescriptorImage::create(vsg::Sampler::create(), offscreenColorImage, 0); // 全屏四边形几何 后处理管线采样 input做模糊/HDR auto postStateGroup vsg::StateGroup::create(); postStateGroup-add(vsg::BindGraphicsPipeline::create(postPipeline)); postStateGroup-add(vsg::BindDescriptorSet::create( VK_PIPELINE_BIND_POINT_GRAPHICS, postPipelineLayout, 0, vsg::Descriptors{input})); postStateGroup-addChild(fullscreenQuad); // 两个三角形覆盖 NDC 全屏 auto presentPass vsg::RenderGraph::create(window); // 渲染到窗口 presentPass-addChild(vsg::View::create(camera2D, postStateGroup));片段着色器模糊示例#version 450 layout(binding 0) uniform sampler2D scene; layout(location 0) in vec2 vUV; layout(location 0) out vec4 outColor; void main() { vec3 sum vec3(0.0); for (int i -2; i 2; i) sum texture(scene, vUV vec2(float(i)*0.002, 0.0)).rgb; outColor vec4(sum / 5.0, 1.0); // 简单横向模糊 }20.6 串联与依赖把两个RenderGraph放进同一个CommandGraph顺序即依赖A 必须先在离屏画完B 才能采样本auto commandGraph vsg::CommandGraph::create(window); commandGraph-addChild(scenePass); // 先离屏场景 commandGraph-addChild(presentPass); // 后全屏后处理 → 屏幕 viewer-assignRecordAndSubmitTaskAndPresentation({commandGraph});VSG 在录制时会按RenderGraph的添加顺序生成命令缓冲并保证屏障/依赖正确如需显式屏障可在RenderGraph间声明依赖。多 Pass如先降采样 → 模糊 → 合成就是继续往CommandGraph里追加RenderGraph。20.7 常见问题现象原因解决后处理全黑离屏纹理没接好 / 采样 binding 错确认DescriptorImage的binding与着色器一致离屏Image可作为采样器读取顺序错乱采到空RenderGraph顺序/依赖未声明先scenePass后presentPass必要时显式依赖性能差全屏 Pass 太重 / 多次拷贝用单个全屏 Pass 串多个效果避免多余中间纹理模糊有缝采样偏移/边界处理处理纹理边界clampToEdge或做多趟模糊20.8 小结后处理 离屏RenderGraph渲染场景到纹理 全屏RenderGraph采样处理 → 屏幕全屏四边形 后处理ShaderSet采样离屏Image多RenderGraph同进一个CommandGraph顺序即依赖可串多趟效果。20.9 延伸阅读与下一章预告第 12 章《RenderGraph 与 CommandGraph》多通道的理论基础第 10 章《描述符与资源绑定》离屏纹理作为DescriptorImage第 26 章《调试技巧》用 RenderDoc 看离屏 Pass 的中间结果。
RELATED

相关推荐

大规模多智能体强化学习:基于均值场子采样的近似纳什均衡求解

大规模多智能体强化学习:基于均值场子采样的近似纳什均衡求解

1. 从单智能体到多智能体:合作博弈中的“最优解”难题在强化学习的圈子里,单智能体任务就像是一个人在玩单机游戏,目标明确,策略清晰。但当我们把场景切换到多智能体环境,特别是合作型任务时,整个问题的复杂…

📅 2026/8/21 7:04:43
UVM 工厂 Factory 与 Override:复用与灵活性的基石

UVM 工厂 Factory 与 Override:复用与灵活性的基石

不改源码,如何改变组件行为? 在验证项目中,我们经常需要在不同的测试用例中改变某个组件的行为。比如,在基础测试中,driver 只产生正常的总线事务;而在错误注入测试中,driver 需要偶尔产生协议违规的事务。如果直接修改 driver 的源代码,不仅会影响其他测试,还会破坏…

📅 2026/8/21 7:04:43
YOLOv4目标检测:核心架构、工程优化与部署实战解析

YOLOv4目标检测:核心架构、工程优化与部署实战解析

1. 项目概述:从YOLOv4看目标检测的“速度与激情” 几年前,当我第一次接触目标检测项目时,面对实时视频流里稍纵即逝的车辆和行人,模型的速度和精度就像鱼和熊掌,总是难以兼得。要么是模型跑得飞快但漏检误检一大堆&…

📅 2026/9/10 5:57:10
MORE NEWS

更多资讯

📰

代码生成器优化策略:提升开发效率的关键方法

1. 代码生成器优化策略概述代码生成器作为现代开发流程中的效率倍增器,已经成为中大型项目的标配工具。从早期的MyBatis Generator到如今流行的MyBatisPlus代码生成器,再到各类框架内置的生成工具(如eladmin代码生成器)&#xff0…

📰

社区论坛小程序源码:微信小程序+Node.js+MySQL完整前后端实现

简介:这是一份功能齐全、页面简洁漂亮的社区论坛小程序源码,包含前端与后端完整实现,适合个人开发者、初创团队以及想快速搭建社区/论坛类小程序的用户。当前社区/论坛类目上线仅需提供企业或单位ICP备案截图,不再要求增值电信业务…

📰

多智能体系统架构设计与优化实战指南

1. 多智能体系统核心架构解析多智能体系统(Multi-Agent System, MAS)作为分布式人工智能的重要分支,其核心在于多个自主智能体通过环境交互实现协同决策。在最新实践中,我们观察到三种典型架构模式:集中式协调架构常见于工业控制系统&#xf…

📰

学习界面开发:认知科学与技术实践指南

1. 为什么我们需要关注学习界面开发?作为一名在UI设计领域摸爬滚打多年的从业者,我见过太多"为了设计而设计"的学习类应用。它们要么堆砌花哨的动效,要么照搬流行设计趋势,却忽略了最核心的问题——如何真正帮助用户专注…

📰

VS Code配置C语言开发环境全指南

1. 为什么选择VS Code作为C语言开发环境? 作为一名长期使用VS Code进行嵌入式开发的工程师,我见证了这款编辑器从单纯的文本工具成长为全功能IDE的历程。对于C语言开发而言,VS Code提供了几个不可替代的优势: 首先是轻量级与高性…

📰

轨迹聚类工程实战:从距离度量到业务标签的全链路解析

简介:这是一份基于Python实现的轨迹聚类项目源码,面向数据挖掘、时空轨迹分析学习者和开发者,可用于从GPS、移动设备定位等轨迹数据中提取运动模式并定位聚类中心。压缩包共7个文件,约998KB,内含4个Python脚本、1个Mar…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬