使用 IBO 制作动画 - 好还是坏?

Posted

技术标签:

【中文标题】使用 IBO 制作动画 - 好还是坏?【英文标题】:Using IBO for animation - good or bad? 【发布时间】:2012-08-13 17:29:05 【问题描述】:

我只是在看我的动画精灵代码,并得到一些想法。 动画是通过改变 tex 坐标制作的。它有缓冲区对象,它保存当前帧的纹理坐标,当新的帧请求时,新的纹理坐标通过 glBufferData() 进入缓冲区。

如果我们预先计算所有动画帧的纹理坐标,将它们放在 BO 中并创建仅包含我们需要绘制的帧数的索引缓冲区对象

 GLbyte cur_frames = 0; //1,2,3 etc

现在我们需要更新动画,我们只需要更新 1 个字节(而不是 4 /quad vertex count/ * 2 /s, t/ * sizeof(GLfloat) 字节用于我们的 IBO 的带有 glBufferData 的 TRIANGLE_STRIP) 帧的四边形绘制,我们不需要在我们的 BO 初始化后保存任何纹理坐标。

我错过了什么?什么是对比?

编辑:当然,例如,您的顶点数据可能不是 gl_float。

【问题讨论】:

预计算 = 更多的内存使用和更大的缓冲区。没有好坏之分,只是不同。分析您的应用程序,看看是否值得您花时间在此处投资提高性能。只有您知道速度/内存折衷是否适合您。 为什么你甚至需要用这种技术更新任何东西?您只需为 glDrawElements 提供不同的起始索引或使用 BaseVertex 变体。 是的,你说得对,只是忘了。 【参考方案1】:

正如 Tim 所说,这取决于您的应用程序,让我们谈谈一些数字,您提到了 IBO 的 将所有帧的纹理坐标插入到一个 VBO 中,所以让我们来看看各自的影响。

假设一个典型的顶点如下所示:

struct vertex

    float x,y,z; //position
    float tx,ty; //Texture coordinates

我添加了一个 z 组件,但如果您不使用它,或者如果您有更多属性,则计算是相似的。所以很明显这个属性需要 20 个字节。

让我们假设一个简单的精灵:一个四边形,由 2 个三角形组成。在非常幼稚的模式下,您只需发送 2x3 顶点并将 6*20=120 字节发送到 GPU。

在索引中,您知道您实际上只有四个顶点:1,2,3,4 和两个三角形1,2,32,3,4。所以我们向 GPU 发送了两个缓冲区:一个包含 4 个顶点(4*20=80 字节),一个包含三角形索引列表([1,2,3,2,3,4]),假设我们可以在 2 个字节中执行此操作(65535 个索引应该足够了),所以这归结为6*2=12 字节。总共92 字节,我们节省了28 字节或大约23%。另外,在渲染 GPU 时很可能会only process each vertex once in the vertex shader,它也为我们节省了一些处理能力。

所以,现在您想一次为所有动画添加所有纹理坐标。首先要注意的是,索引渲染中的顶点由它的所有属性定义,您不能将其拆分为位置索引和纹理坐标索引。所以如果你想添加额外的纹理坐标,你将不得不重复这些位置。因此,您添加的每个“帧”都会将 80 字节添加到 VBO 并将 12 字节添加到 IBO。假设你有 64 帧,你最终得到64*(80+12)=5888byte。假设您有 1000 个精灵,那么这将变成大约 6MB。这似乎并不算太​​糟糕,但请注意它的缩放速度非常快,每一帧都会增加大小,而且还会增加每个属性(因为它们必须重复)。

那么,它对你有什么好处呢?

    您不必动态地将数据发送到 GPU。请注意,更新整个 VBO 需要发送 80 字节或 640 位。假设您需要以每秒30 帧的速度为每帧1000 sprite 执行此操作,您将获得19200000bps 或19.2Mbps(不包括开销)。这是相当低的(例如 16xPCI-e 可以处理 32Gbps),但如果您有其他带宽问题(例如由于纹理),这可能是值得的。此外,如果您仔细构建您的 VBO(例如,单独的 VBO 或非交错的),您可以将其减少为仅更新纹理部分,在上面的示例中每个精灵只有 16 字节,这可能会进一步减少带宽. 您不必浪费时间计算下一帧位置。但是,这通常只是一些添加,很少有处理纹理边缘的方法。我怀疑你会在这里获得很多 CPU 能力。

最后,您还可以简单地将动画图像分割成许多纹理。我完全不知道它是如何缩放的,但在这种情况下,您甚至不必使用更复杂的顶点属性,您只需为每一帧动画激活另一个纹理。

edit:另一种方法是在采样之前以统一的形式传递帧号并在片段着色器中进行计算。设置单个整数统一应该是一个很大的开销。

【讨论】:

【参考方案2】:

对于现代 GPU,访问/解压缩单个字节不一定比访问整数类型甚至向量(寄存器大小和加载指令等)更快。您可以只节省内存,从而节省内存带宽,但我不希望这与所有其他顶点属性数组访问有很大不同。

我认为,为动画精灵提供帧索引的最快方法是统一,或者如果必须使用一次绘制调用渲染多个精灵,则使用实例化顶点属性数组。使用后者,您可以为固定大小的顶点子序列提供单个索引。 例如,在绘制“sprite-quads”时,您将每 4 个顶点获取一帧索引。 当使用实例渲染时,第三种方法是缓冲区纹理。

我建议使用全局(共享)统一来计算时间/帧索引,这样您就可以在着色器中动态计算动画索引,这不需要您更新索引缓冲区(然后只代表相对精灵之间的动画状态)

【讨论】:

你说了很多关于如何传递帧索引,但不作为如何应用它? 是的。但是如果 int 是“在里面”,它可以用来计算具有 2D 层的纹理数组的索引或 3D 纹理的归一化坐标……我只是不认为这是最棘手的部分那个。

以上是关于使用 IBO 制作动画 - 好还是坏?的主要内容,如果未能解决你的问题,请参考以下文章

“单身”工厂,好还是坏?

复合主键:好还是坏?

匿名实例化语法 - 好还是坏?

强制整个站点使用 HTTPS 的好做法还是坏做法?

使用 MVVM 在 wpf 中使用 Dialogs 的好做法还是坏做法?

退出带有空返回语句的函数是好还是坏?