GLSL Programming/Unity/RGB Cube

This tutorial introduces varying variables. It is based on.

In this tutorial we will write a shader to render an RGB cube similar to the one shown. The color of each point on the surface is determined by its coordinates; i.e., a point at position $$(x,y,z)$$ has the color $$(\text{red}, \text{green}, \text{blue}) = (x,y,z)$$. For example, the point $$(x,y,z)=(0,0,1)$$ is mapped to the color $$(\text{red}, \text{green}, \text{blue}) = (0,0,1)$$, i.e. pure blue. (This is the blue corner in the lower right of the figure .)

Preparations
Since we want to create an RGB cube, you first have to create a cube game object. As described in for a sphere, you can create a cube game object by selecting GameObject > Create Other > Cube from the main menu. Continue with creating a material and a shader object and attaching the shader to the material and the material to the cube as described in.

The Shader Code
Here is the shader code, which you should copy & paste into your shader object: If your cube is not colored correctly, check the console for error messages (by selecting Window > Console from the main menu), make sure you have saved the shader code, and check whether you have attached the shader object to the material object and the material object to the game object.

Varying Variables
The main task of our shader is to set the output fragment color in the fragment shader to the position  that is available in the vertex shader. Actually, this is not quite true: the coordinates in  for Unity's default cube are between -0.5 and +0.5 while we would like to have color components between 0.0 and 1.0; thus, we need to add 0.5 to the x, y, and z component, which is done by this expression:.

The main problem, however, is: how do we get any value from the vertex shader to the fragment shader? It turns out that the only way to do this is to use varying variables (or varyings for short). Output of the vertex shader can be written to a varying variable and then it can be read as input by the fragment shader. This is exactly what we need.

To specify a varying variable, it has to be defined with the modifier  (before the type) in the vertex and the fragment shader outside of any function; in our example:. And here comes the most important rule about varying variables:

This is required to avoid ambiguous cases where the GLSL compiler cannot figure out which varying variable of the vertex shader should be matched to which varying variable of the fragment shader.

A Neat Trick for Varying Variables in Unity
The requirement that the definitions of varying variables in the vertex and fragment shader match each other often results in errors, for example if a programmer changes a type or name of a varying variable in the vertex shader but forgets to change it in the fragment shader. Fortunately, there is a nice trick in Unity that avoids the problem. Consider the following shader: As the comments in this shader explain, the line  doesn't actually mark the beginning of the vertex shader but the beginning of a part that is only in the vertex shader. Analogously,  marks the beginning of a part that is only in the fragment shader. In fact, both shaders begin with the line. Therefore, any code between  and the first   line will be shared by the vertex and the fragment shader. (If you are familiar with the C or C++ preprocessor, you might have guessed this already.)

This is perfect for definitions of varying variables because it means that we may type the definition only once and it will be put into the vertex and the fragment shader; thus, matching definitions are guaranteed! I.e. we have to type less and there is no way to produce compiler errors because of mismatches between the definitions of varying variables. (Of course, the cost is that we have to type all these  and   lines.)

Variations of this Shader
The RGB cube represents the set of available colors (i.e. the gamut of the display). Thus, it can also be used show the effect of a color transformation. For example, a color to gray transformation would compute either the mean of the red, green, and blue color components, i.e. $$(\text{red}+\text{green}+\text{blue}) / 3$$, and then put this value in all three color components of the fragment color to obtain a gray value of the same intensity. Instead of the mean, the relative luminance could also be used, which is $$0.21 \text{ red} + 0.72 \text{ green} + 0.07 \text{ blue}$$. Of course, any other color transformation (changing saturation, contrast, hue, etc.) is also applicable.

Another variation of this shader could compute a CMY (cyan, magenta, yellow) cube: for position $$(x, y, z)$$ you could subtract from a pure white an amount of red that is proportional to $$x$$ in order to produce cyan. Furthermore, you would subtract an amount of green in proportion to the $$y$$ component to produce magenta and also an amount of blue in proportion to $$z$$ to produce yellow.

If you really want to get fancy, you could compute an HSV (hue, saturation, value) cylinder. For $$x$$ and $$z$$ coordinates between -0.5 and +0.5, you can get an angle $$H$$ between 0 and 360° with  in GLSL and a distance $$S$$ between 0 and 1 from the $$y$$ axis with. The $$y$$ coordinate for Unity's built-in cylinder is between -1 and 1 which can be translated to a value $$V$$ between 0 and 1 by $$(y + 1.0) / 2.0$$. The computation of RGB colors from HSV coordinates is described in the article on HSV in Wikipedia.

Interpolation of Varying Variables
The story about varying variables is not quite over yet. If you select the cube game object, you will see in the Scene View that it consists of only 12 triangles and 8 vertices. Thus, the vertex shader might be called only eight times and only eight different outputs are written to the varying variable. However, there are many more colors on the cube. How did that happen?

The answer is implied by the name varying variables. They are called this way because they vary across a triangle. In fact, the vertex shader is only called for each vertex of each triangle. If the vertex shader writes different values to a varying variable for different vertices, the values are interpolated across the triangle. The fragment shader is then called for each pixel that is covered by the triangle and receives interpolated values of the varying variables. The details of this interpolation are described in.

If you want to make sure that a fragment shader receives one exact, non-interpolated value by a vertex shader, you have to make sure that the vertex shader writes the same value to the varying variable for all vertices of a triangle.

Summary
And this is the end of this tutorial. Congratulations! Among other things, you have seen:
 * What an RGB cube is.
 * What varying variables are good for and how to define them.
 * How to make sure that a varying variable has the same name and type in the vertex shader and the fragment shader.
 * How the values written to a varying variable by the vertex shader are interpolated across a triangle before they are received by the fragment shader.