目前我正在使用即时模式进行绘图,但显然这对于除了最简单的场景之外的任何东西都太慢了。
我不同意。除非您要绘制 很多 个图块(每帧数万个),否则立即模式应该适合您。
关键是你必须做的事情才能获得良好的性能:纹理图集。您的所有图块都应存储在单个纹理中。渲染时,您使用纹理坐标从该纹理中拉出不同的图块。所以如果这是你的渲染循环现在的样子:
for(tile in tileList) //Pseudocode. Not actual C++
{
glBindTexture(GL_TEXTURE_2D, tile.texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2fv(tile.lowerLeft);
glTexCoord2f(0.0f, 1.0f);
glVertex2fv(tile.upperLeft);
glTexCoord2f(1.0f, 1.0f);
glVertex2fv(tile.upperRight);
glTexCoord2f(1.0f, 0.0f);
glVertex2fv(tile.lowerRight);
glEnd();
}
你可以把它变成这样:
glBindTexture(GL_TEXTURE_2D, allTilesTexture);
glBegin(GL_QUADS);
for(tile in tileList) //Still pseudocode.
{
glTexCoord2f(tile.texCoord.lowerLeft);
glVertex2fv(tile.lowerLeft);
glTexCoord2f(tile.texCoord.upperLeft);
glVertex2fv(tile.upperLeft);
glTexCoord2f(tile.texCoord.upperRight);
glVertex2fv(tile.upperRight);
glTexCoord2f(tile.texCoord.lowerRight);
glVertex2fv(tile.lowerRight);
}
glEnd();
如果您已经在使用纹理图集但仍未获得可接受的性能,那么您可以继续使用缓冲对象等。但是,如果您不先执行此操作,您将不会从缓冲区对象中获得任何更好的性能。
如果您的所有图块都无法放入单个纹理中,那么您将需要执行以下两项操作之一:使用多个纹理(在一个 glBegin/glEnd 对中为每个纹理渲染尽可能多的图块),或使用纹理数组。纹理数组仅在 OpenGL 3.0 级别的硬件中可用。这意味着任何 Radeon HDxxxx 或 GeForce 8xxxx 或更高版本。
您提到您有时会在图块上渲染“特征”。这些功能可能使用混合和与常规图块不同的 glTexEnv 模式。在这种情况下,您需要想办法将相似的特征组合成一个 glBegin/glEnd 对。
正如您可能从中了解到的,性能的关键是尽量减少调用 glBindTexture 和 glBegin/glEnd 的次数。在每个 glBegin/glEnd 中做尽可能多的工作。
如果您希望继续使用基于缓冲区的方法(并且只有在纹理图集方法没有使您的性能达到标准时才应该打扰),这相当简单。将所有图块“块”放入单个缓冲区对象中。不要为每个人做一个缓冲区;没有真正的理由这样做,并且 40x40 瓦片的顶点数据只有 12,800 字节。您可以将 81 个这样的块放在一个 1MB 的缓冲区中。这样,您只需为您的地形调用 glBindBuffer。这又可以节省您的性能。
我需要更多地了解这些“功能”,您有时会使用这些“功能”来建议优化它们的方法。但至于动态缓冲区,我不担心。只需使用 glBufferSubData 来更新有问题的缓冲区部分。如果事实证明这很慢,那么您可以使用多种选项来加快速度。但除非您知道这是必要的,否则您不应该打扰,因为它们很复杂。
精灵可能是从缓冲区对象方法中受益的绝对最少的东西。与立即模式相比,它确实没有什么好处。即使您要渲染数百个,每个都将有自己的转换矩阵。这意味着每个都必须是一个单独的绘图调用。所以也可以是glBegin/glEnd。