在OpenGL中移动精灵的最佳方法 - 转换或改变顶点

时间:2011-12-12 09:29:09

标签: graphics opengl-es

我正在使用openGL ES为Android创建一个应用程序。我试图在2D中绘制许多在屏幕上反弹的移动精灵。

让我们考虑我在坐标100,100处有一个球。球图形宽度为10px,因此我可以创建顶点boundingBox = {100,110,0, 110,110,0, 100,100,0, 110,100,0}并在onDrawFrame()的每个循环上执行以下操作并加载球纹理。

//for each ball object
FloatBuffer ballVertexBuffer = byteBuffer.asFloatBuffer();
ballVertexBuffer.put(ball.boundingBox);
ballVertexBuffer.position(0);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, ballVertexBuffer); 
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0,4);

然后我会更新boundingBox数组以在屏幕上移动球。

或者,在绘制顶点之前,我根本无法改变bounding box而是translatef()

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, ballVertexBuffer); 
gl.glPushMatrix();
gl.glTranslatef(ball.posX, ball.posY, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0,4);
gl.glPopMatrix();

在效率和最佳实践方面,最好的做法是什么。

2 个答案:

答案 0 :(得分:3)

OpenGL ES(截至2.0)支持实例化,不幸的是。如果是的话,我建议绘制一个2-triangle sprite instanced N 次,读取中心点的x / y偏移量,如果你需要不同大小的sprite,可能是一个缩放值,来自一个顶点纹理(ES支持很好)。这会将每帧必须推送的数据量限制到最小。

假设您不能直接在GPU上进行模拟(从而避免每帧上传顶点数据)......这基本上只留下一个有效选项:
生成2个VBO,映射一个并填充它,而另一个用作绘制调用的源。如果你之间有glBufferData(... 0),你也可以使用单个缓冲区看似,这告诉OpenGL生成一个新的缓冲区,并在它完成读取后立即抛弃旧的缓冲区。

每一帧中的流顶点可能不会超快,但只要延迟可以被很好地隐藏(例如,通过从一个缓冲区中绘制而填充另一个缓冲区),这无关紧要。很少有人打电话,几乎没有状态变化,理想情况下,没有任何档位也应该让这个很快。

答案 1 :(得分:1)

绘图调用比更改数据要昂贵得多。此外,glTranslate并不像添加一些数字那样高效,毕竟它必须通过一个完整的4×4矩阵乘法,即64个标量乘法和16个标量加法。

当然,最好的方法是使用某种形式的实例化。