# Point Light Tutorial

## Introduction

This article discusses the vertex and fragment shaders for the Point Light example. The vertex shader provides most of the functionality for the Point Light example. The Fragment Shader Point Light and Face Mapped Cube examples process lighting primarily in the fragment shader. Yet all three examples follow the same pattern.

This tutorial explains the steps which generate point lighting. This article briefly discusses the trade off between processing in the vertex shader, versus the fragment shader.

Seven Thunder Software didn't create the algorithm for the shaders presented here. Light algorithms are based on observations recorded as far back as 10 AD, with detail provided by others along the way.

## Model and Normal Matrices

The model matrix represents rotation and translation for cube vertices in the example projects. The normal matrix represents relative rotation and translation for normals associated with vertices in the cube.

The JavaScript for this example uploads an attribute with normal coordinates per vertex. Each frame of animation uploads a normal matrix. The normal matrix is a 3 x 3 matrix derived from the inverted and transposed model matrix.

That's a complicated way of saying the normal matrix represents a reduced model matrix. The 3 x 3 normal matrix contains the first three entries of the first three rows of the 4 x 4 model matrix.

The following two listings show a sample 4 x 4 model matrix, followed by the transposed and inverted 3 x 3 normal matrix.

### Model Matrix

```0.993,0.095,-0.06,0
0,0.528,0.849,0
0.112,-0.844,0.524,0
0,4.246,-7.641,1
```

### Normal Matrix

```0.993,0.095,-0.06
-0.001,0.528,0.849
0.112,-0.844,0.524
```

### Varyings

The vertex shader sends two varyings out for use within the fragment shader. Varying `v_tex_coord0` simply receives texel coordinates from attribute `a_tex_coord0`. Varying `v_lightweighting` is the focus of this tutorial. The vertex shader assigns a value to `v_lightweighting` representing the amount of light color to apply for each vertex.

```varying vec3 v_lightweighting;
varying vec2 v_tex_coord0;
```

### Attributes

Attribute input to the vertex shader include `vec4` attributes for vertex coordinates, associated `vec3` normal coordinates, as well as texel attributes. The texel attributes are simply passed through a varying to the fragment shader. The following listing includes attribute declarations for vertex coordinates, normals and texels.

```attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_tex_coord0;
```

### Constants

Constants within the vertex shader include a `vec3` representing ambient light, a `vec3` representing the light vector, and a `vec3` representing the light color. The following listing shows the constant declarations.

```const vec3 c_ambient = vec3(
0.2,
0.2,
0.2
);

const vec3 c_light_location = vec3(
-0.5,
-0.5,
1.0
);

const vec3 c_light_color = vec3(
0.8,
0.8,
0.8
);
```

### Uniforms

Uniform input to the vertex shader include a 4 x 4 model view matrix `um4_matrix`, 3 x 3 normal matrix `um3_nmatrix`, and a perspective projection matrix `um4_pmatrix`. The model view matrix `mat4 um4_matrix` represents rotation and translation per frame. The normal matrix `mat3 um3_nmatrix` also represents rotation and translation per frame. However multiply the 3 x 3 normal matrix with a `vec3` normal and the 4 x 4 model view matrix with `vec4` vertex coordinates.

Determine the location of the current vertex modified by translation and rotation. The following line multiplies the model view matrix with the vertex coordinate.

```vec4 v4_model_position = um4_matrix * a_position;
```

Determine the direction of the normal modified by translation and rotation. The following line multiplies the normal matrix with the normal attribute.

```vec3 v3_normal = um3_nmatrix * a_normal;
```

### Vectors

A GLSL `vec3` represents three floating point values. Developers can use `vec3` in a number of ways. For example shaders might access the values of a `vec3` as vertex coordinates with X,Y,Z values, color channels with R,G,B values, or as a vector. A vector is a signed displacement. Vectors represent direction and magnitude or length. For example a `vec3` with the following three values `1.0,3.0,2.0`, represent a displacement of one unit on the X axis, three units on the Y axis, and two units on the Z axis. Apply the Pythagorean theorem to determine the magnitude. The vector symbol is a line with an arrow at one end. Vectors point in specific directions. The arrow represents the direction of the vector.

First the vertex shader declares a `vec4` which represents the transformed position of the current vertex. This article previously displayed the following line which assigns the rotated or translated vertex coordinate to `vec4 v4_model_position`. The shader needs `v4_model_position` for the next step.

```vec4 v4_model_position = um4_matrix * a_position;
```

Second the vertex shader calculates vector `v3_subtraction_vector` as the difference between the transformed vertex vector and the constant light direction vector. The shader subtracts transformed vertex coordinates from the light direction vector. Subtract `v4_model_position` from `c_direction_light`.

```vec3 v3_subtraction_vector = normalize(
c_direction_light - v4_model_position.xyz
);
```

Imagine `c_light_direction` and `v4_model_position` touch at some point and form two edges of a triangle. Vector `v3_subtraction_vector` forms a triangle of three edges. Now the shader has a vector which represents the difference between the current vertex position and the angle of the light. In other words the vector describes the relationship between the vertex and the light.

The built-in function `normalize()` is applied to the result. The `normalize()` function returns a vector with magnitude of one. A vector with magnitude or length of one is called a unit vector. The direction of the normalized vector remains the same.

Now find the relationship between the normal and `v3_subtraction_vector`. Use the dot product to determine how much light to apply to this fragment.

### Dot Product

