Brand new Lod Generator

@simon.heinen said: I tried to use the LodGenerator to reduce the number of vertices on my models on the fly because on Android I sometimes get (com.jme3.renderer.RendererException: OpenGL ES does not support 32-bit index buffers. Split your models to avoid going over 65536 vertices. ) errors and wanted to avoid them. I dont have influence over the models because the users pick them, so I cant just use smaller models ;)

Here is what I tried:

[java]
private void reduceVertexCount(Spatial node) {

	if (node instanceof Node) {
		for (Spatial s : ((Node) node).getChildren()) {
			reduceVertexCount(s);
		}
	} else if (node instanceof Geometry) {
		Geometry geometry = (Geometry) node;
		Mesh mesh = geometry.getMesh();

		System.out
				.println("mesh.getVertexCount()=" + mesh.getVertexCount());

		LodGenerator lodGenerator = new LodGenerator(geometry);
		VertexBuffer[] reducedMesh = lodGenerator.computeLods(
				LodGenerator.TriangleReductionMethod.PROPORTIONAL, 0.5f);
		VertexBuffer newIndexBuffer = reducedMesh[0];

		mesh.clearBuffer(newIndexBuffer.getBufferType());
		mesh.setBuffer(newIndexBuffer);

		System.out.println("new mesh.getVertexCount()="
				+ mesh.getVertexCount());
	}
}

[/java]

The code runs but the number of vertices does not change on my test data:
mesh.getVertexCount()=107844
new mesh.getVertexCount()=107844

Can someone tell my what I am doing wrong?

Afaik the lod generator works on indices, not on vertices. So you always keep your amount of vertices but only a few of them are actually rendered.

@normen said: Afaik the lod generator works on indices, not on vertices. So you always keep your amount of vertices but only a few of them are actually rendered.

Ok that explains why I only have to exchange the index buffer :wink: How hard would it be to implement the “cleanup” of the vertex buffer based on the new index buffer? I probably have to loop over all indices and remove the unused vertices (and which other buffers do I need to clean up then as well?) Or is there a better way?

You need to clean up all the buffers attached to the mesh actually, with no exception.
It’s not complicated but it’s tedious.
I recommend making another mesh compiled from the old one. For each index in the ne index buffer, you extract its data from all the buffers and copy it in the new mesh’s buffers.

1 Like

…and of course create a remapping of the indexes as you go so you can write a new index buffer.

Hei everyone ,
I would like to use the lodGenerator for vertex reduction and have implemented the following code as a test:

                Geometry geometry = (Geometry) node;
		Mesh mesh = geometry.getMesh();

		System.out.println("mesh.getVertexCount()=" + mesh.getVertexCount());
		System.out.println("mesh.getIndexBuffer().size()="
				+ mesh.getIndexBuffer().size());
		System.out.println("mesh.indexbuffer.getNumElements()="
				+ mesh.getBuffer(VertexBuffer.Type.Index).getNumElements());
		System.out.println("mesh.indexbuffer.getNumComponents())="
				+ mesh.getBuffer(VertexBuffer.Type.Index).getNumComponents());
		

		LodGenerator lodGenerator = new LodGenerator(geometry);
		VertexBuffer[] reducedMesh = lodGenerator.computeLods(
				LodGenerator.TriangleReductionMethod.PROPORTIONAL, 0.5f);
		System.out.println("reducedMesh.length=" + reducedMesh.length);
		VertexBuffer newIndexBuffer = reducedMesh[0];
		Buffer b = newIndexBuffer.getData();
		
		

		mesh.clearBuffer(newIndexBuffer.getBufferType());
		mesh.setBuffer(newIndexBuffer);
		

		System.out.println("NEU:");
	
		System.out.println("mesh.getIndexBuffer().size()="
				+ mesh.getIndexBuffer().size());
		System.out.println("new mesh.getVertexCount()="
				+ mesh.getVertexCount());
		System.out.println("newIndexBuffer.getNumElements()="
				+ newIndexBuffer.getNumElements());
		System.out.println("mesh.indexbuffer.getNumElements()="
				+ mesh.getBuffer(VertexBuffer.Type.Index).getNumElements());
		System.out.println("mesh.indexbuffer.getNumComponents()="
				+ mesh.getBuffer(VertexBuffer.Type.Index).getNumComponents());

And this is what i get as system output :

                                    mesh.getVertexCount()=17768
                                    mesh.getIndexBuffer().size()=39888
                                    mesh.indexbuffer.getNumElements()=13296
                                    mesh.indexbuffer.getNumComponents())=3
                                    reducedMesh.length=2
                                    NEU:
                                    mesh.getIndexBuffer().size()=39888
                                    new mesh.getVertexCount()=17768
                                    newIndexBuffer.getNumElements()=13296
                                    mesh.indexbuffer.getNumElements()=13296
                                    mesh.indexbuffer.getNumComponents()=3

it looks as if the old and new index buffers are the same.
What i am doing wrong? :frowning:

Lod level 0 is the original index buffer. You have to pick reduceMesh[1] to have a smaller index buffer.

