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、旋转和缩放但共享相同纹理图集的粒子?这个问题的重点是每个粒子的不同 alphas、rotations和scales。
我意识到这个问题与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 es android中的随机位置绘制多个立方体