Third take the dot product of the transformed normal and the subtraction vector `v3_subtraction_vector`. The dot product indicates the amount of similarity between the normal and the subtraction vector.

With two unit vectors dot product returns values between negative one and positive one. If the dot product returns zero, then two vectors are perpendicular. If the dot product returns a value greater than zero, the two vectors point about the same direction. Values greater than zero indicate an acute angle. A dot product of one indicates two vectors are parallel. Values less than zero indicate an obtuse angle.

The vertex shader uses dot product to determine how much light color the fragment shader will mix with the sampler color. If the dot product returns zero, the vectors are perpendicular, apply zero brightness from the light color to the current fragment. If the dot product returns a value greater than zero, the two vectors point about the same direction. Multiply the value returned by the dot product and the light color, then apply that value to the fragment color.

The final result provides gradual shading across each surface, taking into account the vertex position, normal and light direction. The following listing demonstrates taking the dot product between the transformed normal and the subtraction vector.

```dot(
v3_normal,
v3_subtraction_vector
)
```

Call the built-in function `max()` to return only non negative numbers. Assign the result to the floating point number `f_light_weighting`.

```float f_light_weighting = max(
dot(
normalize(v3_normal),
v3_subtraction_vector
),
0.0
);
```

## Point Light Diagram

Two vector operations determine the amount of light color to apply to a fragment. Subtract the vertex vector from the light vector. The result is labeled Subtraction Vector in the following diagram. Call the `dot()` product function, to find the amount of similarity between the Subtraction Vector and the normal vector. If the angle between vectors is acute, then apply light color. The more similar the vectors are, the more light color applies for this vertex. If the vectors are perpendicular or obtuse, then apply zero light color.

Last the vertex shader determines the amount of light color to send out for the fragment shader. Multiply the light color by the result of the dot product. Add in the ambient light. The sum equals the amount of light to apply for this vertex. Assign the result to the varying `v_lightweighting`. The GPU interpolates values then sends them on to the fragment shader through the varying with the same name; `v_lightweighting`.

```v_lightweighting =
c_ambient +
c_light_color * f_light_weighting;
```

The vertex shader also multiplies the modified vertex coordinate by the perspective projection matrix. Last the built in variable `gl_Position` receives the modified vertex coordinate. The listing for the entire vertex shader follows.

```attribute vec4 a_position;
attribute vec2 a_tex_coord0;
varying vec2 v_tex_coord0;

attribute vec4 a_normal;

// Translated or
// rotated normal matrix.
uniform mat3 um3_nmatrix;

// Translated or
// rotated  model matrix:
uniform mat4 um4_matrix;

// PP matrix.
uniform mat4 um4_pmatrix;

const vec3 c_ambient = vec3(
0.2,
0.2,
0.2
);

const vec3 c_light_location = vec3(
-0.5,
-0.5,
1.0
);

const vec3 c_light_color = vec3(
0.8,
0.8,
0.8
);

varying vec3 v_lightweighting;

void main(void) {
// The position of the
// vertex after rotation and translation.
vec4 v4_model_position = um4_matrix * a_position;

// Determine the direction of the normal
// relative to the current
// rotation and translation.
vec3 v3_normal = um3_nmatrix * a_normal;

// Find the vector
// which represents the
// difference between
// the light vector
// and the position
// of the current vertex.

// The vector from
// the vertex coordinate
// to the light direction.
vec3 v3_subtraction_vector = normalize
(
c_light_location - v4_model_position.xyz
);

// The amount of light.
// Dot product of the normal
// direction and light direction.
// max() restricts result
// to non negative numbers.
float f_light_weighting = max(
dot(
v3_normal,
v3_subtraction_vector
),
0.0
);

// Varying output.
v_tex_coord0 = a_tex_coord0;

// Assign the amount
// of light to apply
// to this vertex,
// to the varying:
v_lightweighting =
c_ambient +
c_light_color * f_light_weighting;

gl_Position = um4_pmatrix * v4_model_position;
}
```

Very little happens in the fragment shader compared to the vertex shader

Varying output from the vertex shader become input for the fragment shader, after the GPU interpolates values. The fragment shader receives the `vec2` varying `v_tex_coord0` as texel coordinates to sample the texture. The fragment shader receives the `vec3` varying `v_lightweighting` which represents the amount of light to apply to this fragment.

The fragment shader samples a texture. The fragment shader multiplies the RGB values of the sample, by the varying `v_lightweighting`. Maintain the sample's original alpha value.

```gl_FragColor = vec4(
color0.rgb * v_lightweighting,
color0.a
);
```

The entire fragment shader source code follows.

```precision mediump float;

// Texel.
varying vec2 v_tex_coord0;

// The amount of
// light to apply
// to this fragment.
varying vec3 v_lightweighting;

uniform sampler2D u_sampler0;

void main(void) {

// Sample the texture.
vec4 v4_color0 = texture2D(
u_sampler0,
v_tex_coord0
);

// Multiply the
// sample color's RGB
// values by the amount
// of light to apply.
gl_FragColor = vec4(
v4_color0.rgb * v_lightweighting,
v4_color0.a
);
}
```

## Summary

This article discussed the vertex and fragment shaders for the Point Light example. The vertex shader provides most of the functionality for the Point Light example. The Fragment Shader Point Light and Face Mapped Cube examples process lighting primarily in the fragment shader. Yet all three examples follow the same pattern.

This tutorial explained the steps which generate point lighting. This article briefly discussed the trade off between processing in the vertex shader, versus the fragment shader.

Have fun and love learning! See more lighting examples below.