Brand new Lod Generator

I was unable to use the manual LOD settings because Ogre files would not work properly for me. So I had to create my own swapping code.

The only way I was able to use the setLodLevel method of in the Spatial Class was to use the LOD generator.

Is there no way in code to tell the LOD algorithm… “use model A for LOD0”, “Use model B for LOD1” ?

Not that I was able to find. That is why I ended up making my own swap code until the LOD generator became available.

@dm1056 said: Also in the SDK Lod Generator there are 1 to many text boxes and if you enter a value in all boxes it generates an index out of bounds error and does not create the LODs.

The last text box should be removed.


Yep I fixed this recently but there is no SDK nightly.

@DieSlower said: Is there no way in code to tell the LOD algorithm.. "use model A for LOD0", "Use model B for LOD1" ?
Nope, you have to make your own control for this.
@DieSlower said: Right...the GPU will make the mipmaps...but it will still have the large texture in VRAM instead of the smaller one. So it's more efficient to pass a smaller texture with a lower LOD (i think), correct me if I'm wrong though.
Well what you are talking about is not a mipmap then. Mipmaps are not meant to reduce memory usage. In fact a texture with mipmap will consume more memory than a texture without. Mipmaps are meant to avoid some aliasing artifacts when rendering far textures and to speed up the rendering since the GPU will fetch texels in smaller maps. Not sure what you describe would really save memory that much and would exhibit other issues, because it would mean to reupload the full res image as you get closer to the rendered object, and the problem won't be memory then but bandwidth.

Correct,
The texture with mipmaps will take up more Vram, but I would think that the generation of mipmaps from the smaller texture will also be faster, and look up of texels will also be quicker.
You would be using up more bandwidth and less ram overall. I guess it depends on what your current project needs.
Cant be sure what truly better.

@nehon said: Yep I fixed this recently but there is no SDK nightly.

Nope, you have to make your own control for this.

Well what you are talking about is not a mipmap then. Mipmaps are not meant to reduce memory usage. In fact a texture with mipmap will consume more memory than a texture without.
Mipmaps are meant to avoid some aliasing artifacts when rendering far textures and to speed up the rendering since the GPU will fetch texels in smaller maps.
Not sure what you describe would really save memory that much and would exhibit other issues, because it would mean to reupload the full res image as you get closer to the rendered object, and the problem won’t be memory then but bandwidth.

While currently not in jme, you might want to read about sparse_textures, basically they are developed for that.
However keep in mind that with normal opengl drivers the driver is free to swap vram, in face opengl has no real seperate concept of vram at all, so it is allowed to swap out currently not necessary mipmap levels.

sparse_textures would be amazing! is this done by OpenGL automatically or falls to the engine to implement?
I haven’t looked at the latest OpenGL improvements for the past few versions…so im not up to date for the time being…

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 :wink:

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?

@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