OpenGL 性能问题
Posted
技术标签:
【中文标题】OpenGL 性能问题【英文标题】:OpenGL performance issue 【发布时间】:2012-08-10 13:03:36 【问题描述】:我正在使用 LWJGL 和 Java 1.6 编写 2D RPG。现在,我有一个“World”类,它包含一个 Tile 的 ArrayList(与每个 Tile 的基本代码的接口)和一个 GrassTile 类,它使用 Spritesheet。
当使用即时模式绘制 64x64 GrassTiles 网格时,我得到大约 100 FPS,并通过从 ArrayList 内的每个图块调用 .draw() 方法来完成此操作,该方法绑定了 spritesheet 并绘制了它的某个区域(使用glTexCoord2f())。所以我听说最好使用 VBO,得到一个基本教程并尝试在 .draw() 方法上实现它们。
现在有两个问题:我不知道如何仅将纹理的某个区域绑定到 VBO(整个纹理将只是 glBindTexture())所以我尝试仅将它们与颜色一起使用。 这把我带到了第二个问题:我只有 +20 FPS(总共 120),这并不是我所期望的,所以我想我做错了什么。此外,我在 ArrayList 中迭代时为每个 GrassTile 制作了一个 VBO。我认为这是错误的,因为我可以简单地将所有图块放入一个 FloatBuffer 中。
那么,如何以更好的方式绘制相似的几何图形,以及如何仅将纹理的某个区域绑定到 VBO?
【问题讨论】:
“仅将纹理的特定区域绑定到 VBO”是什么意思。您不将纹理绑定到缓冲区,而是将它们绑定到纹理单元... 好吧,我不知道,对不起。我的意思是:glTexCoord2f() 的 vbo 等价物是什么? opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml 哦,所以我可以像对顶点或颜色那样做? 是的。顶点属性是通用的......呃,我不想骗你。无论如何,现代 OpenGL (>= 3.3) 将允许您这样做。 【参考方案1】:那么,我怎样才能以更好的方式绘制相似的几何图形...
就像@Ian Mallett 描述的那样;将所有顶点数据放入一个 single 顶点缓冲区对象。这使得一次调用即可呈现您的地图。 如果您的地图变大 1000 倍,您可能希望实施一个仅绘制屏幕上显示的顶点的相机解决方案,但如果您计划显着更大的地图。
...我怎样才能只将纹理的某个区域绑定到 VBO?
您只能绑定整个纹理。您必须指向到要映射的纹理的某个区域。
每个纹理坐标都与特定的顶点相关。每个图块都与四个顶点有关。您游戏中的常见图块将共享相同的纹理,因此称为“图块地图”。好好利用它。将所有瓷砖纹理放在纹理表中并绑定该纹理表。 对于您创建的每个新“图块”,检查该区域是指空气、草地还是地面,然后指向与您想要的纹理对应的部分。
假设您的纹理区域(以像素为单位)为 100x100。地面区域是从左下角算起的 15x15。按照上面的逻辑解释下面显示的示例代码:
// The vertexData array simply contains information
// about a tile's four vertices (or six
// vertices if you draw using GL_TRIANGLES).
mVertexBuffer.put(0, vertexData[0]);
mVertexBuffer.put(1, vertex[1]);
mVertexBuffer.put(2, vertex[2]);
mVertexBuffer.put(3, vertex[3]);
mVertexBuffer.put(4, vertex[4]);
mVertexBuffer.put(5, vertex[5]);
mVertexBuffer.put(6, vertex[6]);
mVertexBuffer.put(7, vertex[7]);
mVertexBuffer.put(8, vertex[8]);
mVertexBuffer.put(9, vertex[9]);
mVertexBuffer.put(10, vertex[10]);
mVertexBuffer.put(11, vertex[11]);
if (tileIsGround)
mTextureCoordBuffer.put(0, 0.0f);
mTextureCoordBuffer.put(1, 0.0f);
mTextureCoordBuffer.put(2, 0.15f);
mTextureCoordBuffer.put(3, 0.0f);
mTextureCoordBuffer.put(4, 0.15f);
mTextureCoordBuffer.put(5, 0.15f);
mTextureCoordBuffer.put(6, 0.15f);
mTextureCoordBuffer.put(7, 0.0f);
else /* Other texture coordinates. */
您实际上编写了解决方案。唯一的区别是您应该将纹理坐标数据上传到 GPU。
【讨论】:
【参考方案2】:这是关键:
我正在为每个 GrassTile 制作一个 VBO,同时在 ArrayList 中进行迭代。
不要这样做。您制作一次 VBO,然后在必要时对其进行更新。制作纹理、VBO、着色器是 OpenGL 最慢的使用方法——难怪你会遇到帧率问题——你要这样做 O(n) 次,每一帧。
我认为这有点不对,因为我不能['t?] 简单地将所有图块扔到一个 FloatBuffer 中。
只有在批量绘制调用时才能获得性能。这意味着当您绘制图块时,您应该使用一个 VBO一次绘制所有个。
//Initialize
Make a single VBO (or two: one for vertex, one for texture
coordinates, whatever--the key point is O(1) VBOs).
Fill your VBO with ALL of your tiles' data.
//Main loop
while (true)
Draw the VBO with a single draw call,
thus drawing all your tiles all at once.
【讨论】:
以上是关于OpenGL 性能问题的主要内容,如果未能解决你的问题,请参考以下文章