VAO rendering using GLES30: bad offset / len !!!!! error

Viewed 121

When trying to render a cube using VAO in GLES30 on an android, I get the following error message:

D/emuglGLESv2_enc: sendVertexAttributes: bad offset / len!!!!!

Does anyone know what this means and how to fix it? I cannot find any documentation for it anywhere, and the functions don't act like they do in lwjgl in normal java. Here is my render class:

/**
   * renders an object
   * @param object - the mesh object to be rendered
   */
  public void renderMesh(MeshObject object) {

      // bind the vertex array
      GLES30.glBindVertexArray(object.getMesh().getVAO()[0]);

      // get the attrib pointers
      int pAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vPosition");
      int nAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vNormal");
      int tAttrib = GLES30.glGetAttribLocation(shaderProgramID, "vTextureCoords");

      // enable the attributes
      GLES30.glEnableVertexAttribArray(pAttrib); // position attribute
      GLES30.glEnableVertexAttribArray(nAttrib); // normal attribute
      GLES30.glEnableVertexAttribArray(tAttrib); // texture attribute

      // send empty data
      GLES30.glVertexAttribPointer(pAttrib, 3, GLES30.GL_FLOAT, false, 3 * 4, 0);
      GLES30.glVertexAttribPointer(nAttrib, 3, GLES30.GL_FLOAT, false, 3 * 4, 0);
      GLES30.glVertexAttribPointer(tAttrib, 2, GLES30.GL_FLOAT, false, 2 * 4, 0);

      // bind the index buffer
      GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, object.getMesh().getIBO()[0]);

      // bind the shader
      GLES30.glUseProgram(shaderProgramID);

      // bind the texture
      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, object.getMesh().getTextureID());

      // get pointers to the uniform locations
      int viewPositionHandle = GLES30.glGetUniformLocation(shaderProgramID, "viewPos");
      int mHandle = GLES30.glGetUniformLocation(shaderProgramID, "vModel");
      int vHandle = GLES30.glGetUniformLocation(shaderProgramID, "vView");
      int pHandle = GLES30.glGetUniformLocation(shaderProgramID, "vProjection");

      // set the uniforms
      GLES30.glUniform3fv(viewPositionHandle, 1, camera.getPosition().toFloatArray(), 0);
      GLES30.glUniformMatrix4fv(mHandle, 1, false, object.getModelMatrix(), 0);
      GLES30.glUniformMatrix4fv(vHandle, 1, false, camera.getViewMatrix(), 0);
      GLES30.glUniformMatrix4fv(pHandle, 1, false, surfaceRenderer.getProjectionMatrix(), 0);

      // draw the triangles specified by the index buffer
      GLES30.glDrawElements(GLES30.GL_TRIANGLES, object.getMesh().getIndices().length, GLES30.GL_UNSIGNED_INT, 0);

      // unbind the shader
      GLES30.glUseProgram(0);

      // unbind the index buffer
      GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);

      // disable the vertex attributes
      GLES30.glDisableVertexAttribArray(pAttrib); // position attribute
      GLES30.glDisableVertexAttribArray(nAttrib); // normal attribute
      GLES30.glDisableVertexAttribArray(tAttrib); // texture attribute

      // unbind the vertex array
      GLES30.glBindVertexArray(0);
  }

And here is my Mesh class:

package com.bramerlabs.productivitree.graphics_engine.graphics;

import android.opengl.GLES30;

import com.bramerlabs.productivitree.graphics_engine.math.Vertex;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

public class Mesh {

    // the vertex array object
    private final int[] vao = new int[1];

    // the buffer objects
    private final int[] pbo = new int[1]; // position buffer object
    private final int[] nbo = new int[1]; // normal buffer object
    private final int[] tbo = new int[1]; // texture buffer object
    private final int[] ibo = new int[1]; // index buffer object

    private final Vertex[] vertices;
    private final int[] indices;
    private final int textureID;

    /**
     * default constructor
     *
     * @param vertices - a list of vertices in the mesh
     * @param indices - the order in which the vertices should be drawn
     */
    public Mesh(Vertex[] vertices, int[] indices, int textureID) {
        this.vertices = vertices;
        this.indices = indices;
        this.textureID = textureID;
    }

