Chapter 2. Playing with Colors
Prev | Part I. The Basics | Next

## Chapter 2. Playing with Colors

This tutorial will show how to provide some color to the triangle from the previous tutorial. Instead of just giving the triangle a solid color, we will use two methods to provide it with varying color across its surface. The methods are to using the fragment's position to compute a color and to using per-vertex data to compute a color.

## Fragment Position Display

As we stated in the overview, part of the fragment's data includes the position of the fragment on the screen. Thus, if we want to vary the color of a triangle across its surface, We can access this data in our fragment shader and use it to compute the final color for that fragment. This is done in the Fragment Position tutorial, who's main file is `FragPosition.cpp`.

In this tutorial, and all future ones, shaders will be loaded from files instead of hard-coded strings in the .cpp file. To support this, the framework has the `Framework::LoadShader` and `Framework::CreateProgram` functions. These work similarly to the previous tutorial's `CreateShader` and `CreateProgram`, except that `LoadShader` takes a filename instead of a shader file.

The FragPosition tutorial loads two shaders, the vertex shader `data/FragPosition.vert` and the fragment shader `data/FragPosition.frag`. The vertex shader is identical to the one in the last tutorial. The fragment shader is very new, however:

Example 2.1. FragPosition's Fragment Shader

    #version 330

    out vec4 outputColor;

    void main()
    {
        float lerpValue = gl_FragCoord.y / 500.0f;

        outputColor = mix(vec4(1.0f, 1.0f, 1.0f, 1.0f),
            vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpValue);
    }

`gl_FragCoord` is a built-in variable that is only available in a fragment shader. It is a `vec3`, so it has an X, Y, and Z component. The X and Y values are in window coordinates, so the absolute value of these numbers will change based on the window's resolution. Recall that window coordinates put the origin at the bottom-left corner. So fragments along the bottom of the triangle would have a lower Y value than those at the top.

The idea with this shader is that the color of a fragment will be based on the Y value of its window position. The 500.0f is the height of the window (unless you resize the window). The division in the first line of the function simply converts the Y position to the [0, 1] range, where 1 is at the top of the window and 0 is at the bottom.

The second line uses this [0, 1] value to perform a linear interpolation between two colors. The `mix` function is one of the many, many standard functions that the OpenGL Shading Language provides. Many of these functions, like `mix`, are vectorized. That is, some of their parameters can be vectors, and when they are, they will perform their operations on each component of the vector simultaneously. In this case, the dimensionality of the first two parameters must match.

The `mix` function performs a linear interpolation. It will return exactly the first parameter if the third parameter is 0, and it will return exactly the second parameter if the third parameter is 1. If the third parameter is between 0 and 1, it will return a value between the two other parameters, based on the third parameter.

### Note

The third parameter to `mix` must be on the range [0, 1]. However, GLSL will not check this or do the clamping for you. If it is not on this range, the result of the `mix` function will be undefined. “Undefined” is the OpenGL shorthand for, “I do not know, but it is probably not what you want.”

We get the following image:

Figure 2.1. Fragment Position

In this case, the bottom of the triangle, the one closest to a Y of 0, will be the most white. While the top of the triangle, the parts closest to a Y of 500, will have the darkest color.

Other than the fragment shader, nothing much changes in the code.

Prev | Up | Next
Glossary | Home | Vertex Attributes