androidshaderopengl-es-2.0fragment-shadervertex-shader

Cannot get attribute location for attributes after Varying Variable has been introduced


I'm trying to implement a ModelViewer that can visualize triangulated shapes with realistic lighting. Since realistic lighting doesn't seem possible with OpenGL ES 1.0 and I need a way to present depth for a single colored object, the project uses OpenGL ES 2.0 which is new to me. The object itself consists of triangles that are drawn using:

GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

As for a test project, I've set up simple shaders that draw the object in consideration of the model-view-projection matrix. After that, my intention was to implement lighting but I cannot get past the first steps. When working with varying variables, the vertex attributes won't be found. Removing the varying attributes works, but i need to pass data. I've searched for days on how to implement vertex and fragment shaders that do more than present an object at a location.

// VERTEX SHADER CODE
    attribute vec4 v_Position;
    uniform mat4 u_MVPMatrix;
    uniform vec4 u_Color;

    varying vec4 v_Color;

    void main() {
        gl_Position = u_MVPMatrix * v_Position;
        v_Color = u_Color;
    };

// FRAGMENT SHADER CODE
    precision mediump float;

    varying vec4 v_Color;

    void main() {
        gl_FragColor = v_Color;
    }

The whole Class:

public class Object3D {

    private FloatBuffer vertexBuffer;

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
//    static float triangleCoords[] = {   // in counterclockwise order:
//            0.0f,  0.622008459f, 0.0f, // top
//            -0.5f, -0.311004243f, 0.0f, // bottom left
//            0.5f, -0.311004243f, 0.0f  // bottom right
//    };
    float[] triangleCoords;

    // Set color with red, green, blue and alpha (opacity) values
    float[] colors = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };


    private final String vertexShaderCode =
            "attribute vec4 v_Position;" +
            "uniform float u_Color" +
            "uniform mat4 u_MVPMatrix;" +
                // outgoing
            "varying vec4 v_Color" +
            "void main() {" +
                // the matrix must be included as a modifier of gl_Position
                // Note that the uMVPMatrix factor *must be first* in order
                // for the matrix multiplication product to be correct.
                "gl_Position = u_MVPMatrix * v_Position;" +
                "v_Color = u_Color;" +
            "}";


    private final String fragmentShaderCode =
            "precision mediump float;" +

            "varying vec4 v_Color;" +
            "void main() {" +
                "gl_FragColor = v_Color;" +
            "}";


    // Use to access and set the view transformation
    private int mMVPMatrixHandle;

    private final int mProgram;

    private int mPositionHandle;
    private int mColorHandle;

    private final int vertexCount;
    private final int vertexStride;

    public Object3D(float[] triangleCoords) {
        this.triangleCoords = triangleCoords;

        vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
        vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

        this.colors = new float[4*vertexCount];
        for (int i = 0; i < colors.length; i+=4) {
            colors[i] = 0.63671875f;
            colors[i+1] = 0.76953125f;
            colors[i+2] = 0.22265625f;
            colors[i+3] = 1.0f;
        }

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (number of coordinate values * 4 bytes per float)
                triangleCoords.length * 4);
        // use the device hardware's native byte order
        bb.order(ByteOrder.nativeOrder());

        // create a floating point buffer from the ByteBuffer
        vertexBuffer = bb.asFloatBuffer();
        // add the coordinates to the FloatBuffer
        vertexBuffer.put(triangleCoords);
        // set the buffer to read the first coordinate
        vertexBuffer.position(0);

        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        // create empty OpenGL ES Program

        mProgram = GLES20.glCreateProgram();

        // add the vertex shader to program
        GLES20.glAttachShader(mProgram, vertexShader);
        // add the fragment shader to program
        GLES20.glAttachShader(mProgram, fragmentShader);

        GLES20.glBindAttribLocation(mProgram, 0, "v_Position");
//        GLES20.glBindAttribLocation(mProgram, 1, "vColor");

        // creates OpenGL ES program executables
        GLES20.glLinkProgram(mProgram);
    }

    public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
        // Add program to OpenGL environment
        GLES20.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "v_Position");
//        if (mPositionHandle == -1) {
//            throw new RuntimeException(
//                    "Could not get attrib location for v_Position");
//        }

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "v_Color");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, colors, 0);
        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

//        // get handle to shape's transformation matrix
//        int mColorHandleU = GLES20.glGetUniformLocation(mProgram, "u_Color");
//
//        // Apply the projection and view transformation
//        GLES20.glUniform4fv(mColorHandleU, 1, new float[] {}, 0);

        // Draw the triangle
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

If I want to do some necessary color calculations, i need varying variables to pass information from the vertex to the fragment shader. However, I cannot seem to get this done.

The Error I keep getting is:

2019-05-14 21:54:25.122 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glEnableVertexAttribArray:892 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.123 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glVertexAttribPointer:604 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.124 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glDisableVertexAttribArray:901 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.237 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glEnableVertexAttribArray:892 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.237 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glVertexAttribPointer:604 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.238 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glDisableVertexAttribArray:901 GL error 0x501
    Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16

Also, the following exception, when implemented, is thrown:

mPositionHandle = GLES20.glGetAttribLocation(mProgram, "v_Position");
        if (mPositionHandle == -1) {
            throw new RuntimeException(
                    "Could not get attrib location for v_Position");
        }

I know that for attributes, the instruction flow goes like this:

GLES20.glBindAttribLocation(...);
-- Link Shader Program --
attributeHandle = GLES20.glGetAttribLocation(programHandle, "a_AttributenName");
GLES20.glEnableVertexAttribArray(attributeHandle);
GLES20.glVertexAttribPointer(programHandle, ..., buffer);

The instruction sequence for uniforms go like this:

uniformHandle = GLES20.glGetUniformLocation(mProgram, "u_UniformName");
// do something with it, for example:
GLES20.glUniform4fv(uniformHandle, ...);

But what is there to do for varying variables?

Thanks in advance!


Solution

  • private final String vertexShaderCode =
            "attribute vec4 v_Position;" +
            "uniform float u_Color" +
            "uniform mat4 u_MVPMatrix;" +
                // outgoing
            "varying vec4 v_Color" +
            "void main() {" +
    

    You're missing a semi-colon after u_Color and also v_Color. Presumably your vertex shader is not compiling and that's cascading down into the errors you're seeing.

    It's a pain, but it really does save time in the long run to check for errors after every OpenGLES call (glGetError). Getting detailed shader compile error logs is also fiddly but worth putting in place - see here (glGetShaderInfoLog, GL_COMPILE_STATUS).