In a simple hello-world OpenGL program, which simply draws a static triangle on the window, when I set the 3 vertex of the triangle to red, green and blue color, the triangle is filled with gradient.
But when I use shaders like this:
Vertex Shader:
attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main(void) { gl_Position = gl_ModelViewMatrix * gl_ProjectionMatrix * aVertex; vColor = aColor; }
where the attributes aVertex
and aColor
comes from a vertex buffer, passed through a call of glVertexAttribPointer
.
Fragment Shader:
varying vec4 vColor; void main(void) { gl_FragColor = vColor; }
The triangle is still filled with gradient, and here comes the question:
If vertex-shader is calculated per vertex, then each instance of vColor
should be assigned with the color of a vertex. And the vertex color should be either red, green, or blue, as set in the vertex buffer.
So where did the gradient come from?
Or, in another word, when did it happen that in the frag-shader, the vColor
turns out to be the interpolated color instead of the vertex's?
A vertex shader receives its input data from a vertex attribute. But how does a fragment shader gets its data? Data is passed from shader to shader by using the in and out keywords. You create an output shader variable by using the out keyword.
There are several kinds of shaders, but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates. Fragment Shaders compute the renderings of a shape's colors and other attributes.
A vertex shader receives a single vertex from the vertex stream and generates a single vertex to the output vertex stream. There must be a 1:1 mapping from input vertices to output vertices. Vertex shaders typically perform transformations to post-projection space, for consumption by the Vertex Post-Processing stage.
"varying" variables in the fragment shader have the result of linearly interpolating between the values given at the vertex shader stage (based on the relative position of the fragment between the vertices).
That is, when the rasterizer spits out a fragment at a pixel, its position is also given relative to the triangle vertices in barycentric coordinates. These coordinates are then used to interpolate all varying variables from the vertex shader. In most cases, this is what you want and the speed gained from not interpolating is pretty insignificant these days.
Using the keyword "flat" will disable interpolation and instead use the value of the first vertex (I'm not 100% sure "flat" works with varying as I've switched to using in/out keywords with the newer versions of GLSL).
On a side note, I've found this particularly useful if the fragment needs some values from each of the vertices. In this case I use flat out myVertexValue[3]
in the geometry shader (for example here).
The gradient comes from the interpolation between vertex colors happening when the varying pass into fragment shader.If you don't want to interpolate use "flat" keyword at the begining of the varying . Your misunderstanding probably stems from the lack of knowledge on how vertex and fragment stages work.They work differently.Vertex shader is invoked per vertex while fragment -per-pixel.The interpolation happens by default as there is a need to cover fragments generated during rasterization stage on the area defined by the primitive assembly.And as I said you can disable interpolation by "flat".In such a case the color of the first vertex attribute will define the overall color of the shape.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With