在libGDX缓慢模型批渲染缓慢、模型、libGDX

2023-09-06 13:16:09 作者:徒手摘星

我有一个问题,是否有在libGDX分组模式的一种特殊模式。我创建了一个实现了一个简单的类了ApplicationListener 这说明我的问题。我使用libGDX的每晚构建。

I've got a question whether there is a special mode for grouping models in libGDX. I created a simple class that implements ApplicationListener which shows my problem. I am using the nightly build of libGDX.

我看了两个不同的机型,采用了相同的纹理。该应用程序分别呈现250车型每一种类型的。这是如何绘制code部分是这样的:

I read two different models which use the same texture. The application renders respectively 250 models of every type. This is how the part of rendering code looks like:

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

我试图找到一个很好的解决方案,所以我写了另外一个测试code:

I was trying to find a good solution so I wrote another test code:

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

}

我用它,因为它是如下图所示:

I used it as it is shown below:

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

然而,它还是给了我13 FPS。 同时使另一项测试我在搅拌机同一地图创建,因为它是在previous程序。接下来,我归纳的一切在短短的一个对象(不带任何附加版本)。这样,我创建了规模的一大目标,几乎1MB,可以看出从搅拌机的截图。

However it still gave me 13 FPS. Meanwhile to make another test I created in blender the same map as it was in the previous program. Next I grouped everything in just one object (without any additional editions). This way I created one BIG object of size almost 1MB, it can be seen on the screenshot from blender.

我的方式,它吸引只有这一个大对象改变了测试程序:

I changed the test program in a way that it draws only this one BIG object:

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

接下来的事情我做的是,我公司推出的方案在我的手机(索尼Xperia迷你临 - 同previously)和iPod 5G和我有... 60 FPS!

Next thing I did was that I launched the program on my phone (Sony XPeria Mini Pro - the same as previously) and iPod 5g and I've got... 60 FPS!

是否有可能使一切都在短短的绘制调用?

Is it possible to render everything in just one draw call?

推荐答案

问题解决了!我一个版本中低端移动设备上实现了60 FPS。本场比赛smootly运行。我发现了如何合并多个网格成一个网孔,使得VBO mechanizms可以使用。有这引起了网格 - 复制方法不可用多个网格在libGDX的错误。后的变化,地图被分成小扇区。每个扇区由网格具有相同的z轴值可以看出下面的图像上的:

Problem solved! I achieved 60 FPS on a ver low-end mobile device. The game runs smootly. I found out how to merge multiple Meshes into one mesh so that VBO mechanizms can be used. There was a bug in libGDX which caused the Mesh-copying method unusable with multiple meshes. After the changes, the map is divided in small sectors. Each sector consists of meshes with the same z-axis value as can be seen on the following image:

的VBO机制非常limitated,所以没有太多的顶点可以在一次性这就是为什么扇区必须相当小​​的绘制。 新的渲染不得不被写入到正确处理的呈现。和渲染器的部分被动态地合并的网眼(没有任何单独的工具,例如像。混合器)。

The VBO mechanisms are very limitated, so not many vertices can be drawn at one-time that is why the sectors have to be rather small. New renderer had to be written to handle the rendering properly. And the parts of the renderer are merging the meshes dynamically (without any seperate tool, like eg. blender).

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非常有用的。如果没有这个mechanizm这是相当不可能写出什么比少数机型更compilcated。

This can be very useful for the people trying to write their own 3D games in libGDX. Without this mechanizm it is rather impossible to write anything more compilcated than a few models.