Procesamiento lento de lotes de modelos en libGDX
Tengo una pregunta sobre si hay un modo especial para agrupar modelos en libGDX. He creado una clase simple que implementa ApplicationListener
que muestra mi problema. Estoy usando la compilación nocturna de libGDX.
He leído dos modelos diferentes que utilizan la misma textura. La aplicación produce respectivamente 250 modelos de todo tipo. Así es como se ve la parte del código de renderizado:
- Android: nesting FrameLayouts - ¿cuál es la sobrecarga de rendimiento exacto?
- StackOverflowError al cambiar la visibilidad de la vista
- ¿Qué significa MediaPlayer info / warning (973, 0)?
- Rendimiento de procesamiento en android
- Es mejor inflar o instanciar los controles en Android?
mModelBatch.begin(camera); for(int y=0; y<50; y++) { for(int x=-5; x<5; x++) { ModelInstance instance; if(x%2 == 0) instance = modelInstance1; else instance = modelInstance2; instance.transform.setToTranslation(x, 0, -y); mModelBatch.render(instance); } } mModelBatch.end();
Estaba tratando de encontrar una buena solución, así que escribí otro código de prueba:
public void getRenderables(Array<Renderable> renderables, Pool<Renderable> pool) { for(int y=0; y<50; y++) { for(int x=-5; x<5; x++) { ModelInstance instance; if(x%2 == 0) instance = modelInstance1; else instance = modelInstance2; instance.transform.setToTranslation(x, y%3, -y); Renderable renderable = pool.obtain(); renderable = instance.getRenderable(renderable); renderables.add(renderable); } }
}
Lo usé como se muestra a continuación:
mModelBatch.begin(camera); mModelBatch.render(testRenderProvider); mModelBatch.end();
Sin embargo, todavía me dio 13 FPS. Mientras tanto para hacer otra prueba he creado en la licuadora el mismo mapa que estaba en el programa anterior. A continuación, agrupé todo en un solo objeto (sin ninguna edición adicional). De esta manera he creado un gran objeto de tamaño casi 1 MB, se puede ver en la captura de pantalla de la licuadora.
He cambiado el programa de prueba de una manera que sólo atrae a un objeto BIG:
mModelBatch.begin(camera); modelInstance1.transform.setToTranslation(0, 0, 0); mModelBatch.render(modelInstance1); mModelBatch.end();
Lo siguiente que hice fue que lancé el programa en mi teléfono (Sony XPeria Mini Pro – lo mismo que antes) y el iPod 5g y tengo … 60 FPS!
¿Es posible hacer todo en una sola llamada?
- Cargando datos de forma eficaz en RecycleView
- Miles de insertos crudos de ORMLite que tardan varios minutos en Android
- ¿Por qué el desarrollo de android con varios proyectos es lento en mi configuración?
- Android diccionario TreeSet tiempo de carga más rápido
- Java Android leer el archivo completo rápidamente
- Disminuir la velocidad de View Pager en android
- ¿Puedo activar multidex en la compilación de depuración de Android solamente?
- Eficiencia de Android: vistas
¡Problema resuelto! Logré 60 FPS en un dispositivo móvil de gama baja. El juego corre sin problemas. Descubrí cómo combinar mallas múltiples en una malla para poder usar los mecanismos VBO. Hubo un error en libGDX que hizo que el método de copiado de malla no se pudiera usar con múltiples mallas. Después de los cambios, el mapa se divide en sectores pequeños. Cada sector se compone de mallas con el mismo valor de eje z que se puede ver en la siguiente imagen:
Los mecanismos VBO son muy limitados, por lo que no muchos vértices se pueden extraer de una sola vez, es por eso que los sectores tienen que ser bastante pequeño. El nuevo procesador tenía que ser escrito para manejar la representación correctamente. Y las partes del procesador están fusionando las mallas de forma dinámica (sin ninguna herramienta separada, como por ejemplo, licuadora).
public static Mesh mergeMeshes(AbstractList<Mesh> meshes, AbstractList<Matrix4> transformations) { if(meshes.size() == 0) return null; int vertexArrayTotalSize = 0; int indexArrayTotalSize = 0; VertexAttributes va = meshes.get(0).getVertexAttributes(); int vaA[] = new int [va.size()]; for(int i=0; i<va.size(); i++) { vaA[i] = va.get(i).usage; } for(int i=0; i<meshes.size(); i++) { Mesh mesh = meshes.get(i); if(mesh.getVertexAttributes().size() != va.size()) { meshes.set(i, copyMesh(mesh, true, false, vaA)); } vertexArrayTotalSize += mesh.getNumVertices() * mesh.getVertexSize() / 4; indexArrayTotalSize += mesh.getNumIndices(); } final float vertices[] = new float[vertexArrayTotalSize]; final short indices[] = new short[indexArrayTotalSize]; int indexOffset = 0; int vertexOffset = 0; int vertexSizeOffset = 0; int vertexSize = 0; for(int i=0; i<meshes.size(); i++) { Mesh mesh = meshes.get(i); int numIndices = mesh.getNumIndices(); int numVertices = mesh.getNumVertices(); vertexSize = mesh.getVertexSize() / 4; int baseSize = numVertices * vertexSize; VertexAttribute posAttr = mesh.getVertexAttribute(Usage.Position); int offset = posAttr.offset / 4; int numComponents = posAttr.numComponents; { //uzupelnianie tablicy indeksow mesh.getIndices(indices, indexOffset); for(int c = indexOffset; c < (indexOffset + numIndices); c++) { indices[c] += vertexOffset; } indexOffset += numIndices; } mesh.getVertices(0, baseSize, vertices, vertexSizeOffset); Mesh.transform(transformations.get(i), vertices, vertexSize, offset, numComponents, vertexOffset, numVertices); vertexOffset += numVertices; vertexSizeOffset += baseSize; } Mesh result = new Mesh(true, vertexOffset, indices.length, meshes.get(0).getVertexAttributes()); result.setVertices(vertices); result.setIndices(indices); return result; } public static Mesh copyMesh(Mesh meshToCopy, boolean isStatic, boolean removeDuplicates, final int[] usage) { // TODO move this to a copy constructor? // TODO duplicate the buffers without double copying the data if possible. // TODO perhaps move this code to JNI if it turns out being too slow. final int vertexSize = meshToCopy.getVertexSize() / 4; int numVertices = meshToCopy.getNumVertices(); float[] vertices = new float[numVertices * vertexSize]; meshToCopy.getVertices(0, vertices.length, vertices); short[] checks = null; VertexAttribute[] attrs = null; int newVertexSize = 0; if (usage != null) { int size = 0; int as = 0; for (int i = 0; i < usage.length; i++) if (meshToCopy.getVertexAttribute(usage[i]) != null) { size += meshToCopy.getVertexAttribute(usage[i]).numComponents; as++; } if (size > 0) { attrs = new VertexAttribute[as]; checks = new short[size]; int idx = -1; int ai = -1; for (int i = 0; i < usage.length; i++) { VertexAttribute a = meshToCopy.getVertexAttribute(usage[i]); if (a == null) continue; for (int j = 0; j < a.numComponents; j++) checks[++idx] = (short)(a.offset/4 + j); attrs[++ai] = new VertexAttribute(a.usage, a.numComponents, a.alias); newVertexSize += a.numComponents; } } } if (checks == null) { checks = new short[vertexSize]; for (short i = 0; i < vertexSize; i++) checks[i] = i; newVertexSize = vertexSize; } int numIndices = meshToCopy.getNumIndices(); short[] indices = null; if (numIndices > 0) { indices = new short[numIndices]; meshToCopy.getIndices(indices); if (removeDuplicates || newVertexSize != vertexSize) { float[] tmp = new float[vertices.length]; int size = 0; for (int i = 0; i < numIndices; i++) { final int idx1 = indices[i] * vertexSize; short newIndex = -1; if (removeDuplicates) { for (short j = 0; j < size && newIndex < 0; j++) { final int idx2 = j*newVertexSize; boolean found = true; for (int k = 0; k < checks.length && found; k++) { if (tmp[idx2+k] != vertices[idx1+checks[k]]) found = false; } if (found) newIndex = j; } } if (newIndex > 0) indices[i] = newIndex; else { final int idx = size * newVertexSize; for (int j = 0; j < checks.length; j++) tmp[idx+j] = vertices[idx1+checks[j]]; indices[i] = (short)size; size++; } } vertices = tmp; numVertices = size; } } Mesh result; if (attrs == null) result = new Mesh(isStatic, numVertices, indices == null ? 0 : indices.length, meshToCopy.getVertexAttributes()); else result = new Mesh(isStatic, numVertices, indices == null ? 0 : indices.length, attrs); result.setVertices(vertices, 0, numVertices * newVertexSize); result.setIndices(indices); return result; }
Esto puede ser muy útil para las personas que tratan de escribir sus propios juegos 3D en libGDX. Sin este mecanismo es bastante imposible escribir algo más compilado que algunos modelos.
- Arrastre para cambiar el tamaño dinámico de un par de diseños adyacentes en Android
- Prevención de la piratería de la aplicación android