BatchNode BufferOverflowException when modifying mesh data

So I got an odd (maybe) problem on my hands. I have a bunch of geometries attached to a batch node which is .batch()ed when they’re all added.

Then later on I’d like to modify the mesh vertex data buffer (and keep the number of vertices the same, just change the positions) like so:

Mesh m = ((Geometry)s).getMesh();
m.setBuffer(Type.Position, 3, new float[]{0,0,0,      fin.x,fin.y,fin.z,});
m.updateBound();

But then for some reason the BatchNode decides that things are getting weird and triggers an overflow.

Oct 17, 2016 8:18:29 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.nio.BufferOverflowException
	at java.nio.DirectFloatBufferU.put(Unknown Source)
	at com.jme3.scene.BatchNode.doTransforms(BatchNode.java:637)
	at com.jme3.scene.BatchNode.updateSubBatch(BatchNode.java:172)
	at com.jme3.scene.Geometry.updateWorldTransforms(Geometry.java:286)
	at com.jme3.scene.Spatial.updateGeometricState(Spatial.java:713)
	at com.jme3.scene.BatchNode.updateGeometricState(BatchNode.java:120)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.scene.Node.updateGeometricState(Node.java:175)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:247)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
	at java.lang.Thread.run(Unknown Source)

Which points to the marked line (from 3.0 source):

    vars.release();
    bufPos.position(offset);

    bufPos.put(tmpFloat, 0, length); //<-- this one
    bufNorm.position(offset);

    bufNorm.put(tmpFloatN, 0, length);

I’m not sure how the BatchNode works so I’m kind of clueless on how to fix it. @nehon I see you’re the author, got any ideas?

We kind of have to take your word for it that the old buffer also had only two vertexes in it.

It shouldn’t be the issue but try removing the extraneous comma, though.

Sorry, forgot to include that. I’m using the Line class with the twin vector constructor:

Line l = new Line(new Vector3f(), new Vector3f());

And I copied that buffer change from the class itself so I’m quite sure it’s right.

protected void updateGeometry(Vector3f start, Vector3f end) {
    this.start = start;
    this.end = end;
    setBuffer(Type.Position, 3, new float[]{start.x,    start.y,    start.z,
                                            end.x,      end.y,      end.z,});


    setBuffer(Type.TexCoord, 2, new float[]{0, 0,
                                            1, 1});

    setBuffer(Type.Normal, 3, new float[]{0, 0, 1,
                                          0, 0, 1});

    setBuffer(Type.Index, 2, new short[]{0, 1});

    updateBound();
}

Still, I tried to remove the comma but it gives the same result.

Ok so to be sure i understand. You have several line geometries and you batch them in a BatchNode. Then you modify one of the lines mesh position buffer. Is that right?
It should not crash, but it will mess things up. Batch Node is not done to handle underlying meshes manual modification, only local transforms. Also the position buffer of the underlying mesh is used as a reference for the BatchNode mesh modification.

That said the error seems more like a missing rewind in the buffer handling or something like this. Hard to tell, it could help if you had a test case to offer.

For this use case, I’d really advise that you make your own mesh and not use the BatchNode.

1 Like

You know what, I’ll give the full custom mesh way a try! Haven’t even considered that :smile:

So would something like this make two separate lines (in the same space)?

setBuffer(Type.Position, 3, new float[]{start.x,    start.y,    start.z,
                                        end.x,      end.y,      end.z,
                                        start.x,    start.y,    start.z,
                                        end.x,      end.y,      end.z,});


setBuffer(Type.TexCoord, 2, new float[]{0, 0,
                                        1, 1
                                        2, 2
                                        3, 3});

setBuffer(Type.Normal, 3, new float[]{0, 0, 1,
                                      0, 0, 1
                                      0, 0, 1
                                      0, 0, 1});

setBuffer(Type.Index, 2, new short[]{0, 1
                                      2,3});

You could also modify the position of your vertices using the vertex shader, provided that you can calculate their position with the available resources.

Hmm, yeah I suppose I could do that too but first I need a mesh to modify.

Well, you are using the same coordinates for both lines… I suspect that’s a typo.

An index buffer is unnecessary since you won’t be sharing any points. Index buffers are basically useless wastes of space for lines.

I’d modify the positions later, on the fly. :slight_smile:

Oh, but how does the mesh then know which two vertices to connect to each other? I thought that was the point of the index buffer.

The point of the index buffer is to share vertices. For just individual triangles or things like lines then it doesn’t make much sense (unless you will be sharing lots of vertices).

Without an index buffer, it’s exactly like if you had an index buffer [0, 1, 2, 3, 4, 5, 6, 7, 8, …]. So when your vertexes are already in the right order and unshared then you don’t need one.

Well in this specific case yes, but I doubt there’s something built in that takes a default value if the buffer doesn’t exist.

??? I make meshes without index buffers all the time.

you only need them when you share vertexes. Else they are superfluous wastes of space. Seriously.

1 Like

Huh. I thought that was a rant/what-if. Thanks then!

I’m not sure that’s exactly right though. If I don’t give it an index buffer it defaults to 3 numbers and gives me a bunch of triangles.

Besides, we’re talking about 30 lines. Not like the gpu is gonna run out of ram from 60 shorts, is it?

Got it working now.

Edit: For anyone else looking at this thread later doing anything simillar, you also need to enable mesh.setMode(Mode.Lines); so you don’t stare at a blank screen wondering what you messed up for 10 minutes like me.

Also, you did not remove that last comma, as pspeed suggested.
I wonder what this does - might it add another zero float at the last position?

I did remove it in my actual code which is a bunch of for loops and it made no difference either way.

I’ll put it on monthly showcase once it’s done.

setBuffer(Type.Position, 3, new float[]{start.x,    start.y,    start.z,
                                        end.x,      end.y,      end.z,
                                        start.x,    start.y,    start.z,
                                        end.x,      end.y,      end.z,});

I still wonder, what this does. It’s strange that this code does compile at all.
It’s simple to find out - just get the length of such an array and if it’s not 12 something unwanted happens. :slight_smile:

sigh Tried it out since you asked so nicely. It ignores the last comma.

Happy?

Somewhat happy, yes. :slight_smile:

I did not expect you to do that. I would have checked it myself as soon as my dev computer is fixed. But hey, now we know… :stuck_out_tongue_winking_eye:

It’s not magic. Index buffers are an optimization not a requirement. Even for triangles, if you don’t give it an index buffer then it will try to take the first three positions and make a triangle. Then the next three positions and make a triangle, etc…

Or cut-paste Line to get started which already does this in its constructor. :slight_smile: