我有一个问题是否有一个特殊的模式来分组模型在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,-y);
mModelBatch.render(instance);
}
}
mModelBatch.end();
我试图找到一个很好的解决方案,所以我写了另一个测试代码:
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.
同时做另一个测试,我在混合器中创建与之前程序中相同的地图.接下来,我将所有内容分组在一个对象中(没有任何其他版本).这样我就创建了一个大小接近1MB的BIG对象,可以从Blender的屏幕截图中看到.
我改变了测试程序,只能画出一个BIG对象:
mModelBatch.begin(camera);
modelInstance1.transform.setToTranslation(0,0);
mModelBatch.render(modelInstance1);
mModelBatch.end();
我做的下一件事是我在手机上启动了程序(Sony XPeria Mini Pro – 与之前相同)和iPod 5g,我已经… 60 FPS!
可以在一个绘图调用中渲染一切吗?
解决方法
问题解决了!我在一个低端移动设备上实现了60个FPS.游戏运行平稳.我发现如何将多个Meshes合并成一个网格,以便可以使用VBO机制. libGDX中有一个错误,导致网格复制方法无法使用多个网格.变更后,地图划分为小部分.每个扇区由具有相同z轴值的网格构成,如下图所示:
VBO机制是非常有限的,因此不能一次绘制多个顶点,这就是为什么这些部门必须相当小.
必须编写新的渲染器才能正确处理渲染.并且渲染器的部分动态地合并网格(没有任何单独的工具,例如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),vertexSize,offset,numComponents,vertexOffset,numVertices);
vertexOffset += numVertices;
vertexSizeOffset += baseSize;
}
Mesh result = new Mesh(true,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,attrs);
result.setVertices(vertices,numVertices * newVertexSize);
result.setIndices(indices);
return result;
}
这对于尝试在libGDX中编写自己的3D游戏的人来说可能非常有用.没有这种机制,写出比几种型号更多的编辑是不可能的.