OpenGL ES:一个 VBO - 几个精灵 - 每个单独翻译
Posted
技术标签:
【中文标题】OpenGL ES:一个 VBO - 几个精灵 - 每个单独翻译【英文标题】:OpenGL ES: one VBO - several sprites - translate each individually 【发布时间】:2017-05-25 12:06:17 【问题描述】:我想知道当这些精灵的顶点存储在同一个 VBO 中时,如何单独访问和操作每个精灵。出于性能原因,我为我的精灵使用纹理图集,然后将它们映射到顶点数组。我尝试将精灵拆分为单独的顶点数组并将它们放在单独的 VBO 中。但是,如果我绘制 100 个精灵,这会影响性能,因为每次调用都必须进行很多单独的绘制。相反,我想使用一个相同的 VBO,然后分别翻译每个精灵。这可能吗?
源代码
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config)
vertexBuffer = GLData.createVertices(nSprites, vertices);
GLData.createUvsData(nSprites, alienUvs, uvBufferAlien);
//drawListBuffer = GLData.createIndices(indices, nSprites);
GLData.createVertexBufferObject(vertexBuffer,nSprites, uvBufferAlien, bufferId.length, bufferId);
createCamera();
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// get shadersource
final String vertexShader = getVertexShader();
final String fragmentShader = getFragmentShader();
final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
new String[] "a_Position", "a_Color", "a_Normal", "a_TexCoordinate");
//create texture
textureHandle = TextureHelper.loadTexture(context);
GLES20.glUseProgram(mProgramHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
//mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
@Override
public void onSurfaceChanged(GL10 unused, int width, int height)
game_width = width;
game_height = height;
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1f;
final float far = 20.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
@Override
public void onDrawFrame(GL10 unused)
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 2, 0f, -7f);
draw();
private void draw()
//uvs
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[0]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, 0);
//vertices
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[1]);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Clear the currently bound buffer (so future OpenGL calls do not use this buffer).
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* MATRIX */
// 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 sprites
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6 * nSprites);
顶点着色器
attribute vec4 a_Position;
uniform mat4 u_MVMatrix;
uniform mat4 u_MVPMatrix;
void main()
gl_Position = u_MVPMatrix * a_Position;
【问题讨论】:
【参考方案1】:您可以上传一个统一的矩阵数组,并将索引作为每个精灵的每个顶点属性,为每个精灵提供一个唯一的矩阵(用于蒙皮骨骼动画模型的技术,但也适用于此)。
但是,对于简单的 sprite,上传矩阵的成本几乎与更新位置数组一样昂贵,而且您需要担心统一数组的大小有限制。您最好只在软件中为它们设置动画,并为每帧批次中的每个顶点上传一个新位置。将位置拆分为一个单独的缓冲区,例如您的纹理坐标,以最小化您上传每帧的带宽。
【讨论】:
我为好的答案投了赞成票 - 但问题没有解决。事实上 - 不敢相信 - 当我在 Galaxy S3(从 S7 切换)上使用我的应用程序时,帧时间下降到 20。我整晚都在考虑这个问题,但它可能是 1920 X 1856 的纹理?是因为它不是 POT 还是它太大了???我会试试这个 - 如果它不起作用,我会在堆栈上提出一个新问题并给你链接。谢谢!!!!!!! 您是否正在修改纹理图集或现有缓冲区而不使用流水线?您可能只是触发了大量资源副本。见community.arm.com/graphics/b/blog/posts/…以上是关于OpenGL ES:一个 VBO - 几个精灵 - 每个单独翻译的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 中使用带有 OpenGL ES 的 VBO 性能不佳