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:

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

Tengo alrededor de 12 FPS en mi teléfono (Sony Xperia mini pro).

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.

Introduzca aquí la descripción de la imagen

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! Introduzca aquí la descripción de la imagen

¿Es posible hacer todo en una sola 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: Introduzca aquí la descripción de la 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.

  • Cómo dibujar varias líneas con el dedo? (Androide)
  • ¿Cómo mterp (Dalvik VM) organiza su bucle de interpretación de bytes?
  • Inicio y fin de solicitudes de registro HTTP desde WebView incorporado de Android
  • HTTP Vs sockets Vanilla para cargar archivos binarios grandes (50-200 MB) desde un dispositivo Android a través de una red Wi-Fi de un solo salto
  • Edittext Mensaje de error de validación en android?
  • Rendimiento ORM: ¿es greenDAO más rápido que ORMLite?
  • Rendimiento JPG vs WebP en Android
  • Android y OOP - Variables globales vs heredados Getters en fragmentos
  • Obtención de velocidad mediante el API de ubicación de Google Play
  • En una aplicación para Android, ¿cuándo se cargan los recursos en la memoria?
  • ¿Por qué está agregando un OnClickListener dentro onBindViewHolder de un RecyclerView.Adapter considerado mala práctica?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.