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);
}

提前致谢。

4

1 回答 1

3

当它意味着四边形时,我对提到“立方体”的问题感到困惑,所以这个答案涉及 3d 案例,无论如何这可能更具启发性。

将视图和投影矩阵组合成一个 ViewProj 矩阵。然后在垂直着色器中执行 VertexPos * Model * ViewProj。

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

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

将所有不同的纹理放入单个纹理(“图集”)中,并通过调整每个立方体的 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

于 2012-10-26T07:34:25.960 回答