84

Is there an analogy that I can think of when comparing these different types, or how these things work?

Also, what does uniforming a matrix mean?

Skorpius
  • 1,943
  • 2
  • 20
  • 29

4 Answers4

90

Copied directly from http://www.lighthouse3d.com/tutorials/glsl-tutorial/data-types-and-variables/. The actual site has much more detailed information and would be worthwhile to check out.

Variable Qualifiers

Qualifiers give a special meaning to the variable. The following qualifiers are available:

  • const – The declaration is of a compile time constant.
  • attribute – Global variables that may change per vertex, that are passed from the OpenGL application to vertex shaders. This qualifier can only be used in vertex shaders. For the shader this is a read-only variable. See Attribute section.
  • uniform – Global variables that may change per primitive [...], that are passed from the OpenGL application to the shaders. This qualifier can be used in both vertex and fragment shaders. For the shaders this is a read-only variable. See Uniform section.
  • varying – used for interpolated data between a vertex shader and a fragment shader. Available for writing in the vertex shader, and read-only in a fragment shader. See Varying section.

As for an analogy, const and uniform are like global variables in C/C++, one is constant and the other can be set. Attribute is a variable that accompanies a vertex, like color or texture coordinates. Varying variables can be altered by the vertex shader, but not by the fragment shader, so in essence they are passing information down the pipeline.

Peter O.
  • 28,965
  • 14
  • 72
  • 87
Alfredo Gimenez
  • 1,961
  • 12
  • 17
  • 1
    Just to expand a bit on attributes: an attribute needs not be an array attribute (an array attribute is needed if the value can be different for each vertex). It can be a constant vertex attribute too, in which case the value is shared among all vertices. In fact, the array attribute needs to be actively enabled by gl.enableVertexAttribArray. – Robert Monfera Oct 19 '16 at 14:43
  • Good to have the text here because the website is dead – ziyuang Dec 05 '19 at 09:59
  • Just to be "that guy" but I see nothing on the site that suggest that it was legal to copy this here. – gman Nov 16 '20 at 05:01
69
  • uniform are per-primitive parameters (constant during an entire draw call) ;
  • attribute are per-vertex parameters (typically : positions, normals, colors, UVs, ...) ;
  • varying are per-fragment (or per-pixel) parameters : they vary from pixels to pixels.

It's important to understand how varying works to program your own shaders.
Let's say you define a varying parameter v for each vertex of a triangle inside the vertex shader. When this varying parameter is sent to the fragment shader, its value is automatically interpolated based on the position of the pixel to draw.

In the following image, the red pixel received an interpolated value of the varying parameter v. That's why we call them "varying".

varying parameter being bilinearly interpolated

For the sake of simplicity the example given above uses bilinear interpolation, which assumes that all the pixels drawn have the same distance from the camera. For accurate 3D rendering, graphic devices use perspective-correct interpolation which takes into account the depth of a pixel.

neeh
  • 2,251
  • 2
  • 21
  • 31
  • 2
    The spirit of the answer is right but remember that for _varying_, the default interpolation done is called perspective-correct interpolation and not merely bilinear interpolation. Of course, this can be changed with the [interpolation qualifier](https://www.khronos.org/opengl/wiki/Type_Qualifier_(GLSL)#Interpolation_qualifiers) `noperspective` to get simple bilinear interpolation and not perspective-correct interpolation (identified by the default qualifier: `smooth`). See [this example](http://www.geeks3d.com/20130514/opengl-interpolation-qualifiers-glsl-tutorial/). – legends2k Aug 26 '19 at 17:56
  • Thanks, I'm gonna add a note about this. – neeh Aug 27 '19 at 10:18
12

In WebGL what are the differences between an attribute, a uniform, and a varying variable?

In OpenGL, a "program" is a collection of "shaders" (smaller programs), which are connected to each other in a pipeline.

// "program" contains a shader pipeline:
//   vertex shader -> other shaders -> fragment shader
//
const program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);

Shaders process vertices (vertex shader), geometries (geometry shader), tessellation (tessellation shader), fragments (pixel shader), and other batch process tasks (compute shader) needed to rasterize a 3D model.

OpenGL (WebGL) shaders are written in GLSL (a text-based shader language compiled on the GPU).

// Note: As of 2017, WebGL only supports Vertex and Fragment shaders

<!-- Vertex Shader -->
<script id="shader-vs" type="x-shader/x-vertex">

  // <-- Receive from WebGL application
  uniform vec3 vertexVariableA;

  // attribute is supported in Vertex Shader only
  attribute vec3 vertexVariableB;

  // --> Pass to Fragment Shader
  varying vec3 variableC;

</script>

<!-- Fragment Shader -->
<script id="shader-fs" type="x-shader/x-fragment">

  // <-- Receive from WebGL application
  uniform vec3 fragmentVariableA;

  // <-- Receive from Vertex Shader
  varying vec3 variableC;

</script>

Keeping these concepts in mind:

Shaders can pass data to the next shader in the pipeline (out, inout), and they can also accept data from the WebGL application or a previous shader (in).

  • The Vertex and Fragment shaders (any shader really) can use a uniform variable, to receive data from the WebGL application.

    // Pass data from WebGL application to shader
    const uniformHandle = gl.glGetUniformLocation(program, "vertexVariableA");
    gl.glUniformMatrix4fv(uniformHandle, 1, false, [0.1, 0.2, 0.3], 0);
    
  • The Vertex Shader can also receive data from the WebGL application with the attribute variable, which can be enabled or disabled as needed.

    // Pass data from WebGL application to Vertex Shader
    const attributeHandle = gl.glGetAttribLocation(mProgram, "vertexVariableB");
    gl.glEnableVertexAttribArray(attributeHandle);
    gl.glVertexAttribPointer(attributeHandle, 3, gl.FLOAT, false, 0, 0);
    
  • The Vertex Shader can pass data to the Fragment Shader using the varying variable. See GLSL code above (varying vec3 variableC;).

tim-montague
  • 12,048
  • 2
  • 50
  • 40
1

Uniforms are another way to pass data from our application on the CPU to the shaders on the GPU, but uniforms are slightly different compared to vertex attributes. First of all, uniforms are global. Global, meaning that a uniform variable is unique per shader program object, and can be accessed from any shader at any stage in the shader program. Second, whatever you set the uniform value to, uniforms will keep their values until they're either reset or updated

I like the description from https://learnopengl.com/Getting-started/Shaders , because the the word per-primitive is not intuitive

Liu Hao
  • 344
  • 3
  • 15