这个系列文章我们来介绍一位海外工程师如何探索 Vulkan 音视频技术,对于想要开始学习音视频技术的朋友,这些文章是份不错的入门资料,本篇介绍 Vulkan 高级渲染技术。
——来自公众号“关键帧Keyframe”的分享
Vulkan 对图形管线的显式控制使开发者能够实现以前难以实现或效率低下的复杂渲染技术。本文探讨了 SaschaWillems/Vulkan 仓库中实现的几种高级渲染技术,展示了如何利用 Vulkan 的功能创建令人惊叹的视觉效果。
1、辉光(Bloom)效果
辉光是一种后处理效果,模拟场景中明亮区域如何发光或渗入较暗区域。这种技术广泛用于游戏和视觉应用中,为光源和反射表面创造强度和真实感。
该仓库中的辉光实现使用可分离的双通道全屏模糊方法,比单通道模糊更高效,因为它需要更少的纹理采样即可获得相同的质量。
1.1、实现概述
辉光效果通过多个渲染通道实现:
- 辉光通道:首先,将模型的发光部分渲染到离屏帧缓冲区
- 垂直模糊通道:然后对辉光纹理应用垂直模糊
- 水平模糊通道:最后,对垂直模糊的纹理应用水平模糊,并与主场景合成
/*
本示例中使用的模糊方法是多通道的,首先渲染垂直模糊,然后渲染水平模糊
虽然可以单通道模糊,但这种方法被广泛使用,因为它需要更少的采样来生成模糊
*/
来源:bloom.cpp#L339-L341
1.2、帧缓冲区设置
该实现使用具有特定颜色附件的离屏帧缓冲区:
// 离屏帧缓冲区属性
#define FB_DIM 256
#define FB_COLOR_FORMAT VK_FORMAT_R8G8B8A8_UNORM
来源:bloom.cpp#L13-L15
帧缓冲区同时创建颜色和深度附件,使其能够作为完整的渲染目标:
// 我们将直接从颜色附件采样
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
来源:bloom.cpp#L163
1.3、渲染通道流程
辉光效果遵循以下顺序:
- 第一渲染通道:将模型的发光部分(单独的网格)渲染到离屏帧缓冲区
- 第二渲染通道:对辉光纹理应用垂直模糊
- 第三渲染通道:渲染主场景并对垂直模糊的纹理应用水平模糊
/*
第一渲染通道:将模型的发光部分渲染到离屏帧缓冲区
*/
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.glowPass);
models.ufoGlow.draw(drawCmdBuffers[i]);
vkCmdEndRenderPass(drawCmdBuffers[i]);
来源:bloom.cpp#L365-L376
2、屏幕空间环境光遮蔽(SSAO)
屏幕空间环境光遮蔽是一种渲染技术,近似于环境光能够到达场景中每个点的程度。它通过使缝隙、角落和彼此靠近的表面变暗来增加真实的接触阴影和深度感知。
2.1、SSAO 实现概述
SSAO 技术涉及几个阶段:
- G-Buffer 通道:将场景几何体渲染到多个渲染目标(MRT),存储位置、法线和反照率
- SSAO 通道:使用 G-Buffer 数据计算环境光遮蔽
- 模糊通道:对 SSAO 结果应用模糊以减少噪声
- 合成通道:将 SSAO 结果与主场景合成
#define SSAO_KERNEL_SIZE 64
#define SSAO_RADIUS 0.3f
来源:ssao.cpp#L12-L13
2.2、G-Buffer 创建
第一步是创建一个包含 SSAO 计算所需所有信息的 G-Buffer:
struct Offscreen : public FrameBuffer {
FrameBufferAttachment position, normal, albedo, depth;
} offscreen;
来源:ssao.cpp#L108-L110
每个附件都使用适当的使用标志创建:
// 我们将直接从颜色附件采样
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
来源:ssao.cpp#L204
2.3、SSAO 渲染通道
SSAO 技术按顺序使用多个渲染通道:
/*
第一通道:使用 MRT 填充 G-Buffer 组件(位置+深度、法线、反照率)
*/
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.offscreen);
scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayouts.gBuffer);
vkCmdEndRenderPass(drawCmdBuffers[i]);
来源:ssao.cpp#L517-L534
填充 G-Buffer 后,SSAO 通道计算环境光遮蔽:
/*
第二通道:SSAO 生成
*/
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ssao);
vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);
来源:ssao.cpp#L537-L561
最后,对模糊通道应用模糊以减少 SSAO 结果中的噪声:
/*
第三通道:SSAO 模糊
*/
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ssaoBlur);
vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);
来源:ssao.cpp#L563-L583
3、其他高级技术
该仓库还包括许多其他高级渲染技术:
3.1、延迟渲染
延迟渲染是一种技术,其中几何信息首先渲染到 G-Buffer,然后使用存储的几何数据在单独的通道中执行光照计算。这种方法对于具有许多动态光源的场景是高效的。
3.2、基于物理的渲染(PBR)
PBR 以物理准确的方式模拟光与表面的相互作用。该仓库包括几个 PBR 示例:
pbrbasic:基本 PBR 实现pbribl:基于图像光照的 PBRpbrtexture:带有纹理贴图的 PBR
3.3、阴影映射技术
高级阴影映射技术包括:
shadowmapping:基本阴影映射shadowmappingcascade:用于大型室外场景的分级阴影贴图shadowmappingomni:用于点光源的全向阴影贴图
3.4、后处理效果
各种后处理效果展示了高级着色器技术:
radialblur:用于景深或运动效果的径向模糊ssao:用于真实阴影的屏幕空间环境光遮蔽bloom:明亮光源的发光效果
4、性能考虑
在 Vulkan 中实现高级渲染技术时,请考虑以下性能方面:
- 渲染通道优化:最小化渲染通道数量,并在可能的情况下使用子通道
- 内存管理:尽可能重用帧缓冲区和附件
- 同步:使用适当的同步原语以避免管线停滞
- 着色器优化:编写高效的着色器,最小化纹理采样和分支
/*
注意:渲染通道之间不需要显式同步,因为这是通过子通道依赖关系隐式完成的
*/
来源:bloom.cpp#L396-L398
5、结论
SaschaWillems/Vulkan 仓库提供了在 Vulkan 中实现的高级渲染技术的优秀示例。这些示例展示了如何利用 Vulkan 的功能创建复杂的视觉效果,同时保持良好的性能。
通过学习这些实现,开发者可以了解:
- 如何构建复杂的渲染管线
- 高效的离屏渲染技术
- 后处理效果的方法
- Vulkan 资源管理的最佳实践
这些示例既可作为学习资源,也可作为在你自己的 Vulkan 应用程序中实现这些技术的起点。
学习和提升音视频开发技术,推荐你加入我们的知识星球:【关键帧的音视频开发圈】

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。