使用OpenGL的2D精灵动画技术

2D Sprite animation techniques with OpenGL

本文关键字:动画 技术 精灵 2D OpenGL 使用      更新时间:2023-10-16

我目前正在尝试使用 OpenGL 4 设置一个 2D 精灵动画。例如,我设计了一个与Gimp一起平稳旋转的球。大约有 32 帧(4 行 8 帧)。

我的目标是在 2D 纹理中创建精灵图集,并将我的精灵数据存储在缓冲区 (VBO) 中。我的精灵矩形总是相同的(即 rect(0,0,32,32) ),但每次帧索引递增时,我的纹理坐标都会改变。

我想知道如何修改坐标。

  1. 由于精灵图块存储在几行上,如果看起来很难在着色器中管理它。
  2. 使用 glBufferSubData() 修改缓冲区内的精灵纹理坐标?

我花了很多时间在OpenGL 1.x上。几个月前我回到OpenGL,我意识到很多事情都发生了变化。不过,我会尝试几种选择,但欢迎您的建议和经验。

由于精灵图块存储在几行上,如果看起来像 很难在着色器中管理它。

不是真的,你所有的精灵都是相同的大小,所以你会得到一个完美的统一网格,从一些 1D 索引到 2D 只是一个除法和模的问题。不是很难。

但是,为什么还要将单个帧存储在 m x n 网格中?现在,您可以将它们仅存储在一行中。但是,在现代 GL 中,我们有数组纹理。这些基本上是一组独立的 2D 图层,大小都相同。您只需通过 3D 坐标访问它们,第三个坐标是从 o 到 n-1 的图层。这非常适合您的用例,并且可以消除边界处纹理过滤/出血的任何问题,并且还可以很好地与 mipmap 配合使用(如果需要的话)。当引入数组纹理时,实现需要支持的最小层数是 64(现在要高得多),因此即使对于旧的 GPU 来说,32 帧也是小菜一碟。

你可以用

一百万种方式做到这一点,但我要提出一个天真的解决方案:

创建一个具有 32(框架正方形)*2(三角形

每帧正方形)*3(三角形顶点)*5(x,y,z,u,v 每个顶点)= 960 个浮点空间的 VBO。用所有精灵的顶点以每帧 2 个三角形的方式填充它。

现在根据glDrawArrays的文档,您可以指定从哪里开始以及渲染多长时间。使用此功能,您可以指定以下内容:

int indicesPerFrame = 960/32;
int indexToStart = indicesPerFrame*currentBallFrame;
glDrawArrays( GL_TRIANGLES, indexToStart, indicesPerFrame);

无需修改 VBO。现在从我的角度来看,一次只渲染 32 帧 1 帧是矫枉过正的。这个问题有更好的解决方案,但这是学习OpenGL4最简单的方法。

在 OpenGL 2.1 中,我使用的是您的第二个选项:

void setActiveRegion(int regionIndex)
{
    UVs.clear();
    int numberOfRegions = (int) textureSize / spriteWidth;
    float uv_x = (regionIndex % numberOfRegions)/numberOfRegions;
    float uv_y = (regionIndex / numberOfRegions)/numberOfRegions;
    glm::vec2 uv_up_left    = glm::vec2( uv_x                     , uv_y );
    glm::vec2 uv_up_right   = glm::vec2( uv_x+1.0f/numberOfRegions, uv_y );
    glm::vec2 uv_down_right = glm::vec2( uv_x+1.0f/numberOfRegions, (uv_y + 1.0f/numberOfRegions) );
    glm::vec2 uv_down_left  = glm::vec2( uv_x                     , (uv_y + 1.0f/numberOfRegions) );

    UVs.push_back(uv_up_left   );
    UVs.push_back(uv_down_left );
    UVs.push_back(uv_up_right  );
    UVs.push_back(uv_down_right);
    UVs.push_back(uv_up_right);
    UVs.push_back(uv_down_left);
    glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
    glBufferSubData(GL_ARRAY_BUFFER, 0, UVs.size() * sizeof(glm::vec2), &UVs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

资料来源:http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-11-2d-text/

他实现它来渲染 2D 文本,但它是相同的概念!

我希望有所帮助!