1

I have spent a few days trying to get a VBO working on Android using OpenGL ES 2.0, but I just can't seem to get it to work.

Here is the code I am using:

/* The Android shader code */
private static final String[] androidVertexShaderCode = new String[] {
        "attribute vec4 vertexPosition;",
        "void main() {",
        "  gl_Position = vertexPosition;",
        "}" };

private static final String[] androidFragmentShaderCode = new String[] {
        "precision mediump float;",
        "uniform vec4 colour;",
        "void main() {",
        "  gl_FragColor = colour;",
        "}" };

/* The Android shader */
public Shader androidShader;

/* The constructor with the render mode and the 
 * number of vertex values given */
public AndroidRenderer(int renderMode, int vertexValuesCount) {
    super(renderMode, vertexValuesCount);
    //Add this renderer to the list
    allRenderers.add(this);
    usage = GLES20.GL_STATIC_DRAW;
    //Setup the Android shader
    this.androidShader = new AndroidShader();
    this.androidShader.vertexShader = ShaderUtils.createShader(ArrayUtils.toStringList(androidVertexShaderCode), Shader.VERTEX_SHADER);
    this.androidShader.fragmentShader = ShaderUtils.createShader(ArrayUtils.toStringList(androidFragmentShaderCode), Shader.FRAGMENT_SHADER);
    this.androidShader.create();
}

/* The method used to setup the buffers,
 * assumes the vertices have already been set */
public void setupBuffers() {
    //Create the vertices buffer
    this.verticesBuffer = BufferUtils.createFlippedBuffer(this.verticesData);
    int[] vh = new int[1];
    GLES20.glGenBuffers(1, vh, 0);
    //Setup the vertices handle
    this.verticesHandle = vh[0];

    //Bind the vertices buffer and give OpenGL the data
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.verticesHandle);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * verticesData.length, this.verticesBuffer, this.usage);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

    //Check to see whether the normals have been set
    if (this.normalsData != null) {
        //Create the normals buffer
        this.normalsBuffer = BufferUtils.createFlippedBuffer(this.normalsData);
        int[] nh = new int[1];
        GLES20.glGenBuffers(1, nh, 0);
        //Setup the normals handle
        this.normalsHandle = nh[0];

        //Bind the normals buffer and give OpenGL the data
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.normalsHandle);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * verticesData.length, this.normalsBuffer, this.usage);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }

    //Check to see whether the colours have been set
    if (this.colourData!= null) {
        //Create the colours buffer
        this.coloursBuffer = BufferUtils.createFlippedBuffer(this.colourData);
        int[] ch = new int[1];
        GLES20.glGenBuffers(1, ch, 0);
        //Setup the colours handle
        this.coloursHandle = ch[0];

        //Bind the colours buffer and give OpenGL the data
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.coloursHandle);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * colourData.length, this.coloursBuffer, this.usage);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }

    //Check to see whether the texture coordinates have been set
    if (this.textureData != null) {
        //Create the texture coordinates buffer
        this.texturesBuffer = BufferUtils.createFlippedBuffer(this.textureData);
        int[] th = new int[1];
        GLES20.glGenBuffers(1, th, 0);
        //Setup the texture coordinates handle
        this.texturesHandle = th[0];

        //Bind the texture coordinates buffer and give OpenGL the data
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.texturesHandle);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, Float.BYTES * textureData.length, this.texturesBuffer, this.usage);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
    }
}

/* The method used to draw the object */
public void render() {
    this.androidShader.use();
    short[] indices = new short[this.verticesData.length];
    for (short a = 0; a < indices.length; a++)
        indices[a] = a;
    ShortBuffer indicesBuffer = BufferUtils.createFlippedBuffer(indices);
    //Enable the arrays as needed
    int vertexPositionAttribute = GLES20.glGetAttribLocation(this.androidShader.program, "vertexPosition");
    int normalAttribute = 0;
    int colourAttribute = 0;
    int texturesAttribute = 0;
    GLES20.glEnableVertexAttribArray(vertexPositionAttribute);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.verticesHandle);
    GLES20.glVertexAttribPointer(vertexPositionAttribute, this.vertexValuesCount, GLES20.GL_FLOAT, false, 0, 0);
    if (this.normalsData != null) {
        GLES20.glEnableVertexAttribArray(normalAttribute);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.normalsHandle);
        GLES20.glVertexAttribPointer(normalAttribute, 2, GLES20.GL_FLOAT, false, 0, 0);
    }
    if (this.colourData != null) {
        colourAttribute = GLES20.glGetAttribLocation(this.androidShader.program, "colour");
        Log.d("HELLO", "" + colourAttribute);
        GLES20.glEnableVertexAttribArray(colourAttribute);
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.coloursHandle);
        GLES20.glVertexAttribPointer(colourAttribute, this.colourValuesCount, GLES20.GL_FLOAT, false, 0, 0);
    }
    if (this.textureData != null) {
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.texturesHandle);
        GLES20.glEnableVertexAttribArray(texturesAttribute);
        GLES20.glVertexAttribPointer(texturesAttribute, this.textureValuesCount, GLES20.GL_FLOAT, false, 0, 0);
    }
    //Draw the arrays
    GLES20.glDrawElements(this.renderMode, indices.length, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);
    //Disable the arrays as needed
    if (this.normalsData != null)
        GLES20.glDisableVertexAttribArray(normalAttribute);
    if (this.textureData != null)
        GLES20.glDisableVertexAttribArray(texturesAttribute);
    if (this.colourData != null)
        GLES20.glDisableVertexAttribArray(colourAttribute);
    GLES20.glDisableVertexAttribArray(vertexPositionAttribute);
    this.androidShader.stopUsing();
}

