OpenGL ES2:使用FrameBuffer对象更快地渲染多个形状

时间:2012-10-26 07:02:23

标签: android opengl-es-2.0

我有一个程序可以绘制超过90个带有纹理的2D形状,用户可以通过触摸屏幕来拾取和拖动。有一个明显的紊乱,DDMS告诉我占用最多CPU时间(~85%)的一种方法是draw()方法。由于只有1个形状实际上是移动而另外89个不是,使用FrameBuffer对象将89个形状渲染到纹理是否可能/更快,并将该纹理绘制在填满整个屏幕的形状上?如果没有,还有其他可能的加速方法吗?

private void draw() {
    // Pass in the position information
    mCubePositions.position(0);
    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, mCubePositions);
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Pass in the color information
    mCubeColors.position(0);
    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, 0, mCubeColors);
    GLES20.glEnableVertexAttribArray(mColorHandle);

    // Pass in the texture coordinate information
    mCubeTextureCoordinates.position(0);
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

    // This multiplies the view matrix by the model matrix, and stores the
    // result in the MVP matrix
    // (which currently contains model * view).
    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

    // Pass in the modelview matrix.
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);

    // This multiplies the modelview matrix by the projection matrix, and
    // stores the result in the MVP matrix
    // (which now contains model * view * projection).
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);

    // Pass in the combined matrix.
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

    // Draw the cube.
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}

提前致谢。

1 个答案:

答案 0 :(得分:3)

我对提到" cube"的问题感到困惑。当它意味着四边形,所以这个答案处理的是3d案例,无论如何这可能更有启发性。

将视图和投影矩阵组合到ViewProj矩阵中。然后在vert着色器中执行VertexPos * Model * ViewProj。

你真的需要批量。您应该有一个包含所有多维数据集的大数组,以及另一个包含每个多维数据集转换的数组。然后,您为所有多维数据集执行一次绘制调用。考虑将其转换为使用顶点缓冲区对象。绘制调用是CPU密集型的,因为它们在幕后的API中调用了大量的逻辑和内存复制等。游戏引擎竭尽全力将它们最小化。

如何使一个绘制调用绘制很多东西

将所有不同的纹理放入单个纹理(" atlas"),并通过调整每个立方体的UV来补偿以查找纹理的适当部分。将所有模型矩阵放入一个连续的数组中,并在顶点着色器中索引此数组,例如

attribute vec3 a_position;
attribute vec2 a_texCoord;
attribute int  a_modelIndex;
attribute int  a_UVlIndex;

uniform   mat4   u_model[90];
uniform   vec2   u_UVOffset[16];   // Support 16 different textures in our atlas.

varying   vec2   v_texCoord;
...

void main()
{
    gl_Position = u_viewProj * u_model[a_modelIndex] * vec4(a_position, 1);
    v_texCoord  = a_texCoord + u_UVOffset[a_UVlIndex];
    ...
}    

您可以将所有顶点数据打包成一个大数组,这样您最终会做GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6 * 90);但更好的是,因为您只是一直在绘制多维数据集,所以您可以重新使用完全相同每次都是顶点数据。模型矩阵负责其余的(缩放,旋转,平移)。要做到这一点,使用glDrawElements代替glDrawArrays,并且---为简单起见假设三个列表 - 指定36个引用顶点数组中36个顶点的索引,这些顶点构成一个立方体,然后重复这36个索引90制作索引数组的时间。顶点应该是一个单位立方体,以(0,0,0)为中心。同样的"立方体模板"然后由顶点着色器中的模型矩阵修改,以创建每个可见的"立方体实例"。您需要更改每个帧的唯一方法是模型矩阵和纹理UV。

glVertexAttribPointer()允许你在你的顶点着色器中喷出你喜欢的任何东西,将模型矩阵作为属性而不是制服使用glVertexAttribPointer可能更有效。

移动设备往往对像素绑定非常敏感。如果你的立方体在屏幕上非常大,你可能会得到很多透支。高CPU%(毕竟它只是一个百分比)可能是一个红色鲱鱼,你可能是GPU上的像素绑定。对此进行简单测试就是使所有立方体非常小,并查看帧速率是否有所改善。

作为参考,S5570有一个Adreno 200 GPU

相关问题