Cg Programming/Unity/RGB Cube

This tutorial discusses vertex output parameters and fragment input parameters. It is assumed that you are familiar with .
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 formula_1 has the color formula_2. For example, the point formula_3 is mapped to the color formula_4, 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 &gt; 3D Object &gt; 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 &amp; paste into your shader object:
Shader "Cg shader for RGB cube" { 
 SubShader { 
 Pass { 
 CGPROGRAM 
 #pragma vertex vert // vert function is the vertex shader 
 #pragma fragment frag // frag function is the fragment shader
 // for multiple vertex output parameters an output structure 
 // is defined:
 struct vertexOutput {
 float4 pos : SV_POSITION;
 float4 col : TEXCOORD0;
 
 vertexOutput vert(float4 vertexPos : POSITION) 
 // vertex shader 
 vertexOutput output; // we don't need to type 'struct' here
 output.pos = UnityObjectToClipPos(vertexPos);
 output.col = vertexPos + float4(0.5, 0.5, 0.5, 0.0);
 // Here the vertex shader writes output data
 // to the output structure. We add 0.5 to the 
 // x, y, and z coordinates, because the 
 // coordinates of the cube are between -0.5 and
 // 0.5 but we need them between 0.0 and 1.0. 
 return output;
 
 float4 frag(vertexOutput input) : COLOR // fragment shader
 return input.col; 
 // Here the fragment shader returns the "col" input 
 // parameter with semantic TEXCOORD0 as nameless
 // output parameter with semantic COLOR.
 
 ENDCG 
If your cube is not colored correctly, check the console for error messages (by selecting Window &gt; General &gt; 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.
Communication between Vertex and Fragment Shaders.
The main task of our shader is to set the fragment output color (i.e. the fragment output parameter with semantic codice_1) in the fragment shader to the vertex position that is available in the vertex shader. Actually, this is not quite true: the coordinates in the vertex input parameter with semantic codice_2 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: codice_3.
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 pairs of vertex output parameters and fragment input parameters with the same semantics (codice_4 in this case). In fact, it is only the semantics that are used to determine which vertex output parameters correspond to which fragment input parameters. Instead of the semantic codice_4 we could also use another semantic, e.g. codice_1, it doesn't really matter here, except that parameters with the semantic codice_1 are often clamped to values between 0 and 1 (which would be OK in this case). It is, however, common to use the semantics codice_4, codice_9, codice_10, etc. for all kinds of parameters.
The next problem is to specify multiple vertex output parameters. Since the return instruction can only return one value, it is common to define a structure for all the required vertex output parameters. Here, this structure is called codice_11:
 struct vertexOutput {
 float4 pos : SV_POSITION;
 float4 col : TEXCOORD0;
By using this structure as an argument of the fragment shader function, we make sure that the semantics match. Note that in Cg (in contrast to C), we don't have to write codice_12 when defining variables of this type but we can just use the name codice_11 (without codice_14) for the same type.
The out Qualifier.
An alternative to the use of an output structure would be to use arguments of the vertex shader function with the codice_15 qualifier, e.g.:
Shader "Cg shader for RGB cube" { 
 SubShader { 
 Pass { 
 CGPROGRAM 
 #pragma vertex vert // vert function is the vertex shader 
 #pragma fragment frag // frag function is the fragment shader
 void vert(float4 vertexPos : POSITION,
 out float4 pos : SV_POSITION,
 out float4 col : TEXCOORD0) 
 pos = mul(UNITY_MATRIX_MVP, vertexPos);
 col = vertexPos + float4(0.5, 0.5, 0.5, 0.0);
 return;
 
 float4 frag(float4 pos : SV_POSITION, 
 float4 col : TEXCOORD0) : COLOR 
 return col; 
 
 ENDCG 
However, the use of an output structure is more common in practice and it makes sure that vertex output parameters and fragment input parameters have matching semantics. 
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 could compute the mean of the red, green, and blue color components, i.e. formula_5, and then put this value in all three color components of the fragment color to obtain a gray value of the same brightness. Instead of the mean, the relative luminance could also be used, which is formula_6. 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 formula_7 you could subtract from a pure white an amount of red that is proportional to formula_8 in order to produce cyan. Furthermore, you would subtract an amount of green in proportion to the formula_9 component to produce magenta and also an amount of blue in proportion to formula_10 to produce yellow.
If you really want to get fancy, you could compute an HSV (hue, saturation, value) cylinder. For formula_8 and formula_10 coordinates between -0.5 and +0.5, you can get an angle formula_13 between 0 and 360° with codice_16 in Cg and a distance formula_14 between 0 and 1 from the formula_9 axis with codice_17. The formula_9 coordinate for Unity's built-in cylinder is between -1 and 1 which can be translated to a value formula_17 between 0 and 1 by formula_18. The computation of RGB colors from HSV coordinates is described in the article on HSV in Wikipedia.
Interpolation of Vertex Output Parameters.
The story about vertex output parameters and fragment input parameters 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 vertex output parameters. However, there are many more colors on the cube. How did that happen?
In fact, the vertex shader is only called for each vertex of each triangle. However, the different values of the vertex output parameters for the different vertices 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 vertex output parameters as fragment input parameters. 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 (so-called "flat shading"), you can either make sure that the vertex shader writes the same value to the vertex output parameters for all vertices of a triangle, or you can use the HLSL storage-class modifier codice_18. In our example, you could use this struct:
 struct vertexOutput {
 float4 pos : SV_POSITION;
 nointerpolation float4 col : TEXCOORD0;
Summary.
And this is the end of this tutorial. Congratulations! Among other things, you have seen:
Further reading.
If you want to know more