BatchNode, IndexOutOfBoundsException (again)

Hi everyone,

I have encountered an IndexOutOfBoundsException from BatchNode, which I think is the same issue others have seen - but this time I’ve been able to reproduce it with a SSCE.

Exception:

java.lang.IndexOutOfBoundsException
	at java.nio.Buffer.checkBounds(Buffer.java:567)
	at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:265)
	at com.jme3.scene.BatchNode.doTransforms(BatchNode.java:548)
	at com.jme3.scene.BatchNode.updateSubBatch(BatchNode.java:152)
	at com.jme3.scene.BatchNode.onTransformChange(BatchNode.java:104)
	at com.jme3.scene.Geometry.updateWorldTransforms(Geometry.java:326)
	at com.jme3.scene.Spatial.updateGeometricState(Spatial.java:911)
	at com.jme3.scene.Node.updateGeometricState(Node.java:269)
	at com.jme3.scene.Node.updateGeometricState(Node.java:269)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:265)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:153)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:234)
	at java.lang.Thread.run(Thread.java:745)

SSCE:

import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.BatchNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;

public class TestBatchNodeDifferentShapes extends SimpleApplication {

	public static void main(String[] args){
		TestBatchNodeDifferentShapes app = new TestBatchNodeDifferentShapes();
		app.setShowSettings(false);  // disable the initial settings dialog window
		app.start();
	}

	@Override
	public void simpleInitApp() {
		flyCam.setMoveSpeed(30);
		addAmbientLight();
		addDirectionalLight();
		addFloor();

		BatchNode theBatchNode = new BatchNode("theBatchNode");
		rootNode.attachChild(theBatchNode);

		Material boxMat = createLightingMaterial(ColorRGBA.Yellow);
		Material sphereMat = createLightingMaterial(ColorRGBA.Pink);

		Mesh boxMesh = new Box(0.7f, 0.7f, 0.7f);
		Mesh sphereMesh = new Sphere(32, 32, 1f);

		// 1) add spheres
		for (int z = 0; z < 10; z++) {
			Geometry sphere = new Geometry("sphere", sphereMesh);
			sphere.setMaterial(sphereMat);
			sphere.setLocalTranslation(new Vector3f(-2, -3, -(z * 4)));
			theBatchNode.attachChild(sphere);
		}

		theBatchNode.batch();


		// 2) add boxes
		for (int z = 0; z < 10; z++) {
			Geometry box = new Geometry("box", boxMesh);
			box.setMaterial(boxMat);
			box.setLocalTranslation(new Vector3f(+2, -3, -(z * 4)));
			theBatchNode.attachChild(box);
		}

		theBatchNode.batch();
	}


	private Material createLightingMaterial(ColorRGBA color) {
		Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
		material.setBoolean("UseMaterialColors", true);
		material.setColor("Ambient", color);
		material.setColor("Diffuse", color);
		material.setColor("Specular", color);
		material.setFloat("Shininess", 1.0f);
		return material;
	}

	private void addFloor() {
		Geometry floor = new Geometry("floor", new Box(20, 0.1f, 40));
		floor.setMaterial(createLightingMaterial(ColorRGBA.Gray));
		floor.setLocalTranslation(5, -5, 0);
		floor.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
		rootNode.attachChild(floor);
	}

	private void addAmbientLight() {
		AmbientLight ambientLight = new AmbientLight(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
		rootNode.addLight(ambientLight);
	}

	private void addDirectionalLight() {
		DirectionalLight light = new DirectionalLight();

		light.setColor(ColorRGBA.White);
		light.setDirection(new Vector3f(-1, -2, -0.5f));

		rootNode.addLight(light);
	}
}

The problem only happens if I batch the spheres, then the boxes. If I do it the other way around then the exception does not occur. I thought BatchNode ought to be able to handle this case, even though you might reasonably suggest that I don’t call batch() until all the spatials are added.

I get the same results from 3.3.2-stable and from master.

Probably related topics:

So with either order, if you batch just once then it also works?

…wonder if there is some book-keeping that happens on update() that gets confused by the double batching.

Correct - if I remove the first batch() call, it works. If I add boxes then spheres, with only one batch call, it works. And if I add boxes then spheres, with a batch call after each set - then it also works. It’s just this specific case.

1 Like