1

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;
    }
}

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Bo Bramer
  • 35
  • 1
  • 6

1 Answers1

0

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);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Thanks for the response. I had that initially, but then it threw the error: ```java.lang.IllegalArgumentException: remaining() < size < needed at android.opengl.GLES20.glBufferData(Native Method)```. Removing the *4 fixed it, so I'm not sure if that's the issue. – Bo Bramer Mar 21 '21 at 11:36
  • @BoBramer So you had the correct code but removed it? – Rabbid76 Mar 21 '21 at 11:40
  • Yeah, I removed it because including that made the entire application crash with the ```java.lang.IllegalArgumentException```. By removing the ```*4```, the program works, but nothing is rendered and it sends the ```D/emuglGLESv2_enc: sendVertexAttributes: bad offset / len!!!!!``` error message. – Bo Bramer Mar 21 '21 at 11:43
  • @BoBramer I do not guess here. You have to specify the buffer size in bytes. – Rabbid76 Mar 21 '21 at 11:44
  • Okay, then how would I fix the ```java.lang.IllegalArgumentException``` error? I agree the including the ```*4``` is the proper way of doing it, but it makes my entire application crash. – Bo Bramer Mar 21 '21 at 11:45
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/230180/discussion-between-bo-bramer-and-rabbid76). – Bo Bramer Mar 21 '21 at 11:46
  • 1
    This is an error message from the emulator https://android.googlesource.com/device/generic/goldfish-opengl/+/emu-master-qemu-release/system/GLESv2_enc/GL2Encoder.cpp (line 1104) – Rabbid76 Mar 08 '22 at 17:02