I haven't implemented the use of normal or textures at the moment, as I am just trying to draw a triangle where each vertex is a different color. I know that the shader should be working as I got this to work, rendering with only one color using the same shader, and vertices/colour data.

When I looked at LogCat, the message: : GL_INVALID_VALUE was being printed out. I then decided to print out the value of the colourAttribute found using glGetAttribLocation, and it turns out this was -1. Upon further research I found this: https://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml, which states that the value of -1 is returned "If the named attribute variable is not an active attribute in the specified program object".

After searching Google, I haven't found a solution to the problem of the triangle not rendering, so would appreciate any help.

Thank you.

Diversity
  • 1,890
  • 13
  • 20
2851999
  • 167
  • 1
  • 1
  • 10
  • Are you sure that the shaders are compiling correctly and is the colorData an array of float with 4 elements. – Diversity Aug 18 '14 at 13:57
  • Yes, the colorData is produced from 4 values (rgba), and the shader was working before hand, when I used a similar method shown here: http://developer.android.com/training/graphics/opengl/draw.html in the draw method, in fact I copied the shader code from the same set of tutorials. – 2851999 Aug 18 '14 at 14:24

1 Answers1

1

It seams that the stride of the vertexAttributePointer method is always 0. Which means you override the vertex positions within the vertex buffer with you color values.

GLES20.glVertexAttribPointer(colourAttribute, this.colourValuesCount, GLES20.GL_FLOAT, false, **0**, 0);

You have to increase that stride by an offset of the sum of the previous vertex attribute sizes. In your case 4 because of the vec4 of the vertexPosition vector. The same applies later for the texture and normals.

Have a look here for the definition of glVertexAttribPointer: http://androidbook.com/akc/display?url=displaynoteimpurl&ownerUserId=android&reportId=4229

Additionally you can try to add a fixed color to the fragment shader eg:

gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);

So you avoid that the colorHandle has any influence to the rendering process.

Additionally try to avoid to use the IndexBuffer at first and not use the

glDrawElements(.. , ..) 

method just use directly the vertexBufferObject with a

glDrawArrays(.., .., )

method.

If that works you can of course switch back to the IndexBuffer method.

UPDATE due to comment

I see another problem right now. You missed to link the shader and enable it using glLinkProgram and glUseProgram. Have a look here: Shader for Android OpenGL ES

This post shows you also how to output the compile errors of the shader program.

Community
  • 1
  • 1
Diversity
  • 1,890
  • 13
  • 20
  • I did everything you suggested and the only thing that worked was adding a fixed color, the problem is that the glGetAttribLocation is returning -1, which can't be right, so I don't think the shader is even getting the color from the program itself. – 2851999 Aug 18 '14 at 15:20
  • Wow, I just checked LogCat again, now there is another problem ": GL_INVALID_OPERATION and aparently "GL_INVALID_OPERATION is generated if program is not a program object. GL_INVALID_OPERATION is generated if program could not be made part of current state." So maybe there might be a problem with the shader as well. – 2851999 Aug 18 '14 at 15:28
  • Did you already check if the vertexPositionAttribut is initialized correctly – Diversity Aug 18 '14 at 15:29
  • Yes in my oppinion the problem must be the shaders. If they would compile correctly than the attributes could be bound correctly. – Diversity Aug 18 '14 at 15:31
  • I see another problem right now. You missed to link the shader and enable it using glLinkProgram and glUseProgram. Have a look here: http://stackoverflow.com/questions/4850025/shader-for-android-opengl-es – Diversity Aug 18 '14 at 15:50
  • Ok, I have now got an error, it is: Could not link the program. Invalid fragment shader. Link cannot proceed. – 2851999 Aug 18 '14 at 16:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/59523/discussion-between-2851999-and-diversity). – 2851999 Aug 18 '14 at 16:18