OpenGL ES - 如何批量渲染 500 多个带有不同 alpha、旋转和缩放的粒子?

Posted

技术标签:

【中文标题】OpenGL ES - 如何批量渲染 500 多个带有不同 alpha、旋转和缩放的粒子?【英文标题】:OpenGL ES - How to Batch Render 500+ particles w/ different alphas, rotations, and scales? 【发布时间】:2012-08-01 00:42:04 【问题描述】:

我正在开发一个需要一次渲染 500-800 个粒子的 ios 游戏。我了解到在 OpenGL ES 中批量渲染许多精灵是一个好主意,而不是在游戏中的每个精灵上调用glDrawArrays(..),以便能够在不大幅降低帧速率的情况下渲染更多精灵。

我的问题是:我如何批量渲染 500 多个具有不同 alpha、旋转和缩放但共享相同纹理图集的粒子?这个问题的重点是每个粒子的不同 alphasrotationsscales

我意识到这个问题与How do I draw 1000+ particles (w/ unique rotation, scale, and alpha) in iPhone OpenGL ES particle system without slowing down the game? 非常相似,但是,该问题不涉及批量渲染。在我利用顶点缓冲区对象之前,我想了解 OpenGL ES 中的批处理渲染,它们具有独特的 alpha、旋转和缩放(但具有相同的纹理)。因此,虽然我最终计划使用 VBO,但我想先采用这种方法。

非常感谢代码示例,如果您像某些示例一样使用索引数组,请解释索引数组的结构和用途。

编辑我使用的是 OpenGL ES 1.1。

编辑 下面是我如何渲染场景中每个粒子的代码示例。假设它们共享相同的纹理,并且在此代码执行之前,纹理已经绑定在 OpenGL ES 1.1 中。

- (void) render 

    glPushMatrix();

    glTranslatef(translation.x, translation.y, translation.z);

    glRotatef(rotation.x, 1, 0, 0);
    glRotatef(rotation.y, 0, 1, 0);
    glRotatef(rotation.z, 0, 0, 1);

    glScalef(scale.x, scale.y, scale.z);

    // change alpha
    glColor4f(1.0, 1.0, 1.0, alpha);

    // glBindTexture(GL_TEXTURE_2D, texture[0]);

    glVertexPointer(2, GL_FLOAT, 0, texturedQuad.vertices);
    glEnableClientState(GL_VERTEX_ARRAY);


    glTexCoordPointer(2, GL_FLOAT, 0, texturedQuad.textureCoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glPopMatrix();

非常感谢此方法的替代代码!

【问题讨论】:

你的目标是什么版本的opengl-es? 我正在使用 OpenGL ES 1.1(在编辑中注明)。谢谢! 【参考方案1】:

一种可能性是将这些值包含在顶点属性数组中——我认为这是最好的选择。如果您使用的是 OpenGL ES 1.1 而不是 2.0,那么您将无法使用这种方法。顶点属性数组允许您在每个顶点存储值,在这种情况下,您可以将 alpha 和旋转分别存储在它们自己的属性数组中,并使用glVertexAttribArray 将它们传递给着色器。然后着色器将使用 alpha 进行旋转变换和颜色处理。

另一种选择是在 CPU 上进行旋转变换,然后将具有相似 alpha 值的粒子批处理到多个绘制调用中。这个版本需要更多的工作,它不会是一个单一的绘制调用,但如果着色器不是一个选项,它仍然有助于优化。

注意:您链接到的问题也推荐了数组解决方案

编辑:鉴于您的代码是 OpenGL ES 1.0,这是使用 glColorPointer 的解决方案:

// allocate buffers to store an array of all particle data
verticesBuffer = ... 
texCoordBuffer = ...
colorBuffer = ...

for (particle in allParticles)

  // Create matrix from rotation
  rotMatrix = matrix(particle.rotation.x, particle.rotation.y, particle.rotation.z)
  // Transform particle by matrix
  verticesBuffer[i] = particle.vertices * rotMatrix

  // copy other data
  texCoordBuffer[i] = particle.texCoords;
  colorBuffer[i] = color(1.0, 1.0, 1.0, particle.alpha);


glVertexPointer(verticesBuffer, ...)
glTexCoordPointer(texCoodBuffer, ...)
glColorPointer(colorBuffer, ...)

glDrawArrays(particleCount * 4, ...);

此解决方案的一个很好的优化是为每个渲染共享缓冲区,这样您就不必在每一帧都重新分配它们。

【讨论】:

不幸的是,由于我使用的是 OpenGL ES 1.1,我可能会选择更多地转向您提到的第二个选项。 +1 为那个答案。谢谢! @TrueLifeCoder 您应该能够合理地获得 4-10 个绘图调用,具体取决于您需要的 alpha 值的变化量。您是将粒子旋转存储为矩阵还是其他形式? @TrueLifeCoder 我刚刚意识到使用 OpenGL ES 1.1 你可以只使用 glColorPointer 为每个顶点传递颜色信息,旋转仍将在 CPU 上完成,但这可能会降低到单个绘图调用 我的旋转存储为一个结构类型XYZ,它具有三个按 x、y 和 z 坐标的 CGFloats。每个粒子都有自己的 XYZ ivar。我在我的问题中添加了一个 EDIT 来说明我通常会做什么。可能您可以提供替代代码:) @TrueLifeCoder 我已经编辑了我的答案,向您展示如何使用 glColorPointer 的示例

以上是关于OpenGL ES - 如何批量渲染 500 多个带有不同 alpha、旋转和缩放的粒子?的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 会使用多个 VBO 减慢渲染速度吗?

OpenGL ES 多目标渲染(MRT)

在opengl es android中的随机位置绘制多个立方体

如何在 iPhone OpenGL ES 2.0 中在渲染和呈现帧缓冲区之间切换?

在 OpenGL ES 2.0 中渲染到纹理时的抗锯齿

如何使用用于 iPhone 开发的 OpenGL ES 渲染 3D 对象(顶点和法线存储在头文件中)?