我只是在看我的动画 Sprite 代码,并得到一些想法。
动画是通过改变 tex 坐标制作的。它有缓冲区对象,它保存当前帧纹理坐标,当新帧被请求时,新的纹理坐标通过 glBufferData() 馈入缓冲区。
如果我们预先计算所有动画帧纹理坐标,将它们放入 BO 中并创建仅包含我们需要绘制的帧数的索引缓冲区对象
GLbyte cur_frames = 0; //1,2,3 etc
现在我们需要更新动画,我们只需要更新 1 个字节(而不是 4/quad vertex count/* 2/s, t/* sizeof(GLfloat) bytes for quad drawing with TRIANGLE_STRIP) frame of our IBO with glBufferData,我们不需要在 BO 初始化后保留任何纹理坐标。
我错过了什么?什么是对比?
编辑:当然,您的顶点数据可能不是 gl_float,例如。
最佳答案
正如 Tim 正确指出的那样,这取决于您的应用,让我们谈谈一些数字,您提到了 IBO 和将所有帧的纹理坐标插入到一个 VBO 中,所以让我们看一下每个的影响。
假设一个典型的顶点看起来像这样:
struct vertex
{
float x,y,z; //position
float tx,ty; //Texture coordinates
}
我添加了一个 z 分量,但如果您不使用它,或者如果您有更多属性,计算是相似的。所以很明显这个属性需要20个字节。
让我们假设一个简单的 Sprite :一个由 2 个三角形组成的四边形。在非常简单的模式下,您只需发送 2x3 顶点并将 6*20=120
字节发送到 GPU。
在索引中,您知道实际上只有四个顶点:1,2,3,4
和两个三角形 1,2,3
和 2 ,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 ,它也为我们节省了一些处理能力。
所以,现在您想要一次为所有动画添加所有纹理坐标。首先你要注意的是索引渲染中的顶点是由它的所有属性定义的,你不能将它拆分为位置索引和纹理坐标索引。所以如果你想添加额外的纹理坐标,你将不得不重复这些位置。因此,您添加的每个“帧”都会向 VBO 添加 80
字节,向 IBO 添加 12
字节。假设您有 64 帧,您最终得到 64*(80+12)=5888
字节。假设您有 1000 个 Sprite ,那么这将变成大约 6MB
。这看起来还不错,但请注意它的缩放速度非常快,每一帧都会增加大小,而且每个属性也会增加(因为它们必须重复)。
那么,它给你带来了什么?
- 您不必动态地向 GPU 发送数据。请注意,更新整个 VBO 需要发送
80
字节或640
位。假设您需要以每秒30
帧的速度为每帧1000
个 Sprite 执行此操作,您将达到19200000
bps 或19.2Mbps
(不包括开销)。这是相当低的(例如 16xPCI-e 可以处理32Gbps
),但如果您有其他带宽问题(例如由于纹理),这可能是值得的。此外,如果您仔细构建 VBO(例如,单独的 VBO 或非交错),您可以将其减少为只更新纹理部分,在上面的示例中每个 Sprite 只有16
字节,这可以进一步减少带宽。 - 您不必浪费时间计算下一帧位置。然而,这通常只是一些添加,很少用于处理纹理的边缘。我怀疑您会在这里获得很多 CPU 能力。
最后,您还可以将动画图像简单地拆分为多个纹理。我完全不知道这是如何缩放的,但在这种情况下,您甚至不必使用更复杂的顶点属性,您只需为每个动画帧激活另一个纹理。
编辑:另一种方法可能是在采样之前以统一方式传递帧编号并在片段着色器中进行计算。设置单个整数统一应该是一个很大的开销。
关于opengl - 使用 IBO 制作动画——好还是坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11939295/