Медленная модель пакетной рендеринга в libGDX

У меня вопрос, есть ли специальный режим для группировки моделей в libGDX. Я создал простой класс, который реализует ApplicationListener который показывает мою проблему. Я использую ночную сборку libGDX.

Я читал две разные модели, которые используют ту же текстуру. Приложение отображает соответственно 250 моделей каждого типа. Так выглядит часть кода рендеринга:

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

У меня около 12 FPS на моем телефоне (Sony Xperia mini pro).

Я пытался найти хорошее решение, поэтому я написал еще один тестовый код:

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

}

Я использовал его, как показано ниже:

 mModelBatch.begin(camera); mModelBatch.render(testRenderProvider); mModelBatch.end(); 

Однако это все равно дало мне 13 FPS. Между тем, чтобы сделать еще один тест, я создал в блендере ту же карту, что и в предыдущей программе. Затем я сгруппировал все только в одном объекте (без каких-либо дополнительных выпусков). Таким образом, я создал один БОЛЬШОЙ объект размером почти 1 МБ, его можно увидеть на скриншоте из блендера.

Введите описание изображения здесь

Я сменил тестовую программу так, чтобы она рисовала только один объект BIG:

 mModelBatch.begin(camera); modelInstance1.transform.setToTranslation(0, 0, 0); mModelBatch.render(modelInstance1); mModelBatch.end(); 

Следующее, что я сделал, это то, что я запустил программу на своем телефоне (Sony XPeria Mini Pro – то же, что и раньше) и iPod 5g, и у меня есть … 60 FPS! Введите описание изображения здесь

Можно ли сделать все в одном призыве?

Solutions Collecting From Web of "Медленная модель пакетной рендеринга в libGDX"

Задача решена! Я достиг 60 FPS на мобильном устройстве низкого уровня. Игра проходит гладко. Я узнал, как объединить несколько мешей в одну сетку, чтобы можно было использовать механизмы VBO. В libGDX произошла ошибка, из-за чего метод Mesh-копирования не использовался с несколькими сетками. После изменений карта делится на небольшие сектора. Каждый сектор состоит из сеток с тем же значением оси z, что и на следующем изображении: Введите описание изображения здесь

Механизмы VBO очень ограничены, поэтому не так много вершин можно нарисовать за один раз, поэтому секторы должны быть довольно маленькими. Новый рендерер должен был быть написан для правильной обработки рендеринга. А части рендеринга динамически объединяют сетки (без какого-либо отдельного инструмента, например, блендера).

 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; } 

Это может быть очень полезно для людей, пытающихся написать свои собственные 3D-игры в libGDX. Без этого механизма довольно сложно написать что-нибудь более компилируемое, чем несколько моделей.