语言

Menu
Sites
Language
How to pass color in for each vertex in OpenGL ES 2.0?

We talk about this topic about how to pass color in for each vertex in OpenGL ES 2.0 based on the tutorial about Tizen OpenGL ES:

https://developer.tizen.org/development/tutorials/native-application/graphics/opengl-es-0

If you have not read it, please read it first.

We focus on how you specify color for each vertex.

Firstly, in the shader program, gl_FragColor got the passed in color array at last, and pass it to the GPU to shading color for each vertex.

But how to pass the color in? We need to use the attribute vector in vertex shader to accept the color data passed from C++ codes. And pass the color from vertex shader to fragment shader through a same name varing vector.

/* Vertex Shader Source */

static const char vertex_shader[] =

        "attribute vec4 a_position;\n"

        "attribute vec4 a_color;\n"

        "varying vec4 v_color;\n"

        "\n"

        "void main()\n"

        "{\n"

        "    v_color = a_color;\n"  // pass it to varying vector, which is same name with the varing vector in fragment shader.

        "    gl_Position = a_position;\n"

        "}";

/* Fragment Shader Source */

static const char fragment_shader[] =

        "#ifdef GL_ES\n"

        "precision mediump float;\n"

        "#endif\n"

        "varying vec4 v_color;\n" // same name with the varing vector in vertex shader

        "\n"

        "void main (void)\n"

        "{\n"

        "    gl_FragColor = v_color;\n"

        "}";

Then you need to prepare the color for each vertex in C++ codes. Both vertices and colors are hold by float array. We need to define color for each vertex, color array and vertex array should be one to one relationship.

const float coords_vertices[] =
{
      0.0f,  0.75f, 0.0f,       // [0] top
    -0.6f, -0.4f, 0.0f,       // [1] left bottom
      0.6f, -0.4f, 0.0f,        // [2] right bottom  

};

const float coords_colors[] =

{
    1.0, 0.0, 0.0, 1.0, //  [0] is red, color for coords_vertices[0]
    0.0, 1.0, 0.0, 1.0, // [1] is green, color for coords_vertices[1]
    0.0, 0.0, 1.0, 1.0, // [2] is blue, color for coords_vertices[2]
};

And if we draw triangles or lines by glDrawElements, we need to specify the drawing sequence of the vertices by an index array as below.

const int coords_indices_count = 6;

const unsigned short coords_indices[] =
{
    0, 1,
    1, 2,
    2, 0
};

The function glDrawElements to use this index array would be like:

glDrawElements(GL_LINES, coords_indices_count, GL_UNSIGNED_SHORT,  coords_indices);

Then in C++ codes, before drawing the objects, we need create shaders, load shader sources, compile shaders, create shader program, attach shaders, link shader program  and use shader program.

static void init_shaders(Evas_Object *obj) {
    appdata_s *ad = evas_object_data_get(obj, "ad");
    const char *p;

    p = vertex_shader;
    ad->vtx_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(ad->vtx_shader, 1, &p, NULL);
    glCompileShader(ad->vtx_shader);

    p = fragment_shader;
    ad->fgmt_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(ad->fgmt_shader, 1, &p, NULL);
    glCompileShader(ad->fgmt_shader);

    ad->program = glCreateProgram();
    glAttachShader(ad->program, ad->vtx_shader);
    glAttachShader(ad->program, ad->fgmt_shader);

    glLinkProgram(ad->program);

    ad->idx_position = glGetAttribLocation(ad->program, "a_position");
    ad->idx_color = glGetAttribLocation(ad->program, "a_color");
    ad->idx_mvp = glGetUniformLocation(ad->program, "u_mvpMatrix");

    glUseProgram(ad->program);
}

We can see above bold lines that take the vertex array location and color array location in the shader out as pointer.

Then fill the arrays by previously delared vertex array and color array into these shader location when drawing the objects represented by the vertices.

static void draw_gl(Evas_Object *obj) {
    appdata_s *ad = evas_object_data_get(obj, "ad");
    int w, h;

    if (!ad)
        return;

    elm_glview_size_get(obj, &w, &h);

    if (!h)
        return;

    glViewport(0, 0, w, h);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glVertexAttribPointer(ad->idx_position, 3, GL_FLOAT, GL_FALSE,  3 * sizeof(float), coords_vertices);

    glVertexAttribPointer(ad->idx_color, 4, GL_FLOAT, GL_FALSE,   4 * sizeof(float), coords_colors);
    glEnableVertexAttribArray(ad->idx_position);
    glEnableVertexAttribArray(ad->idx_color);
    glDrawElements(GL_LINES, coords_indices_count, GL_UNSIGNED_SHORT,  coords_indices);

    glFlush();

    display_fps();
}

