1
votes

Trying to modify the triangle vertex color values from the Android Developer OpenGL Tutorial. The triangle renders but appears dark. What is wrong with the color buffer?

public class Triangle {

    ...

Added the following lines to establish a color buffer. Is this necessary?

    private FloatBuffer colorBuffer;
    static final int COLORS_PER_VERTEX = 4;

    static float triangleColors[] = {
            0.6f, 0.2f, 0.2f, 1.0f,
            0.2f, 0.6f, 0.2f, 1.0f,
            0.9f, 0.9f, 0.2f, 1.0f
    };

    private final int colorStride = COLORS_PER_VERTEX * 4; 

With the following shader codes, replaced the original "uniform vec4 vColor" with attribute instead of varying because there is no GLES20.getVaryingLocation.

    private final String vertexShaderCode =
        "attribute vec4 vPosition;void main(){gl_Position = vPosition;}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    //originally uniform, use varying?
                   "attribute vec4 vColor;" +
                    "void main() {" +
                    "    gl_FragColor = vColor;"+
                    "}";

In the constructor:

    public Triangle()
    {
        ...

        ByteBuffer cb = ByteBuffer.allocateDirect(triangleColors.length * 4);
        cb.order(ByteOrder.nativeOrder());
        colorBuffer = cb.asFloatBuffer();
        colorBuffer.put(triangleColors);
        colorBuffer.position(0);

        ... //compile and link shaders code is unchanged   
    }

    public void draw()
    {
        GLES20.glUseProgram(mProgram);

        ...

        /*
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        */

        mColorHandle = GLES20.glGetAttribLocation(mProgram, "vColor");
        GLES20.glEnableVertexAttribArray(mColorHandle);
        GLES20.glVertexAttribPointer(mColorHandle, COLORS_PER_VERTEX,
                GLES20.GL_FLOAT, false, colorStride, colorBuffer);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mColorHandle);

    }

}
1

1 Answers

1
votes

You are misunderstanding what is an uniform, an attribute and a varying.

To do the change you are describing you need both, an attribute and a varying. The vertex shader must include an attribute for a color such as attribute vec4 aColor; and a varying output as varying vec4 vColor;. Then in main you need to assign the color as vColor = aColor;. In the fragment shader you then only need varying vec4 vColor; and use it the same way you did in the main method.

To explain a bit on what these are:

  • An attribute and an uniform are quite similar but attribute is per vertex while the uniform is per draw call (will have the same value for all vertices, fragments). They are both designed to produce communication between the CPU and the GPU (You send the data to the GPU through either of these).
  • A varying is a bit different. Usually a varying is assigned from the attribute and is done in the vertex shader. This means every vertex will have its own value from the attribute but after rasterization is done each of the varying value will be interpolated depending on the fragment position relative to the bounding vertices. So a varying is designed to communicate between the vertex and the fragment shader (sending data from vertex to fragment shader).

It is easiest to explain on a line defined by 2 points (A,B) and let's say on your render buffer the line will take 100 pixels. If first line has a white color C1 = (1,1,1,1) and the second point has a black color C2 = (0,0,0,1). You will assign the same color in the vertex shader for the varying value and a fragment shader will be called 100 times which is for each of the pixels. Now your varying color in the fragment shader will have an interpolated value for position X as in

color = C1 + (C2-C1)*((X-A).length()/(B-A).length()).

So for case of 100 pixels the 46th pixel would be

color = (1,1,1,1)-(1,1,1,0)*(64/100)

which results in (.36, .36, .36, 1.0). So the pixels will fade to black linearly from A to B which will produce a nice gradient.

I hope this will clear things a bit.