c++ - 哪种方法最适合使用 Vulkan API 实现粒子着色器?
问题描述
我正在实现粒子着色器,这意味着为每个矩形绘制大量具有唯一数据的矩形。现在我看到了不同的方法来做到这一点。
方式一:
- 对所有粒子使用一个统一的缓冲区
- 在绘图开始时执行单个 vkCmdBindDescriptorSets
- 调用单个 vkCmdDraw 实例数等于粒子数
- 在顶点着色器中使用仅由单个数组组成的统一结构:
struct Particle
{
//...
};
layout(binding = 0) uniform ParticleUniformBufferObject
{
Particle particles[MAX_PARTICLES_TO_DRAW];
} ubo;
- 然后在绘图时使用 glsl 变量来访问统一数据
vec3 particlePosition = ubo.particles[gl_InstanceID].position;
方式二:
- 对所有粒子使用一个统一的缓冲区
- 使用动态偏移为每个粒子做 vkCmdBindDescriptorSets
- 对实例计数为 1 的每个粒子执行 vkCmdDraw
- 在没有数组的情况下以通用方式访问顶点着色器中的缓冲区数据
方式3:
通过顶点输入完成所有操作,无需任何对象统一。可能会有很多不必要的数据开销。在这种情况下,顶点缓冲区应该在每一帧更新。
我的问题 - 在性能方面哪种方式更好?
或者您是否看到了另一种使用 Vulkan API 进行粒子渲染的好方法?
解决方案
另一种方法是使用间接绘图:vkCmdDrawIndirect
. 如果您只能在 GPU 上修改粒子,那么这种方法可能会获得回报。如果您需要动画/修改/等。它们在 CPU 上,那么间接绘图将无济于事。
就您的粒子数据而言,您可以将它们存储在VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
缓冲区中,在计算着色器通道中修改它们,并使用间接绘制调用来渲染它们。要访问粒子的数据,您必须使用GLSL
's built-in gl_DrawID
。
一般来说,就性能而言,无法判断哪种方式比另一种方式更好。这取决于很多因素:你将如何修改粒子,它们依赖什么,粒子数量,使用的 GPU 等等。如果你真的想知道,你必须实现所有方法并测量.
如果您要执行后者,请分享您的结果并描述您的设置!像这样的东西总是很有趣。
推荐阅读
- android - Flutter应用中点击关闭App的通知时,如何打开应用并调用首页函数?
- git - 樱桃采摘到多个分支机构
- php - 如何减少 TTFB(到第一个字节的时间)响应?
- delphi - RAD Studio:启动 IDE 时出错。如何纠正这个?
- apache-spark-sql - Spark 创建的用于从 S3 读取输入表的任务
- azure-functions - IDurableOrchestrationContext.SetCustomStatus 不会立即更新状态
- ruby-on-rails - 通过控制台访问翻译表
- reactjs - 改变 a 的背景颜色与 useRef 反应
- nginx - Nginx Lua 扩展读取多部分形式的正文,使其保持完整(代理)
- rust - 使用 serde 将枚举变量的名称作为字符串获取