- Brick Shader Overview
- Vertex Shader
- Fragment Shader
- Observations
- Summary
- Further Information

## 6.3 Fragment Shader

The purpose of a fragment shader is to compute the color to be applied to a fragment or to compute the depth value for the fragment or both. In this case (and indeed with most fragment shaders), we're concerned only about the color of the fragment. We're perfectly happy using the depth value that's been computed by the OpenGL rasterization stage. Therefore, the entire purpose of this shader is to compute the color of the current fragment.

Our brick fragment shader starts off by defining a few more uniform variables than did the vertex shader. The brick pattern that will be rendered on our geometry is parameterized in order to make it easier to modify. The parameters that are constant across an entire primitive can be stored as uniform variables and initialized (and later modified) by the application. This makes it easy to expose these controls to the end user for modification through user interface elements such as sliders and color pickers. The brick fragment shader uses the parameters that are illustrated in Figure 6.1. These are defined as uniform variables as follows:

uniform vec3 BrickColor, MortarColor; uniform vec2 BrickSize; uniform vec2 BrickPct;

We want our brick pattern to be applied in a consistent way to our geometry in order to have the object look the same no matter
where it is placed in the scene or how it is rotated. The key to determining the placement of the brick pattern is the modeling
coordinate position that is computed by the vertex shader and passed in the varying variable *MCposition*:

varying vec2 MCposition;

This variable was computed at each vertex by the vertex shader in the previous section, and it is interpolated across the primitive and made available to the fragment shader at each fragment location. Our fragment shader can use this information to determine where the fragment location is in relation to the algorithmically defined brick pattern. The other varying variable that is provided as input to the fragment shader is defined as follows:

varying float LightIntensity;

This varying variable contains the interpolated value for the light intensity that we computed at each vertex in our vertex shader. Note that both of the varying variables we defined in our fragment shader are defined with the same type that was used to define them in our vertex shader. A link error would be generated if this were not the case.

With our uniform and varying variables defined, we can begin with the actual code for the brick fragment shader:

void main (void) { vec3 color; vec2 position, useBrick;

In this shader, we'll do things more like we would in C and define all our local variables before they're used at the beginning
of our *main* function. In some cases, this can make the code a little cleaner or easier to read, but it is mostly a matter of personal
preference and coding style. The first actual lines of code in our brick fragment shader will compute values for the local
**vec2** variable *position*:

position = MCposition / BrickSize;

This statement divides the fragment's *x* position in modeling coordinates by the column width and the *y* position in modeling coordinates by the row height. This gives us a "brick row number" (*position.y*) and a "brick number" within that row (*position.x*). Keep in mind that these are signed, floating-point values, so it is perfectly reasonable to have negative row and brick
numbers as a result of this computation. Next, we'll use a conditional to determine whether the fragment is in a row of bricks
that is offset:

if (fract(position.y * 0.5) > 0.5) position.x += 0.5;

The "brick row number" (*position.y*) is multiplied by 0.5, and the result is compared against 0.5. Half the time (or every other row) this comparison will be
true, and the "brick number" value (*position.x*) is incremented by 0.5 to offset the entire row by half the width of a brick. Following this, we need to compute the fragment's
location within the current brick:

position = fract(position);

This computation provides us with the vertical and horizontal position within a single brick. This will be used as the basis for determining whether to use the brick color or the mortar color.

Next we need a function that gives us a value of 1.0 when the brick color should be used and 0 when the mortar color should be used. If we can achieve this, we'll end up with a simple way to choose the appropriate color. We know that we're working with a horizontal component of the brick texture function and a vertical component. If we can create the desired function for the horizontal component and the desired function for the vertical component, we can just multiply the two values together to get our final answer. If the result of either of the individual functions is 0 (mortar color), the multiplication will cause the final answer to be 0; otherwise, it will be 1.0, and the brick color will be used.

The *step* function can be used to achieve the desired effect. It takes two arguments, an edge (or threshold) and a parameter, to test
against that edge. If the value of the parameter to be tested is less than or equal to the edge value, the function returns
0; otherwise, it returns 1.0. (Refer to Figure 5.11 for a graph of this function). In typical use, the *step* function is used to produce a pattern of pulses (i.e., a square wave) where the function starts off at 0 and rises to 1 when
the threshold is reached. We can get a function that starts off at 1.0 and drops to 0 just by reversing the order of the two
arguments provided to this function:

useBrick = step(position, BrickPct);

In these two lines, we compute two values that tell us whether we are in the brick or in the mortar in the horizontal direction
(*useBrick.x*) and in the vertical direction (*useBrick.y*). The built-in function *step* will produce a value of 0 when *BrickPct.x* <= *position.x* and a value of 1.0 when *BrickPct.x* > *position.x*. Because of the *fract* function, we know that *position.x* will vary from [0,1). The variable *BrickPct* is a uniform variable, so its value will be constant across the primitive. This means that the value of *useBrick.x* will be 1.0 when the brick color should be used and 0 when the mortar color should be used as we move horizontally. The same
thing is done in the vertical direction using *position.y* and *BrickPct.y* to compute the value for *useBrick.y*. By multiplying *useBrick.x* and *useBrick.y* together, we can get a value of 0 or 1.0 that will let us select the appropriate color for the fragment. The periodic step
function for the horizontal component of the brick pattern is illustrated in Figure 6.3.

**Figure 6.3. The periodic step function that produces the horizontal component of the procedural brick pattern**

The values of *BrickPct.x* and *BrickPct.y* can be computed by the application to give a uniform mortar width in both directions based on the ratio of column width to
row height, or they can be chosen arbitrarily to give a mortar appearance that looks right.

All that remains is to compute our final color value and store it in the special variable *gl_FragColor*:

color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); color *= LightIntensity; gl_FragColor = vec4 (color, 1.0); }