    /**
     * creates the mesh
     */
    public void create() {
        // generate and bind the vertex array
        GLES30.glGenVertexArrays(1, vao, 0);
        GLES30.glBindVertexArray(vao[0]);

        // generate the data arrays
        // generate the position buffer object
        float[] positionData = new float[vertices.length * 3];
        for (int i = 0; i < vertices.length; i++) {
            positionData[3 * i] = vertices[i].getPosition().getX();
            positionData[3 * i + 1] = vertices[i].getPosition().getY();
            positionData[3 * i + 2] = vertices[i].getPosition().getZ();
        }
        FloatBuffer positionBuffer = createFloatBuffer(positionData, 3);

        // generate the normal buffer object
        float[] normalData = new float[vertices.length * 3];
        for (int i = 0; i < vertices.length; i++) {
            positionData[3 * i] = vertices[i].getNormal().getX();
            positionData[3 * i + 1] = vertices[i].getNormal().getY();
            positionData[3 * i + 2] = vertices[i].getNormal().getZ();
        }
        FloatBuffer normalBuffer = createFloatBuffer(normalData, 3);

        // generate the texture buffer object
        float[] textureData = new float[vertices.length * 2];
        for (int i = 0; i < vertices.length; i++) {
            textureData[2 * i] = vertices[i].getTextureCoord().getX();
            textureData[2 * i + 1] = vertices[i].getTextureCoord().getY();
        }
        FloatBuffer textureBuffer = createFloatBuffer(textureData, 2);

        // generate the index buffer object
        ByteBuffer bb = ByteBuffer.allocateDirect(indices.length * 4);
        bb.order(ByteOrder.nativeOrder());
        IntBuffer indexBuffer = bb.asIntBuffer();
        indexBuffer.put(indices).flip();
        indexBuffer.position(0);

        // store the data
        storeData(pbo, positionBuffer, 0, 3);
        storeData(nbo, normalBuffer, 1, 3);
        storeData(tbo, textureBuffer, 2, 2);

        // create the index buffer
        GLES30.glGenBuffers(1, ibo, 0);
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
        GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity(), indexBuffer, GLES30.GL_STATIC_DRAW);
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
    }

    /**
     * stores buffer data in an index
     */
    private void storeData(int[] location, FloatBuffer buffer, int index, int size) {
        // generate a buffer at the location
        GLES30.glGenBuffers(1, location, 0);

        // bind the buffer
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, location[0]);

        // add the data to the buffer
        GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, buffer.capacity(), buffer, GLES30.GL_STATIC_DRAW);

        // set the data type attribute
        GLES30.glVertexAttribPointer(index, size, GLES30.GL_FLOAT, false, 0, 0);

        // unbind the buffer
        GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
    }

    /**
     * creates a buffer
     * @param data - a float array of data
     * @param stride - the stride of the data
     * @return - a float buffer containing the data
     */
    private FloatBuffer createFloatBuffer(float[] data, int stride) {
        // initialize empty float buffer
        ByteBuffer bb = ByteBuffer.allocateDirect(data.length * stride * 4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer dataBuffer = bb.asFloatBuffer();

        // add the data to the float buffer and flip it
        dataBuffer.put(data).flip();

        // seek to the first position
        dataBuffer.position(0);
        return dataBuffer;
    }

    /**
     * getter method
     * @return - the position buffer object
     */
    public int[] getPBO() {
        return this.pbo;
    }

    /**
     * getter method
     * @return - the normal buffer object
     */
    public int[] getNBO() {
        return this.nbo;
    }

    /**
     * getter method
     * @return - the texture buffer object
     */
    public int[] getTBO() {
        return this.tbo;
    }

    /**
     * getter method
     * @return - the index buffer object
     */
    public int[] getIBO() {
        return this.ibo;
    }

    /**
     * getter method
     * @return - the vertex array object
     */
    public int[] getVAO() {
        return this.vao;
    }

    /**
     * getter method
     * @return - the draw order
     */
    public int[] getIndices() {
        return this.indices;
    }

    /**
     * getter method
     * @return - the vertices
     */
    public Vertex[] getVertices() {
        return this.vertices;
    }

    public int getTextureID() {
        return this.textureID;
    }
}

1 Answers

The 2nd argument of glBufferData is the size of the buffer in bytes, but not the number of elements in the array.
The byte size of an element in a FloatBuffer or IntBuffer is 4:

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, buffer.capacity(), buffer, GLES30.GL_STATIC_DRAW);

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, 
    buffer.capacity() * 4, buffer, GLES30.GL_STATIC_DRAW);

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity(), indexBuffer, GLES30.GL_STATIC_DRAW);

GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, 
    indexBuffer.capacity() * 4, indexBuffer, GLES30.GL_STATIC_DRAW);
Related