Then the three lines would be drawn with the color defined to each vertex.

 

编辑者为: Jean Yang 06 8月, 2015

响应

5 回复
Jean Yang

The lines drawn is as below.

Jean Yang

But currently Tizen has bug, please see another topic.

https://developer.tizen.org/forums/native-application-development/why-color-vertieces-not-work-when-i-try-eliminate-those-redundant-points-vertexes-array?tab=my

Jean Yang

Let's continue to explain how the shader code take the position vertex and color vertex out then shadering them on the GPU and show on the screen.

When we call the OpenGL drawing API, it will call the shader program to process the vertices. Let's take a look at the calling of  glDrawElements and imaging how these vertices are processed.

    glDrawElements(GL_LINES, coords_indices_count, GL_UNSIGNED_SHORT,  coords_indices);

Firstly, this drawing API would retrive 2 vertices for a GL_LINE, it looks up the coords_indices, and find the indices are "0,1,", so the first position vertex "0.0f,  0.75f, 0.0f,       // [0] top" would be the start point of GL_LINE, the second poistion vertex "-0.6f, -0.4f, 0.0f,       // [1] left bottom" would be the end point of the GL_LINE. 

Why we know each vertex is 3 floats other than 2 ints or 4 floats? The API glVertexAttribPointer define this.

    glVertexAttribPointer(ad->idx_position, 3, GL_FLOAT, GL_FALSE,  3 * sizeof(float), coords_vertices);

How to handle each positon vertex in the vertex shader? we can see two lines as below.

"attribute vec4 a_position;\n"

"    gl_Position =  a_position;\n"

It meens a vec4 attribute a_position will be passed in one time and will be assigned to system variable gl_Position for shadering.

And the frist color vertex "1.0f, 0.0f, 0.0f, 1.0f, // [0] is red" would be the color for the first position vertex, the second color vertex "0.0f, 1.0f, 0.0f, 1.0f, // [1] is green" would be the color for the second position vertex.

Why we know each color vertex is 4 floats? Also, it is defined by  glVertexAttribPointer.

    glVertexAttribPointer(ad->idx_color, 4, GL_FLOAT, GL_FALSE,   4 * sizeof(float), coords_colors);

How to handle each color vertex in the shaders? We can see three lines in the vertex shader as below.

        "attribute vec4 a_color;\n"

        "varying vec4 v_color;\n"

        "    v_color = a_color;\n"  

And two lines in the Fragment shader as following.

        "varying vec4 v_color;\n"

        "    gl_FragColor = v_color;\n"

It means each time the shader program is called, a vec4 attribute a_color will be passed in, then it is assigned to the variable varying vec4 v_color. Later in the fragment shader varying vec4 v_color will get value of the same name variable in the vertex shader, then assign it to system variable gl_FragColor for shadering.

That's the process to handle the first GL_LINE.

In turn, the second GL_LINE vertice indices are "1, 2,", corresponding position vertices are:

    -0.6f, -0.4f, 0.0f,       // [1] left bottom
    0.6f, -0.4f, 0.0f,        // [2] right bottom  

and corresponding color vertices are:

    0.0f, 1.0f, 0.0f, 1.0f, // [1] is green
    0.0f, 0.0f, 1.0f, 1.0f, // [2] is blue

The third GL_LINE vertice indices are "2, 0", corresponding position vertices are:

    0.0f,  0.75f, 0.0f,       // [0] top
    0.6f, -0.4f, 0.0f,        // [2] right bottom  

and corresponding color vertices are:

    1.0f, 0.0f, 0.0f, 1.0f, // [0] is red
    0.0f, 0.0f, 1.0f, 1.0f, // [2] is blue

Although we can only imaging the shader program retriving the vertices for each GL_LINE line by line, these three GL_LINES will be drawing by GPU parallelly.

 

pius lee

It's not but too.

test your vertext like it.

{
    	 0.0f,  0.0f, 0.0f,       // [0] top
	-0.1f, -0.1f, 0.0f,       // [1] left bottom
	 0.1f, -0.1f, 0.0f,        // [2] right bottom
};

Your vertex too large, so lines was drawn out of screen.

 

Jean Yang

Ok, I confirmed with the shrinked vertices, the color works well now. Thanks Pius!