[SOLVED] BatchNode BufferUnderflowException


#1

Hi,

I’m trying to use BatchNode in my project and I’m getting a BufferUnderflowException with the following stacktrace:

java.nio.BufferUnderflowException
at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:271)
at com.jme3.scene.BatchNode.doTransforms(BatchNode.java:556)
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:905)
at com.jme3.scene.Node.updateGeometricState(Node.java:271)
at com.jme3.scene.Node.updateGeometricState(Node.java:271)
at com.jme3.scene.Node.updateGeometricState(Node.java:271)

Getting into BatchNode code, the doTransforms method:

private void doTransforms(FloatBuffer bindBufPos, FloatBuffer bindBufNorm, FloatBuffer bindBufTangents, FloatBuffer bufPos, FloatBuffer bufNorm, FloatBuffer bufTangents, int start, int end, Matrix4f transform) {

        TempVars vars = TempVars.get();
        Vector3f pos = vars.vect1;
        Vector3f norm = vars.vect2;
        Vector3f tan = vars.vect3;

        int length = (end - start) * 3;
        int tanLength = (end - start) * 4;

        // offset is given in element units
        // convert to be in component units
        int offset = start * 3;
        int tanOffset = start * 4;

        bindBufPos.rewind();
        bindBufPos.get(tmpFloat, 0, length);

        if (bindBufNorm != null) {
            bindBufNorm.rewind();
            bindBufNorm.get(tmpFloatN, 0, length);
        }

        if (bindBufTangents != null) {
            bindBufTangents.rewind();
            bindBufTangents.get(tmpFloatT, 0, tanLength); // This is the line producing the exception

        }
....

In my case, this batch has 2544 vertices which results in vertices3 buffer except from tmpFloatT having size of vertices4 while bindBufTangents is vertices*3 causing the buffer underflow.

Tangents for all geometries added to the BatchNode before running batch() are created using the TangentBinormalGenerator generate method which getting into the code generates a buffer of size vertices*3 :

....
    private static void processTriangleData(Mesh mesh, VertexData[] vertices,
            boolean approxTangent)
    {
        FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();

        FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 3);
....

In adition to that, as far as I undertand, the 4th position for each vertex is not used or set. Also from BatchNode.doTransforms:

....
            if (bindBufTangents != null) {
                tanIndex1 = tanIndex + 1;
                tanIndex2 = tanIndex + 2;
                tan.x = tmpFloatT[tanIndex];
                tan.y = tmpFloatT[tanIndex1];
                tan.z = tmpFloatT[tanIndex2];
                transform.multNormal(tan, tan);
                tmpFloatT[tanIndex] = tan.x;
                tmpFloatT[tanIndex1] = tan.y;
                tmpFloatT[tanIndex2] = tan.z;
                tanIndex += 4;
            }
....

Maybe tangents should be created using 4 floats for each vertex, maybe BatchNode should use vertices*3 temp tangent buffer, maybe I’m missing something…

Thank you for your answers :wink:


#2

OK, it was completely something I was missing. I started this project long ago with jme3 alpha2 and back then, if I remember correctly, the tangentBinormalGenerator didn’t work properly or I had some issues with it, so I forked it inside my project, so the code using just 3 coordinates per vertex is the old code back then creating the issue :confused: :man_facepalming:

I removed it from the project and changed the imports to use the current generator and it works as expected :stuck_out_tongue: