2012-08-13 42 views
2

我只是看着我的动画精灵代码,并得到一些想法。
动画是通过改变tex coords来完成的。它有缓冲区对象,它保存当前帧纹理坐标,当请求新帧时,新的纹理坐标在缓冲区中输入glBufferData()使用IBO进行动画 - 好还是坏?

而如果我们预先计算所有动画帧质地COORDS,把它们放在一个BO,只需数帧,这是我们需要绘制

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

那么现在,我们需要创建索引缓冲区对象为了更新动画,我们需要的是更新1字节(而不是4/四顶点计数/* 2/s,t/* sizeof(GLfloat)字节用于带有TRIANGLE_STRIP的四边形绘图)我们的IBO框架使用glBufferData,在我们的BO初始化之后,我们不需要保存任何纹理坐标。

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

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

+3

预计算=更多的内存使用量和更大的缓冲区。它不好或不好,它只是*不同*。分析您的应用,看看是否值得花时间在这里投资更高的性能。只有你知道速度/记忆权衡是否适合你。 – Tim 2012-08-13 17:41:47

+1

为什么你甚至需要用这种技术来更新任何东西?您只需为['glDrawElements'](http://www.opengl.org/wiki/GLAPI/glDrawElements)提供不同的起始索引或使用['BaseVertex'](http://www.opengl.org/wiki/GLAPI/glDrawElementsBaseVertex)变体。 – KillianDS 2012-08-13 19:07:27

+0

是的,没错。 – Aristarhys 2012-08-13 19:45:45

回答

1

蒂姆正确地指出,这取决于你的应用程序,让我们来谈谈一些数字,你提到的所有帧到一个VBO两个国际文凭组织插入纹理坐标,所以让我们来看看各的影响。

假设一个典型的顶点看起来是这样的:

struct vertex 
{ 
    float x,y,z; //position 
    float tx,ty; //Texture coordinates 
} 

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

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

Triangulated quad

在自带的索引,你知道你有实际只有四个顶点: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,它也为我们节省了一些处理能力。

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

那么,它会给你带来什么?

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

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

编辑:另一种方法可以是在统一中传递帧号并在采样之前在片段着色器中进行计算。设置一个整数统一应该是那么多开销。

1

对于现代GPU,访问/解包单个字节不一定比访问整数类型或甚至向量(寄存器大小&加载指令等)更快。你可以节省内存,从而节省内存带宽,但我不认为这会给所有其他顶点属性数组访问带来很大的差异。

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

我推荐一个用于时间/帧索引计算的全局(共享)统一,因此您可以在着色器中动态计算动画索引,而不需要您更新索引缓冲区(然后它仅代表在精灵之间的相对动画状态)

+0

你说了很多关于如何传递帧索引,但不是如何应用它? – KillianDS 2012-08-13 23:20:32

+0

是的。但是,如果int是'在那里',它可以用来计算具有2D图层的纹理数组的索引或3D纹理的归一化坐标......我只是不认为这是所有的棘手部分那。 – Sam 2012-08-13 23:36:55