Applying color to single vertices squared in opengl

I am trying to color single vertices of quads that are drawn through glDrawElements , I work with cocos2d libray, so I was able to clear the source code to understand exactly what was happening, the code looks like this:

 glBindVertexArray( VAOname_ ); glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) ); glBindVertexArray(0); 

Vertex array objects are used. I am trying to change the color of the single vertices of the objects that are being transmitted, and it seems to work, but with a glitch, which is described by the following image:

enter image description here

Here I tried to change the color of the bottom left and right vertices. The result is different, I think this is due to the fact that the square is represented as a pair of triangles with common hypotenuse, which is located on the diagonal, which goes from the lower left vertex to the upper right vertex. Thus, this may lead to a different result.

Now I would like to get the second result for the first case. Is there any way to get it?

+4
source share
1 answer

Your guess is correct. The OpenGL driver attaches your quad to two triangles in which the colors of the vertices are interpolated barycentrically, which leads to what you see.

The usual approach to solving this issue is to perform manual interpolation in the fragment shader, which takes into account the target topology, in your case, a square. Or, in short, you must perform barycentric interpolation based not on a triangle, but on a quadrant. You can also apply perspective correction.

I don’t have any ready to read resources on hand right now, but I will update this answer as soon as I have (in fact, this may mean I will have to write it myself).

Update

First we need to understand the problem: most OpenGL implementations break up higher primitives into triangles and make them localized, that is, without additional knowledge about the rest of the primitive, for example. quad Therefore, we must do it ourselves.

This is how I do it.

 #version 330 // vertex shader 

Of course, we also need regular uniforms.

 uniform mat4x4 MV; uniform mat4x4 P; 

First we need the vertex position processed by the shader execution instance.

 layout (location=0) in vec3 pos; 

Next, we need some vertex attributes that we use to describe the square itself. This means that its angular positions

 layout (location=1) in vec3 qp0; layout (location=2) in vec3 qp1; layout (location=3) in vec3 qp2; layout (location=4) in vec3 qp3; 

and colors

 layout (location=5) in vec3 qc0; layout (location=6) in vec3 qc1; layout (location=7) in vec3 qc2; layout (location=8) in vec3 qc3; 

We put them in variables to handle the fragment shader.

 out vec3 position; out vec3 qpos[4]; out vec3 qcolor[4]; void main() { qpos[0] = qp0; qpos[1] = qp1; qpos[2] = qp2; qpos[3] = qp3; qcolor[0] = qc0; qcolor[1] = qc1; qcolor[2] = qc2; qcolor[3] = qc3; gl_Position = P * MV * position; } 

In the fragment shader, we use this to implement distance weighting for color components:

 #version 330 // fragment shader in vec3 position; in vec3 qpos[4]; in vec3 qcolor[4]; void main() { vec3 color = vec3(0); 

The following can be simplified combinatorially, but for clarity, I write: For each corner point of the vertex, mix the colors of all the corner points with the projection of the position on the edge between them as a mixing factor.

  for(int i=0; i < 4; i++) { vec3 p = position - qpos[i]; for(int j=0; j < 4; j++) { vec3 edge = qpos[i] - qpos[j]; float edge_length = length(edge); edge = normalize(edge); float tau = dot(edge_length, p) / edge_length; color += mix(qcolor[i], qcolor[j], tau); } } 

Since we looked at each corner point 4 times, we reduce it by 1/4

  color *= 0.25; gl_FragColor = color; // and maybe other things. } 

We are almost done. On the client side, we need to convey additional information. Of course, we do not want to duplicate data. To do this, we use glVertexBindingDivisor so that the vertex attribute moves only every 4 vertices (i.e., Square) in places qp… and qc… , i.e. a location from 1 to 8

 typedef float vec3[3]; extern vec3 *quad_position; extern vec3 *quad_color; glVertexAttribute(0, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[0]); glVertexBindingDivisor(1, 4); glVertexAttribute (1, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[0]); glVertexBindingDivisor(2, 4); glVertexAttribute (2, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[1]); glVertexBindingDivisor(3, 4); glVertexAttribute (3, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[2]); glVertexBindingDivisor(4, 4); glVertexAttribute (4, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[3]); glVertexBindingDivisor(5, 4); glVertexAttribute (5, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[0]); glVertexBindingDivisor(6, 4); glVertexAttribute (6, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[1]); glVertexBindingDivisor(7, 4); glVertexAttribute (7, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[2]); glVertexBindingDivisor(8, 4); glVertexAttribute (8, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[3]); 

It makes sense to put the above into the vertex array object. Also, using VBO makes sense, but then you have to calculate the offset sizes manually; due to typedef float vec3 compiler does the math for us ATM.

When all this is installed, you can finally tesselation independently output your quad.

+7
source

All Articles