使用着色器在OpenGL中绘制精灵表的技巧

3
我正在学习OpenGL,并希望能够从精灵表中绘制一些精灵到屏幕上。我不确定自己是否正在正确操作。
我的目标是像Terraria一样通过瓷砖来构建世界。这意味着我所有用来构建世界的瓷砖都是1x1,但是我可能会在以后添加像2x1、1x2、2x2等实体。
我现在所做的是创建一个名为"Tile"的类,其中包含这个瓷砖的变换矩阵和指向其缓冲区的指针。非常简单:
Tile::Tile(glm::vec2 position, GLuint* vbo)
{
    transformMatrix = glm::translate(transformMatrix, glm::vec3(position, 0.0f));
    buffer = vbo;
}

当我绘制瓦片时,只需绑定缓冲区并更新着色器的UV坐标和顶点位置。之后,我将瓦片的变换矩阵传递给着色器,并使用glDrawElements进行绘制:

glEnableVertexAttribArray(positionAttrib);
glEnableVertexAttribArray(textureAttrib);

for(int i = 0; i < 5; i++) 
{
    glBindBuffer(GL_ARRAY_BUFFER, *tiles[i].buffer);

    glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
    glVertexAttribPointer(textureAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));

    glUniformMatrix4fv(transformMatrixLoc, 1, GL_FALSE, value_ptr(tiles[i].transformMatrix));
    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
}

glDisableVertexAttribArray(positionAttrib);
glDisableVertexAttribArray(textureAttrib);

我能更高效地完成这个任务吗?我正在考虑为1x1的图块设置一个缓冲区,2x1的图块设置另一个缓冲区等等,并且只需要让Tile类包含UVpos和UVsize,然后将它们发送到着色器中,但我不确定该如何实现。

我认为使用一个缓冲区处理1x1和另一个处理2x1听起来会更快。


使用精灵表作为瓷砖的纹理,并指定要使用的表部分,听起来是一个不错的方法。不幸的是,我没有使用GLSL(只用过Cg和HLSL),所以无法帮助你解决如何的问题。你尝试过搜索如何设置着色器参数的示例吗? - Matt Kline
我知道如何在着色器中设置值,它是通过glDrawElements上面的三行完成的。问题是,由于它是基于每个顶点完成的,我需要将4个UV坐标对传递给着色器。我不知道该如何绑定缓冲区,然后发送UV数据。 - Semicolon
1个回答

1
这个能不能更高效一些呢?
我认为你不可能做得更低效了。你为每个四边形绑定了一个完整的缓冲对象,然后上传一个矩阵。对于每个四边形都是如此。
通常瓦片地图绘制(仅限于地图,而不是实体)的方式是构建一个包含可见屏幕瓦片某部分的缓冲对象。空白区域被渲染为透明瓷砖。然后在一个绘制调用中渲染该屏幕区域的所有瓷砖。您为该区域中的所有瓷砖提供一个矩阵。
通常,您会有一些这样的可见区域,以便在它们发生变化时轻松更新该区域的瓷砖。离开屏幕的区域将被重复使用于进入屏幕的区域,因此您需要填充它们以获取新的瓷砖数据。

这就是我为什么在问了。我读了很多教程,但我找到的那些没有使用glBegin的教程只绘制一个面。不过我没有想到可以将更多的东西绑定到一个缓冲区中。谢谢。 - Semicolon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接