Render Box shape with index and interleave buffers

Hi,

I want to render a bunch of boxes (shape that extends from AbstractBox) with an index buffer and an interleaved buffer because of the index buffer reduces the size of memory allocations and the interleaved data buffer reduces cache misses and overhead on the GPU.

So I have made a simple test scene. But all I see are some white quads instead of a bunch of boxes with the normal debug shader applied. I had to modify the method Mesh.updateCounts() because of it doesn’t work with interleaved buffers.

Am I doing something wrong or is it a engine render bug? Why is Mesh.setInterleaved() deprecated?

screenshot:

source code:

Mesh.java
[java]
@@ -773,11 +758,23 @@
*/
public void updateCounts()
{

  •   VertexBuffer ib = getBuffer(Type.Index);
    
  •   if (getBuffer(Type.InterleavedData) != null)
    
  •   	throw new IllegalStateException("Should update counts before interleave");
    
  •   {
    
  •   	if (ib != null)
    
  •   	{
    
  •   		vertCount = ib.getData().limit() / ib.getNumComponents();
    
  •   	}
    
  •   	else
    
  •   	{
    
  •   		throw new IllegalStateException("Should update counts before interleave");
    
  •   	}
    
  •   	return;
    
  •   }
    
      VertexBuffer pb = getBuffer(Type.Position);
    
  •   VertexBuffer ib = getBuffer(Type.Index);
    
  •   if (pb != null)
      {
      	vertCount = pb.getData().limit() / pb.getNumComponents();
    

[/java]

RenderTest.java
[java]
package net.qb.tests.RenderTest;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.scene.BatchNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;

public class RenderTest extends SimpleApplication
{
RenderTest app;

public RenderTest()
{
	app = this;
	app.setPauseOnLostFocus(false);
	AppSettings settings = new AppSettings(false);
	settings.setRenderer(AppSettings.LWJGL_OPENGL2);
	app.setSettings(settings);
	app.start(); // start the game
}

public static void main(String[] args)
{
	new RenderTest();
}

@Override
public void simpleInitApp()
{
	app.getFlyByCamera().setMoveSpeed(25);

	int sizeX = 16;
	int sizeY = 16;
	int sizeZ = sizeX;

	switch (0)
	{
		case 0:
			noBatch(sizeX, sizeY, sizeZ);
			break;
		case 1:
			tileBatch(sizeX, sizeY, sizeZ);
			break;
		case 2:
			wholeBatch(sizeX, sizeY, sizeZ);
			break;
	}

	System.out.println("finish");
}

private void wholeBatch(int sizeX, int sizeY, int sizeZ)
{
	BatchNode batch = new BatchNode();

	for (int x = 0; x < sizeX; x++)
	{
		for (int z = 0; z < sizeZ; z++)
		{
			for (int y = 0; y < sizeY; y++)
			{
				createMesh(batch, x, y, z);
			}
		}
	}

	batch.batch();
	rootNode.attachChild(batch);
}

private void tileBatch(int sizeX, int sizeY, int sizeZ)
{
	for (int x = 0; x < sizeX; x++)
	{
		for (int z = 0; z < sizeZ; z++)
		{
			BatchNode batch = new BatchNode();

			for (int y = 0; y < sizeY; y++)
			{
				createMesh(batch, x, y, z);
			}

			batch.batch();
			rootNode.attachChild(batch);
		}
	}
}

private void noBatch(int sizeX, int sizeY, int sizeZ)
{
	for (int x = 0; x < sizeX; x++)
	{
		for (int z = 0; z < sizeZ; z++)
		{
			for (int y = 0; y < sizeY; y++)
			{
				createMesh(rootNode, x, y, z);
			}
		}
	}
}

public void createMesh(Node node, int x, int y, int z)
{
	// Box b = new Box(0.5f, 0.5f, 0.5f);
	BoxInterleaved b = new BoxInterleaved(0.5f, 0.5f, 0.5f);
	// b.updateCounts();
	// b.setInterleaved();
	// b.setStatic();
	Geometry geom = new Geometry("Box", b);
	Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
	geom.setMaterial(mat);
	geom.setLocalTranslation(x, y, z);
	node.attachChild(geom);
}

}
[/java]

BoxInterleaved.java
[java]
package net.qb.tests.RenderTest;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

import com.jme3.math.Vector3f;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.shape.AbstractBox;
import com.jme3.util.BufferUtils;

public class BoxInterleaved extends AbstractBox
{
private static final short[] GEOMETRY_INDICES_DATA = { //
2, 1, 0, 3, 2, 0, // back
6, 5, 4, 7, 6, 4, // right
10, 9, 8, 11, 10, 8, // front
14, 13, 12, 15, 14, 12, // left
18, 17, 16, 19, 18, 16, // top
22, 21, 20, 23, 22, 20 // bottom
};

private static final float[] GEOMETRY_NORMALS_DATA = {//
0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, // back
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // right
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // front
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // left
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // top
0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 // bottom
};

private static final float[] GEOMETRY_TEXTURE_DATA = {//
1, 0, 0, 0, 0, 1, 1, 1, // back
1, 0, 0, 0, 0, 1, 1, 1, // right
1, 0, 0, 0, 0, 1, 1, 1, // front
1, 0, 0, 0, 0, 1, 1, 1, // left
1, 0, 0, 0, 0, 1, 1, 1, // top
1, 0, 0, 0, 0, 1, 1, 1 // bottom
};

public BoxInterleaved(float x, float y, float z)
{
	super();
	updateGeometry(Vector3f.ZERO, x, y, z);
}

@Deprecated
public BoxInterleaved(Vector3f center, float x, float y, float z)
{
	super();
	updateGeometry(center, x, y, z);
}

public BoxInterleaved(Vector3f min, Vector3f max)
{
	super();
	updateGeometry(min, max);
}

/**
 * Empty constructor for serialization only. Do not use.
 */
public BoxInterleaved()
{
	super();
}

@Override
public BoxInterleaved clone()
{
	return new BoxInterleaved(center.clone(), xExtent, yExtent, zExtent);
}

@Override
protected void duUpdateGeometryIndices()
{
}

@Override
protected void duUpdateGeometryNormals()
{
}

@Override
protected void duUpdateGeometryTextures()
{
}

@Override
protected void duUpdateGeometryVertices()
{
	// size = ((vertComponents * verts * 2 (verts & normals) + texCoords) * six faces) * 4 float bytes
	ByteBuffer byteBuffer = BufferUtils.createByteBuffer((3 * 4 * 2 + 8) * 6 * 4);
	FloatBuffer fpb = byteBuffer.asFloatBuffer();

	Vector3f[] v = computeVertices();

	float[] verts = new float[] { //
	v[0].x, v[0].y, v[0].z, v[1].x, v[1].y, v[1].z, v[2].x, v[2].y, v[2].z, v[3].x, v[3].y, v[3].z, // back
	v[1].x, v[1].y, v[1].z, v[4].x, v[4].y, v[4].z, v[6].x, v[6].y, v[6].z, v[2].x, v[2].y, v[2].z, // right
	v[4].x, v[4].y, v[4].z, v[5].x, v[5].y, v[5].z, v[7].x, v[7].y, v[7].z, v[6].x, v[6].y, v[6].z, // front
	v[5].x, v[5].y, v[5].z, v[0].x, v[0].y, v[0].z, v[3].x, v[3].y, v[3].z, v[7].x, v[7].y, v[7].z, // left
	v[2].x, v[2].y, v[2].z, v[6].x, v[6].y, v[6].z, v[7].x, v[7].y, v[7].z, v[3].x, v[3].y, v[3].z, // top
	v[0].x, v[0].y, v[0].z, v[5].x, v[5].y, v[5].z, v[4].x, v[4].y, v[4].z, v[1].x, v[1].y, v[1].z // bottom
	};

	// put data for 24 vertices * components into the buffer
	for (int i = 0, j = 0; i < 72; i += 3, j += 2)
	{
		fpb.put(verts[i + 0]);
		fpb.put(verts[i + 1]);
		fpb.put(verts[i + 2]);

		fpb.put(GEOMETRY_NORMALS_DATA[i + 0]);
		fpb.put(GEOMETRY_NORMALS_DATA[i + 1]);
		fpb.put(GEOMETRY_NORMALS_DATA[i + 2]);

		fpb.put(GEOMETRY_TEXTURE_DATA[j + 0]);
		fpb.put(GEOMETRY_TEXTURE_DATA[j + 1]);
	}

	if (getBuffer(Type.Index) == null)
	{
		setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(GEOMETRY_INDICES_DATA));
	}

	setBuffer(Type.InterleavedData, 1, byteBuffer);

	updateBound();
}

}
[/java]

Hi,
I know my english is bad, but what’s the problem? Could my question not be understood or is the description of the problem too complicated?

best regards

Alrik

I think no one has needed interleaved in a very very long time so no one is using it… so probably no one knows how to answer your question.

It’s likely that you don’t actually need it and that any performance problems you think you are having could be solved in simpler ways. Hard to say for sure.

What do you mean with “very very long time”? I have read (forum threads from 2012-2013) It’s general recommended to interleave the vertex buffers. I have 8 different vertex buffers (not in the test scene above) and I want to test if there is any performance gain or not if they are interleaved. It’s also a common way to interleaved vertex buffers on mobile devices.

@alrik said: What do you mean with "very very long time"? I have read (forum threads from 2012-2013) It's general recommended to interleave the vertex buffers. I have 8 different vertex buffers (not in the test scene above) and I want to test if there is any performance gain or not if they are interleaved. It's also a common way to interleaved vertex buffers on mobile devices.

Well, then if it’s popular I guess someone will eventually respond.

Actually, the javadoc has this to say on the subject:
http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/Mesh.html#setInterleaved()

Interleaves the data in this mesh. This operation cannot be reversed. Some GPUs may prefer the data in this format, however it is a good idea to avoid using this method as it disables some engine features.

And looking at the code, ‘index buffers’ is one of the things that is unsupported.
[java]
// index buffer not included when interleaving
vbs.remove(getBuffer(Type.Index));
[/java]

Don’t be afraid to look at the javadoc and code if you are having issues like this.

ok so I will try it on my own way thanks :S

edit: I didn’t use the method setInterleveaved. I only want to know why it is deprecated. It is possible and wise to use index buffers and interleaved buffer together