【问题标题】:Best way to move sprites in OpenGL - translate or alter vertices在 OpenGL 中移动精灵的最佳方式 - 转换或更改顶点
【发布时间】:2023-03-24 10:16:01
【问题描述】:

我正在使用 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();

就高效和最佳实践而言,在这种情况下最好的做法是什么。

【问题讨论】:

    标签: graphics opengl-es


    【解决方案1】:

    OpenGL ES(从 2.0 开始)支持实例化,不幸的是。如果是这样,我建议从顶点绘制一个实例化的 2 三角形精灵 N 次,读取中心点的 x/y 偏移量,如果您需要不同大小的精灵,可能还需要一个缩放值纹理(ES 支持就好了)。这会将每帧必须推送的数据量限制在最低限度。

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

    每帧中的流式传输顶点可能不会超快,但这并不重要,只要延迟可以很好地隐藏(例如,通过从一个缓冲区绘制同时填充另一个缓冲区)。很少的绘图调用,很少的状态更改,理想情况下没有停顿应该仍然可以让这个速度变快。

    【讨论】:

    • 我必须承认我昨天才开始使用openGL。我现在无法完全理解你的回答。您是否建议可以优化程序,因为填充 VBO 和绘制 VBO 可以在不同的硬件上同时完成?
    • 缓冲区对象是您不拥有的“一些内存”的抽象(除非您拥有)。因此,OpenGL 实现(或 GPU)可以从中读取数据,知道数据是明确定义且有效的。当您映射缓冲区以写入它时,或者当 glBufferData 正在运行时,情况并非如此。数据正在发生变化。因此,OpenGL 显然必须阻止您,直到它完成读取数据,并且只有在您取消映射缓冲区或 glBufferData 完成后才能开始读取。然而,如果你调用 BufferData(0),你告诉 OpenGL 你并不真正感兴趣......
    • ... 在这个缓冲区中,但你想要一个新的写入。你也很快得到了(没有任何明显的差异)。这也将当前缓冲区标记为已删除,OpenGL 最终将删除它——但只有在它不再需要读取它之后。这意味着不多不少于a)您不需要等待绘图完成,b)绘图不需要等待您。这样可以避免管道停止。
    • 我想我需要先睡一会儿才能消化。谢谢你的帮助,感激不尽。
    【解决方案2】:

    绘图调用比更改数据要昂贵得多。而且 glTranslate 并不像仅仅添加几个数字那么有效,毕竟它必须经过一个完整的 4×4 矩阵乘法,即 64 次标量乘法和 16 次标量加法。

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

    【讨论】:

    • 如果我保留一份ballVertexBuffer 的副本会怎样。如果我使用翻译,我就不必在每次调用时都将顶点加载到 VBO 中
    • 我读过一些似乎表明 glTranslate 将是一个更好的选择 gamedev.stackexchange.com/questions/8658/… 。记住矩阵乘法是 GPU 的基础——也许最好是翻译?也就是说,我不确定有多少手机有 GPU
    • @user1093404 但glTranslate 不在 GPU 上执行。 datenwolf 指的是glTranslate 调用,它将当前模型视图矩阵与平移矩阵相乘。这与每个顶点乘以模型视图矩阵无关,无论您使用什么技术,它总是在 GPU 上完成(假设你不使用着色器)并且总是在 GPU 上。但是glTranslate 调用会执行单个矩阵相乘,但在 CPU 上。
    • @user1093404 您所指的问题具有完全不同的性质,并且涉及较大的对象,对其进行转换也不像简单的翻译那么容易,并且无论如何都有些误导。这与您的许多简单且相等的 4 顶点对象不同。
    • 有趣。感谢您输入克里斯蒂安。因此,例如,如果我有一个具有数千个顶点的对象,那么换一种方式可能会更好,但在我的情况下不值得吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多