Android OpenGL ES 2.0: VBA и VBO с различными позиционированными объектами
Поэтому я работаю над проектом, который немного похож на Minecraft, в котором есть тысячи кубов.
Я достиг очень высокого уровня производительности довольно рано и поэтому начал искать способы улучшить FPS.
Сначала я посмотрел на это и следовал рекомендациям Android OpenGL 2.0 Low FPS
Я сейчас пробую этот урок на VBO, и он очень быстрый.
http://www.learnopengles.com/android-lesson-seven-an-introduction-to-vertex-buffer-objects-vbos/
Я предполагаю, что вы должны строить cubePositionData каждый раз, когда я добавляю куб?
VBO - это путь к Minecraft?
public class CubeVBOVBA extends Cube {
/**
* Size of the position data in elements.
*/
static final int POSITION_DATA_SIZE = 3;
/**
* Size of the normal data in elements.
*/
static final int NORMAL_DATA_SIZE = 3;
/**
* Size of the texture coordinate data in elements.
*/
static final int TEXTURE_COORDINATE_DATA_SIZE = 2;
/**
* How many bytes per float.
*/
static final int BYTES_PER_FLOAT = 4;
final int mCubePositionsBufferIdx;
final int mCubeNormalsBufferIdx;
final int mCubeTexCoordsBufferIdx;
private int mActualCubeFactor = 40;
public CubeVBOVBA( int generatedCubeFactor)
{
final float[] cubePositionData = new float[108 * generatedCubeFactor * generatedCubeFactor * generatedCubeFactor];
int cubePositionDataOffset = 0;
final int segments = generatedCubeFactor + (generatedCubeFactor - 1);
final float minPosition = -1.0f;
final float maxPosition = 1.0f;
final float positionRange = maxPosition - minPosition;
for (int x = 0; x < generatedCubeFactor; x++) {
for (int y = 0; y < generatedCubeFactor; y++) {
for (int z = 0; z < generatedCubeFactor; z++) {
final float x1 = minPosition + ((positionRange / segments) * (x * 2));
final float x2 = minPosition + ((positionRange / segments) * ((x * 2) + 1));
final float y1 = minPosition + ((positionRange / segments) * (y * 2));
final float y2 = minPosition + ((positionRange / segments) * ((y * 2) + 1));
final float z1 = minPosition + ((positionRange / segments) * (z * 2));
final float z2 = minPosition + ((positionRange / segments) * ((z * 2) + 1));
// Define points for a cube.
// X, Y, Z
final float[] p1p = { x1, y2, z2 };
final float[] p2p = { x2, y2, z2 };
final float[] p3p = { x1, y1, z2 };
final float[] p4p = { x2, y1, z2 };
final float[] p5p = { x1, y2, z1 };
final float[] p6p = { x2, y2, z1 };
final float[] p7p = { x1, y1, z1 };
final float[] p8p = { x2, y1, z1 };
final float[] thisCubePositionData = ShapeBuilder.generateCubeData(p1p, p2p, p3p, p4p, p5p, p6p, p7p, p8p,
p1p.length);
System.arraycopy(thisCubePositionData, 0, cubePositionData, cubePositionDataOffset, thisCubePositionData.length);
cubePositionDataOffset += thisCubePositionData.length;
}
}
}
FloatBuffer[] floatBuffers = getBuffers(cubePositionData, cubeNormalData, textureCoordinateData, generatedCubeFactor);
FloatBuffer cubePositionsBuffer = floatBuffers[0];
FloatBuffer cubeNormalsBuffer = floatBuffers[1];
FloatBuffer cubeTextureCoordinatesBuffer = floatBuffers[2];
// Second, copy these buffers into OpenGL's memory. After, we don't need to keep the client-side buffers around.
final int buffers[] = new int[3];
GLES20.glGenBuffers(3, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubePositionsBuffer.capacity() * BYTES_PER_FLOAT, cubePositionsBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeNormalsBuffer.capacity() * BYTES_PER_FLOAT, cubeNormalsBuffer, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[2]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cubeTextureCoordinatesBuffer.capacity() * BYTES_PER_FLOAT, cubeTextureCoordinatesBuffer,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mCubePositionsBufferIdx = buffers[0];
mCubeNormalsBufferIdx = buffers[1];
mCubeTexCoordsBufferIdx = buffers[2];
cubePositionsBuffer.limit(0);
cubePositionsBuffer = null;
cubeNormalsBuffer.limit(0);
cubeNormalsBuffer = null;
cubeTextureCoordinatesBuffer.limit(0);
cubeTextureCoordinatesBuffer = null;
}
FloatBuffer[] getBuffers(float[] cubePositions, float[] cubeNormals, float[] cubeTextureCoordinates, int generatedCubeFactor) {
// First, copy cube information into client-side floating point buffers.
final FloatBuffer cubePositionsBuffer;
final FloatBuffer cubeNormalsBuffer;
final FloatBuffer cubeTextureCoordinatesBuffer;
cubePositionsBuffer = ByteBuffer.allocateDirect(cubePositions.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
cubePositionsBuffer.put(cubePositions).position(0);
cubeNormalsBuffer = ByteBuffer.allocateDirect(cubeNormals.length * BYTES_PER_FLOAT * generatedCubeFactor * generatedCubeFactor * generatedCubeFactor)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
for (int i = 0; i < (generatedCubeFactor * generatedCubeFactor * generatedCubeFactor); i++) {
cubeNormalsBuffer.put(cubeNormals);
}
cubeNormalsBuffer.position(0);
cubeTextureCoordinatesBuffer = ByteBuffer.allocateDirect(cubeTextureCoordinates.length * BYTES_PER_FLOAT * generatedCubeFactor * generatedCubeFactor * generatedCubeFactor)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
for (int i = 0; i < (generatedCubeFactor * generatedCubeFactor * generatedCubeFactor); i++) {
cubeTextureCoordinatesBuffer.put(cubeTextureCoordinates);
}
cubeTextureCoordinatesBuffer.position(0);
return new FloatBuffer[]{cubePositionsBuffer, cubeNormalsBuffer, cubeTextureCoordinatesBuffer};
}
public void render(float[] mVMatrix, float[] mProjMatrix) {
GLES20.glUseProgram(mProgramHandle);
// Pass in the position information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubePositionsBufferIdx);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the normal information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeNormalsBufferIdx);
GLES20.glEnableVertexAttribArray(mNormalHandle);
GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the texture information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeTexCoordsBufferIdx);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORDINATE_DATA_SIZE, 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.setIdentityM(mRenderer.mModelMatrix, 0);
Matrix.translateM(mRenderer.mModelMatrix, 0, position.x, position.y, position.z);
Matrix.scaleM(mRenderer.mModelMatrix, 0, scale.x, scale.y, scale.z);
Matrix.rotateM(mRenderer.mModelMatrix, 0, rotation.x, 1, 0, 0);
Matrix.rotateM(mRenderer.mModelMatrix, 0, rotation.y, 0, 1, 0);
Matrix.rotateM(mRenderer.mModelMatrix, 0, rotation.z, 0, 0, 1);
Matrix.multiplyMM(mRenderer.mMVPMatrix, 0, mVMatrix, 0, mRenderer.mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mRenderer.mMVMatrixHandle, 1, false, mRenderer.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(mTemporaryMatrix, 0, mProjMatrix, 0, mRenderer.mMVPMatrix, 0);
System.arraycopy(mTemporaryMatrix, 0, mRenderer.mMVPMatrix, 0, 16);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mRenderer.mMVPMatrixHandle, 1, false, mRenderer.mMVPMatrix, 0);
// Draw the cubes.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mActualCubeFactor * mActualCubeFactor * mActualCubeFactor * 36);
}
public void release() {
// Delete buffers from OpenGL's memory
final int[] buffersToDelete = new int[]{mCubePositionsBufferIdx, mCubeNormalsBufferIdx,
mCubeTexCoordsBufferIdx};
GLES20.glDeleteBuffers(buffersToDelete.length, buffersToDelete, 0);
}
}
1 ответ
Я пошел с реализацией VBO / VBA, и у меня было значительное увеличение производительности, с 20 объектов при 40 кадрах в секунду до 50000 при 60 кадрах в секунду! Стоит использовать VBO / VBA со статическими элементами