Here we compute the color of the fragment and store it in the local variable *color*. The built-in function *mix* is used to choose the brick color or the mortar color, depending on the value of *useBrick.x * useBrick.y*. Because *useBrick.x* and *useBrick.y* can have values of only 0 (mortar) or 1.0 (brick), we will choose the brick color only if both values are 1.0; otherwise,
we will choose the mortar color.

The resulting value is then multiplied by the light intensity, and that result is stored in the local variable *color*. This local variable is a **vec3**, and *gl_FragColor* is defined as a **vec4**, so we create our final color value by using a constructor to add a fourth component (alpha) equal to 1.0 and assign the
result to the built-in variable *gl_FragColor*.

The source code for the complete fragment shader is shown in Listing 6.2.

#### Listing 6.2. Source code for brick fragment shader

uniform vec3 BrickColor, MortarColor; uniform vec2 BrickSize; uniform vec2 BrickPct; varying vec2 MCposition; varying float LightIntensity; void main(void) { vec3 color; vec2 position, useBrick; position = MCposition / BrickSize; if (fract(position.y * 0.5) > 0.5) position.x += 0.5; position = fract(position); useBrick = step(position, BrickPct); color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); color *= LightIntensity; gl_FragColor = vec4 (color, 1.0); }

When comparing this shader to the vertex shader in the previous example, we notice one of the key features of the OpenGL Shading
Language, namely that the language used to write these two shaders is almost identical. Both shaders have a main function,
some uniform variables, and some local variables; expressions are the same; built-in functions are called in the same way;
constructors are used in the same way; and so on. The only perceptible differences exhibited by these two shaders are (A)
the vertex shader accesses built-in attributes, such as *gl_Vertex* and *gl_Normal*, (B) the vertex shader writes to the built-in variable *gl_Position*, whereas the fragment shader writes to the built-in variable *gl_FragColor*, and (C) the varying variables are written by the vertex shader and are read by the fragment shader.

The application code to create and use these shaders will be shown in Section 7.11, after the OpenGL Shading Language *API* has been presented. The result of rendering some simple objects with these shaders is shown in Figure 6.4. A color version of the result is shown in Color Plate 25.

**Figure 6.4. A flat polygon, a sphere, and a torus rendered with the brick shaders**