I don’t think analogies are really helpful.
A uniform variable has the same value for every shader invocation resulting from a given draw call. They can be accessed from any shader stage (vertex, fragment, geometry, etc) in the program. You set the value with glUniform
. Uniform variables are stored in the program object (this can be an issue if you’re using the same program from multiple threads).
There are also uniform blocks, which behave like a uniform variable of structure type, but the data is stored in a buffer object rather than in the program object. There are no specific calls to set the values; you just modify the buffer’s contents using e.g. glBufferSubData
or glMapBuffer
etc. This avoids the issue with multi-threading, and also allows you to change the values of all of the variables in one go by binding a different buffer object.
An input variable may have different values for different shader invocations. Vertex shader inputs take their values either from attribute arrays (glVertexAttribPointer
) or if the attribute array is disabled (gl{Enable,Disable}VertexAttribArray
) from a constant value set with glVertexAttrib
. Fragment shader inputs get their values from the vertex shader outputs (assuming that no other stages are present), either by interpolating the values across the primitive or (if the variable has the flat
qualifier) by using the value from one of the vertices for all fragments in the primitive.