使用 OpenGL 的 2D Sprite 动画技术
Posted
技术标签:
【中文标题】使用 OpenGL 的 2D Sprite 动画技术【英文标题】:2D Sprite animation techniques with OpenGL 【发布时间】:2015-03-01 02:02:42 【问题描述】:我目前正在尝试使用 OpenGL 4 设置 2D 精灵动画。 例如,我设计了一个使用 Gimp 平滑旋转的球。大约有 32 帧(4 行 8 帧)。
我的目标是在 2D 纹理中创建一个精灵图集,并将我的精灵数据存储在缓冲区 (VBO) 中。我的精灵矩形将始终相同(即 rect(0,0,32,32) ),但每次增加帧索引时我的纹理坐标都会改变。
不知如何修改坐标。
-
由于精灵图块存储在多行中,如果在着色器中看起来难以管理它。
使用 glBufferSubData() 修改缓冲区内的精灵纹理坐标?
我在 OpenGL 1.x 上花了很多时间......几个月前我又回到了 OpenGL,但我意识到很多事情都发生了变化。我会尝试几种选择,但欢迎您的建议和经验。
【问题讨论】:
【参考方案1】:因为精灵图块存储在几行中,如果看起来是 很难在着色器中管理它。
不是真的,你所有的精灵都是一样的大小,所以你得到了一个完美的统一网格,从一维索引到二维只是一个除法和模数的问题。并不难。
但是,您为什么还要将单个帧存储在 m
xn
网格中?现在您可以将它们存储在一行中。但是,在现代 GL 中,我们有 array textures。这些基本上是一组独立的 2D 层,大小都相同。您只需通过 3D 坐标访问它们,第三个坐标是从 o 到 n-1 的层。这非常适合您的用例,并且可以消除边界处的纹理过滤/出血的任何问题,并且它也适用于 mipmapping(如果您需要的话)。当引入阵列纹理时,实现需要支持的最小层数是 64(现在要高得多),因此即使对于旧 GPU,32 帧也是小菜一碟。
【讨论】:
【参考方案2】:你可以用一百万种方法做到这一点,但我要提出一个幼稚的解决方案:
创建一个具有 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最简单的。
【讨论】:
感谢 sgtHale。这是我计划实施的解决方案的一部分:)【参考方案3】:在 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 文本,但它是相同的概念!
希望对你有所帮助!
【讨论】:
以上是关于使用 OpenGL 的 2D Sprite 动画技术的主要内容,如果未能解决你的问题,请参考以下文章