0

我正在使用 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?

4

2 回答 2

2

这是关键:

我在 ArrayList 中迭代时为每个 GrassTile 制作一个 VBO。

不要这样做。您制作一次 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.
}
于 2012-08-10T21:05:22.170 回答
2

那么,我怎样才能以更好的方式绘制相似的几何图形......

就像@Ian Mallett 描述的那样;将所有顶点数据放入单个顶点缓冲区对象中。这使得一次调用即可呈现您的地图。如果您的地图变大 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。

于 2012-08-11T15:47:29.200 回答