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:
- Cómo comprobar si existe una clave en Json Object y obtener su valor
- Android - ListView con imágenes se desplaza demasiado lento incluso sin ningún procesamiento en el método getView del adaptador
- Las imágenes de gridview de Android en caché, en las imágenes de desplazamiento se repiten antes de ser reemplazadas
- Forma preferida de actualizar sqlite db en android
- ¿Por qué la API de Android solicita un parámetro de resultados en lugar de un método de devolución?
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?
- El proveedor de contactos de Android sólo obtiene contactos telefónicos con todos los correos electrónicos
- Obtener la intensidad de la señal de WIFI y datos móviles
- Descomprimir archivos de una manera más rápida que usar java.util.zip en Android
- Android desplácese hacia arriba ocultar vista y desplácese hacia abajo mostrar el efecto de vista como twitter
- Efecto de trayectoria de trazo que hace la pantalla lenta
- ¿Por qué el perro String.format de android es lento?
- ¿Cómo probar el rendimiento de una aplicación de Android?
- KitKat tarda 6 segundos más que Froyo para reaccionar a TextToSpeech.speak () en primera llamada
¡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