What does mesh.getBuffer(VertexBuffer.Type.Index).getNumComponents() calculate ?
I thought it calculates the absolute entries in the index buffer. So the number of vertices.
But when i save all the entries in the indexbuffer and delete the duplicated entries , the number is different to the number mesh.getBuffer(VertexBuffer.Type.Index).getNumComponents() number.
Can someone explain?

Thanks :smile:

Oh sorry i mean mesh.getBuffer(VertexBuffer.Type.Index).getNumElements()

That says the number of indices in the index buffer. If you are using Mesh.Mode.Triangles then you can divide it by 3 to get the number of triangles you have.

1 Like

But how can the vertex count be bigger than the number of elements in the indexbuffer?.. In the indexbuffer each vertex is at least ones with a index integrated…or didn’t i understand it? :blush:

Oh i think i understand…not each vertex index needs to be in the index buffer,right?

The correspondence between vertices and indices is not 1:1, you may have vertices that are not used by any triangle, or vertices that are used by several.
In your case you have 39888 indices and 17768 vertices, so the vertices are shared by multiple triangles.

1 Like

i dont understand why my model has missing textures when i set the new indexbuffer and change the other buffers. :frowning:

Let me cut out the irrelevant parts and see if it makes it clearer:
“i dont understand why my model has missing textures when i change the other buffers.”

Why do you change the other buffers? If you change one buffer (say moving items around) then you would have to change ALL of them (other than index) or they will not match anymore. But first, try not changing the other buffers to see if that fixes the problem.

Thanks for your answer.
When i just set the new indexbuffer the same problem appears . I think triangles are missing.

Here my code:

Generate new index buffer :

                    LodGenerator lodGenerator = new LodGenerator(geometry);
                    VertexBuffer[] reducedMesh = lodGenerator.computeLods( LodGenerator.TriangleReductionMethod.PROPORTIONAL, 0.5f);
                    VertexBuffer newIndexBuffer = reducedMesh[1];

Set new index buffer :

mesh.clearBuffer(VertexBuffer.Type.Index);
mesh.setBuffer(newIndexBuffer);

Generate new position buffer :

        VertexBuffer buffer = mesh.getBuffer(VertexBuffer.Type.Position);
        Vector3f[] newPosArray = new Vector3f[buffer.getNumElements()];
       
  for(int index : returnArray){
      newPosArray[index] = new Vector3f();
      newPosArray[index].setX((Float) buffer.getElementComponent(index, 0));   
      newPosArray[index].setY((Float) buffer.getElementComponent(index, 1));
      newPosArray[index].setZ((Float) buffer.getElementComponent(index, 2));
     }

The same method I used for the normal buffer and the TexCoord buffer.

And at the end :

 mesh.clearBuffer(VertexBuffer.Type.TexCoord);
 mesh.clearBuffer(VertexBuffer.Type.Normal);
 mesh.clearBuffer(VertexBuffer.Type.Position);
 mesh.setBuffer(VertexBuffer.Type.TexCoord , 2 , BufferUtils.createFloatBuffer(newTextureCArray));     
 mesh.setBuffer(VertexBuffer.Type.Normal , 1 , BufferUtils.createFloatBuffer(newNormalArray));
 mesh.setBuffer(VertexBuffer.Type.Position , 3 , BufferUtils.createFloatBuffer(newPosArray));
 mesh.getBuffer(VertexBuffer.Type.TexCoord).setUpdateNeeded();
 mesh.getBuffer(VertexBuffer.Type.Normal).setUpdateNeeded();
 mesh.getBuffer(VertexBuffer.Type.Position).setUpdateNeeded();
 mesh.updateCounts(); 
 mesh.updateBound();

Why do you tell me that you tried it without modifying the buffers and it still fails… then show me code where you modify the buffers? I’m not even sure why you are copying values or what returnarray has but it’s going to be hard to convince us that it doesn’t work even when not modifying the buffers if we only see an example where you still modify the buffers. :wink:

Make a simple test case where you do LOD as intended by running your mesh through the utility and then setting the LOD level on Geometry. If your model still looks messed up then we’ll have something to talk about otherwise the problem is in your vertex manipulation and a misunderstanding of how index buffers and LOD works. Because you can’t move vertexes around without also changing the individual index buffer values.

:blush:

Do you mean:

    LodGenerator lodGenerator = new LodGenerator(geometry);
    VertexBuffer[] reducedMesh = lodGenerator.computeLods(
    LodGenerator.TriangleReductionMethod.PROPORTIONAL, 0.5f);
    VertexBuffer newIndexBuffer = reducedMesh[1];

       
    mesh.clearBuffer(VertexBuffer.Type.Index); 
    mesh.setBuffer(newIndexBuffer);

and then :

  geometry.setLodLevel(1);

No

The intended way to make it work is

    LodGenerator lodGenerator = new LodGenerator(geometry);
    VertexBuffer[] reducedMesh = lodGenerator.computeLods(LodGenerator.TriangleReductionMethod.PROPORTIONAL, 0.5f);
    mesh.setLodLevels(reducedMesh);

...
   geometry.setLodLevel(1);

Else you can even use the bakeLods method fo the generator that will assign them for you to the mesh.

See

No, I meant what I said:

Not once did I mention funky buffer manipulations that would break LOD.

When i make it like nehon said , some triangles are still missing.