OpenGl es 2.0 几何体实例化

5

我需要绘制170个对象,每个对象都由312个顶点构成。我有一个对象,并使用不同的矩阵将其绘制170次。我已经发现,如果我逐个绘制它们,就不需要调用某些函数,所以我只在开始时调用它们。这可以带给我大约5fps的性能提升,我使用的是非索引化三角形和drawArrays函数。

if(!started)
{
    glUseProgram( __programObject );
    glEnableVertexAttribArray(attPosition);
    glVertexAttribPointer(attPosition, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), vVertices);//3*sizeof(float)
    glEnableVertexAttribArray(attNormals);
    glVertexAttribPointer(attNormals, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), vNormals);//3*sizeof(float)
}

有没有办法在es 2.0下加快速度?我在sgx 540上只能获得大约23fps,将每个对象的顶点细节降低到36不会增加帧率,在矩阵计算(缩放、乘法、平移、转置、反演)中有大约10fps,但它们是在cpu上完成的,我认为将它们移到着色器中不是一个好主意。我知道大部分时间都花在传递uniforms上。我知道有一种方法可以实例化对象并传递uniforms,然后一次性绘制,但我找不到任何描述它的教程,请问你知道在哪里可以找到吗?

使用单个VBO与交错数据可以显著提高性能。一些GPU也更喜欢16字节的跨度。 - tc.
遗憾的是,SGX540上没有gl_ext_draw_instancedgl_ext_instanced_arrays,只有在SGX543、544、554(也就是所谓的5XT系列5系列不同)才有。 - Engineer
2个回答

3

尝试将顶点和法向量存储在一个数组中,就像这样:

sqTex.getVertexBuffer().position(sqTex.VERT_OFFSET);
GLES20.glVertexAttribPointer(
                                GLES20.glGetAttribLocation(programTextured, "aPosition"), 3,
                                GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());
GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(programTextured, "aPosition"));

sqTex.getVertexBuffer().position(sqTex.TEXT_OFFSET);
GLES20.glVertexAttribPointer(
                                GLES20.glGetAttribLocation(programTextured, "aTextureCoord"), 2,
                                GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());
GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(programTextured, "aTextureCoord"));

在这个例子中,我有一个数组用于顶点和纹理坐标。
引自《OpenGL ES 2.0编程指南》:
 How to store different attributes of a vertex
We described the two most common ways of storing vertex attributes—
array of structures and structure of arrays. The question to ask is which allocation
method would be the most efficient for OpenGL ES 2.0 hardware
implementations. The answer is array of structures. The reason is that the
attribute data for each vertex can be read in sequential fashion and so will
most likely result in an efficient memory access pattern. A disadvantage of
using array of structures is when an application wants to modify specific
attributes. If a subset of vertex attribute data needs to be modified (e.g., texture
coordinates), this will result in strided updates to the vertex buffer.
When vertex buffer is supplied as a buffer object, the entire vertex attribute
buffer will need to be reloaded. One can avoid this inefficiency by storing
vertex attributes that are dynamic in nature in a separate buffer.

那本书还有使用此方式的示例。

我在开始时只传递了一次法线和顶点,我认为可以将法线和位置矩阵一起传递,这样应该会更快一些 -> 完成,将gluniformmatrix3fv和4fv用于位置和法线矩阵的数组转换为7个vec4传递的浮点数数组,现在帧率为28-29fps。我一直在考虑为所有对象制作一个大的顶点数组,并预先计算出位置和法线...我想我会尝试一下。 - ZZZ
2
不同向量数组的问题在于GPU需要从一个内存源跳到另一个内存源以处理每个顶点,这是额外的操作。依我之见。 - Yuriy Vikulov
我曾经读过一篇来自Nvidia的文章,其中提到始终使用交错顶点三角形带。因为这样可以实现缓存命中。他们列举了一些其他原因,但主要关注点是缓存命中。不过我已经记不清在哪里看到这篇文章了 :( - eonil
也许这是与硬件相关的建议,不是吗?然而Nvidia是主流。 - Yuriy Vikulov
2
线性化数据以实现最佳缓存性能与硬件无关。每当一组指令在多个数据源上运行时,为了获得缓存局部性,交错这些数据是明智的选择。即使在 CPU 上也是如此。 - Engineer

1

你可以尝试通过属性而不是统一变量来传递每个实例的数据。在桌面OpenGL上有时会有所帮助。

因此,顶点着色器将如下所示:

attribute vec3 position;
attribute mat4 proj_view_matrix;
void main()
{
    gl_Position = proj_view_matrix * position;
}

渲染代码将如下所示:

glUseProgram( programObject );
glEnableVertexAttribArray(attPosition);
glVertexAttribPointer(attPosition, ..., pPositions);
glDisableVertexAttribArray(attProjViewMatrix+0);
glDisableVertexAttribArray(attProjViewMatrix+1);
glDisableVertexAttribArray(attProjViewMatrix+2);
glDisableVertexAttribArray(attProjViewMatrix+3);

foreach( instance )
{
    glVertexAttrib4fv(attProjViewMatrix+0, instance.proj_view_matrix.column0);
    glVertexAttrib4fv(attProjViewMatrix+1, instance.proj_view_matrix.column1);
    glVertexAttrib4fv(attProjViewMatrix+2, instance.proj_view_matrix.column2);
    glVertexAttrib4fv(attProjViewMatrix+3, instance.proj_view_matrix.column3);
    glDrawArrays( ... );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接