10

Since vertex shader is run once per vertex (that mean in triangle 3 times), how does the varying variable gets computed for every fragment, if it's assigned (as in the example) only three times?

Fragment shader:

precision mediump float;
varying vec4 v_Color;

void main() {
    gl_FragColor = v_Color;
}

Vertex shader:

attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;

void main() {
    v_Color = a_Color;
    gl_Position = a_Position;
}

So, the question is, how does the system behind this know, how to compute the variable v_Color at every fragment, since this shader assigns v_Color only 3 times (in a triangle).

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Vilda
  • 1,675
  • 1
  • 20
  • 50
  • It interpolates the value between the three vertices, which is what it means to be a varying variable. – Matt Greer Apr 21 '14 at 16:57
  • Could you please tell me, how do the inner processes go? How does it measure the distance. (Sorry for my lack of knowledge, but couldn't find anything else on the internet.) – Vilda Apr 21 '14 at 16:58
  • 1
    I'm not that experienced with GLSL, I was hoping someone else would answer the question. But basically if your vertices are ten pixels apart from each other, then each pixel between the vertices will get an interpolated color that is 1/10th towards the other color, then 2/10ths, 3/10ths, etc. – Matt Greer Apr 21 '14 at 17:07
  • AFAIK its equivalent to the more recent `smooth in` qualifier; i.e. perspective-corrected linear interpolation between vertices. – Colonel Thirty Two Apr 21 '14 at 17:10
  • So if I set the v_Color to something. It's stored in the fragment shader system and if I set the v_Color to another color (at different vertex) it's stored as another variable and does not rewrite the first one? – Vilda Apr 21 '14 at 17:11
  • 1
    Yes. When you set `v_Color` in the vertex shader, it sets it on the vertex. When the fragment shader runs, it reads all of the vertices' `v_Color` values and interpolates between them based on the fragment's location. There's no overwriting. – Colonel Thirty Two Apr 21 '14 at 17:13
  • That pretty much explains it. Thank you guys for your anwser. – Vilda Apr 21 '14 at 17:14
  • For further details you can check this: [GLSL Core Tutorial – Pipeline (OpenGL 3.2 – OpenGL 4.2)](http://www.lighthouse3d.com/tutorials/glsl-core-tutorial/pipeline33/) – t.niese Apr 21 '14 at 17:15
  • Here's more info for cases where varying is across vec or mat values: https://gamedev.stackexchange.com/questions/139720/glsl-varying-interpolation-component-wise-reference-in-the-spec – trusktr Jun 01 '17 at 02:42
  • See this interesting visual by Gregg Man: https://github.com/greggman/webgl-fundamentals/issues/80 – trusktr Jun 01 '17 at 06:09

2 Answers2

7

All outputs of the vertex shader are per vertex. When you set v_Color in the vertex shader, it sets it on the current vertex. When the fragment shader runs, it reads the v_Color value for each vertex in the primitive and interpolates between them based on the fragment's location.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
3

First of all, it is a mistake to assume that the vertex shader is run once per-vertex. Using indexed rendering, primitive assembly can usually access the post T&L cache (result of previous vertex shader invocations) based on vertex index to eliminate evaluating a vertex more than once. However, new things such as geometry shaders can easily cause this to break down.

As for how the fragment shader gets its value, that is generally done during rasterization. Those per-vertex attributes are interpolated along the surface of the primitive (triangle in this case) based on the fragment's distance relative to the vertices that were used to build the primitive. In DX11 interpolation can be deferred until the fragment shader itself runs (called "pull-model" interpolation), but traditionally this is something that happens during rasterization.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • If the implementation is caching the vertex shader's outputs, then afaik it's detected that a second invocation of the vertex shader for that vertex can't result in any different values, so the point is moot. – Colonel Thirty Two Apr 21 '14 at 17:24
  • 1
    @ColonelThirtyTwo: There's actually limited capacity for the post T&L cache and it is traditionally FIFO, this is why supplying vertices in locality optimized order such as *strip-order* can improve performance even if you don't actually use the vertices as a strip (which mostly saves on the number of indices you have to store). Geometry Shaders make matters worse by introducing a second layer of data that needs to be cached, but that mostly affects the maximum number of simultaneous invocations of a GS and the size of the post-GS cache was largely addressed when tessellation was introduced. – Andon M. Coleman Apr 21 '14 at 17:39
  • Right, but those don't affect the final rendered image. For someone who looks like they are just starting to learn OpenGL and isn't too worried about efficiency, it seems like a technical thing to get into. – Colonel Thirty Two Apr 21 '14 at 20:23
  • 1
    @ColonelThirtyTwo: It definitely is a technical thing that does not pertain much to this question, that is why I did not bother going into detail explaining any of the terms. I kind of just dangled the fact that it is a false assumption out there and used the proper terminology in case there was a desire to learn more. To properly explain all that would take pages ;) – Andon M. Coleman Apr 21 '14 at 20:45