Giving colour to primitives in OpenGL using Vertex

2019-08-01 15:54发布

问题:

I am writing a program in C, using OpenGL, to draw some primitives (lines, circles, etc.). I have succeeded in using the buffer objects to store the vertices of the primitives, and hence, in drawing them. But I seem to be stuck now since I don't know how to set their colour. Part of the program was given to me by my teacher, so I know that the colour attributes must be specified using this structure:

typedef struct {
    float r;
    float g;
    float b;
    float a;
} vec4;

I know I am supposed to use a vec4 array to store colour values so I declared one such variable. The first one is a vec2 array which will be used to store the primitive vertices.

vec2 vertices[10000];
vec4 colours[10000];

The function which (as I understand) is used to set the limit of the vertex buffer looks like this:

void initShaders(void) 
{
    GLuint buffer;
    GLuint loc;
    GLuint vao;

    /*Create and initialize a program object with shaders */ 
  idProgram = initProgram("ass1vshader.glsl", "ass1fshader.glsl");

    /*installs the program object as part of current rendering state */ 
   glUseProgram(idProgram);

   /*Creat a vertex array object */ 
   glGenVertexArrays(1, &vao);
   glBindVertexArray(vao);

    /*Create buffer in the shared display list space and */ 
     /* bind it as GL_ARRAY_BUFFER */ 
    glGenBuffers( 1, &buffer);
    glBindBuffer( GL_ARRAY_BUFFER, buffer);
    glBufferData( GL_ARRAY_BUFFER, sizeof(vertex)+sizeof(colours), NULL,GL_STATIC_DRAW);

    /*Initialize attribute vPosition in program */ 
    loc = glGetAttribLocation( idProgram, "vPosition");
    glEnableVertexAttribArray(loc);
    glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)BUFFER_OFFSET(0));

    /*Get location of the uniform attribute 'u_proj_matrix' */ 
    idProjection = glGetUniformLocation(idProgram, "u_proj_matrix");

    /*Set graphics attributes */ 
    glLineWidth(3.0);
    glPointSize(1.0);
    glClearColor(1.0, 1.0, 1.0, 1.0);

}

As you can see, I have initialized the vertex buffer size to the combined size of "vertex" and "colours".

I am also given to understand that the fragment shader plays an important role in the colouring process. It looks like this:

#version 140

in vec4 color;
out vec4  fColor;

void
main()
{    
    fColor = color;
}

Can somebody tell me how I can go about giving colour to my primitives? I hope the information I have provided is sufficient.

回答1:

One way to do it is to use a color array. You can do this by calling glColorPointer() in the same way as you do for glVertexPointer().

Also, I don't know if this is just a typo, or if you actually have this error, but you wrote:

glBufferData( GL_ARRAY_BUFFER, sizeof(vertex)+sizeof(colours), NULL,GL_STATIC_DRAW);

However, your vertex array is named "vertices" not "vertex" (at least according to your earlier statement). If it compiles OK, then it probably means you have another variable or data structure named vertex, but it's not doing what you think.

And since your data isn't interleaved (you have separate vertex and color data), I think you'll want to use separate buffers for them. If they were in one structure, you could use a single array, and set the stride appropriately, but since they aren't interleaved, I'm not sure if what you're attempting to do will work.



回答2:

First of all, you haven't shown you vertex shader, that is responsible for receiving the per vertex color and putting it out to be interpolated over the primitive and sent to the fragment shader. I guess it looks (or should look) something like:

uniform mat4 u_proj_matrix;

in vec4 vPosition;
in vec4 vColor;

out color;

void main()
{
    gl_Position = u_proj_matrix * vPosition;
    color = vColor;
}

So we have an additional per vertex attribute called vColor for which we need to specify a source, in the same way we did for the vPosition attribute:

loc = glGetAttribLocation(idProgram, "vColor");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 0, 
                      (GLvoid*)BUFFER_OFFSET(sizeof(vertices)));

This specifies the colors of all 10000 vertices to be stored in the buffer after the coordinates of all 10000 vertices.


But as user1118321 already noted, it may be a better idea (even if not the only one possible) to store the coordinates and color of a single vertex together and thus interleave the attributes. In this case you would have a structure like this one:

typedef struct {
    vec2 coords;
    vec4 color;
} vertex;

and a single array of those:

vertex vertices[10000];

But in this case we have to tell OpenGL that our data is interleaved by playing with the stride and offset parameters of glVertexAttribPointer:

//for position:
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 
                      sizeof(vertex), (GLvoid*)offsetof(vertex, coords));

//for color:
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 
                      sizeof(vertex), (GLvoid*)offsetof(vertex, color));

This tells OpenGL, that the stride (offset from one to the next) between the attribute values of two consecutive vertices is the size of our custom struct. Meaning to get from the beginning of the coordinate data of one vertex to that of the next we have to "jump over" sizeof(vertex) bytes (most probably sizeof(vec2)+sizeof(vec4) = 24) and likewise for the colors.

Morevover, we tell the GL that our vertex data starts at the offset of the coords member of the first vertex (most probably 0) and our color data starts at the offset of the color member of the first vertex (most probably sizeof(vec2) = 8).