# Android/OpenGL ES2: How do I set fragment shader value using C;

This should be easy So I am using the following to create a fragment shader.

 GLbyte fShaderStr[] = "precision mediump float;"
"void main()                                \n"
"{                                          \n"
"  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
"}                                          \n";


I then render a circle (collection of lines) the circle comes our red. If I change the code to...

GLbyte fShaderStr[] = "precision mediump float;"
"void main()                                \n"
"{                                          \n"
"  gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0); \n"
"}                                          \n";


The circle is now purple. My question is how do I control this dynamically? So for example when I receive an input I toggle the two colors?

I tried...

GLbyte vShaderStr[] = "attribute vec4 vPosition;   \n"
"attribute vec4 inColor;   \n"
"uniform mat4 Projection;   \n"
"varying vec4 fragColor;   \n"
"void main()                 \n"
"{                           \n"
"   gl_Position = Projection * vPosition; \n"
"   fragColor = inColor; \n"
"}                           \n";

GLbyte fShaderStr[] = "precision mediump float;"
"varying vec4 fragColor;                   \n"
"void main()                                \n"
"{                                          \n"
"  gl_FragColor = fragColor; \n"
"}\n";

void initColor(){
LOGD("Initing Color");
GLfloat vVertices[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, vVertices);
}


However, this doesn't seem to work as the circle is now black.

glEnableVertexAttribArray(1);


Basically any attribute is disabled by default, so you may have to enable it first. See this.

Edit

msell comment made me realize that you probably want the circle to be of single color, in that case yes, you need uniforms. Attributes are a property of vertices, so you would use attributes when you want to paint different vertices with different colors. Also, in that case you would need to specify a color for each vertex, so your vVertices array would need to have 4 floats for each vertex you are going to draw.

How to do it

The function you need is in the family of glUniform and most likely is glUniform4f because you want to set a color that is represented by 4 floats. You should declare your color in the fragment shader as a uniform:

uniform vec4 inColor;


Then in your application code you would do:

GLint location = glGetUniformLocation(program, "inColor");
glUniform4f(location, 1.0f, 0.0f, 0.0f, 1.0f);


Little explanation

Usually it doesn't make sense to derive the value of a varying solely from uniforms in the vertex shader; the reason is that uniforms are uniform across all possible vertices shaded during the current draw call. The varyings are varying in the sense that the vertex shader computes their value for each vertex of a triangle, and then the interpolation units on the graphic card constructs all the intermediate values corresponding to the generated fragments. Since a uniform value is the same for each vertex, each fragment would get the same value. That is, if you use a uniform to decide in the vertex shader that all vertices are purple, the interpolator will generate all the shades of purple between purple and purple, that is, purple.

Instead, if you specify colors as attributes it is necessary to generate all intermediate shades across the triangle, so it makes sense to assign the attribute to the varying.

Reference

Square

You need 6 positions:

-1.0, -1.0, 0.0
+1.0, -1.0, 0.0
-1.0, +1.0, 0.0
-1.0, +1.0, 0.0
+1.0, -1.0, 0.0
+1.0, +1.0, 0.0


And two colors, spread over two triangles:

1.0, 0.0, 0.0, 1.0 // Red
1.0, 0.0, 0.0, 1.0 // Red
1.0, 0.0, 0.0, 1.0 // Red
0.0, 1.0, 0.0, 1.0 // Green
0.0, 1.0, 0.0, 1.0 // Green
0.0, 1.0, 0.0, 1.0 // Green


And then use a call like:

glDrawArrays(GL_TRIANGLES, 0, 6);

• Is there an example on how to change a uniform? Does the value in the shade renderer also change to a uniform? – Jackie May 26 '13 at 15:03
• You already have a uniform in your program, it's the mat4 Projection. In addition to have uniforms in the vertex shader, you can also have them in the fragment shader. In your code you should have a call to glUniformMatrix4fv, because, I repeat, you are already using uniforms for the projection matrix. You need to do something similar for the uniform inColor, and the API you need is glUniform4f. Check the code in my answer. – damix911 May 27 '13 at 6:02
• One more question if you don't mind (you have been very helpful so far). If I change it over to a square made from a triangle strip and I set up a vec 4 with 8 floats (4 for each of the two triangles in the strip) I was hoping to see two different color triangles but instead I get what looks like a gradient from one color to the other. How would I make each triangle have a different color. – Jackie May 27 '13 at 15:18
• Are you using uniforms or attributes? To paint a multicolored object with a single draw call you most likely need attributes. Also, a square made from triangle strip is such that the two triangles share two vertices. They not only share the position of the vertices, but also any other attribute, including color. If I where you I would sue GL_TRIANGLES instead of GL_TRIANGLE_STRIP and specify 6 vertices in total, three with one color, and the other three with another one. Check the updated answer. – damix911 May 27 '13 at 21:27
• Thanks I finally got it working after a bunch of rereading about the differences between uniform vary and attribute. Working as expected now, of course not I need to learn texturing :-) – Jackie May 27 '13 at 22:14