## In Review

In this tutorial, you have learned the following:

• Point lights are lights that have a position within the world, radiating light equally in all directions. The light direction at a particular point on the surface must be computed using the position at that point and the position of the light.

• Attempting to perform per-vertex lighting computations with point lights leads to artifacts.

• Lighting can be computed per-fragment by passing the fragment's position in an appropriate space.

• Lighting can be computed in model space.

• Point lights have a falloff with distance, called attenuation. Not performing this can cause odd effects, where a light appears to be brighter when it moves farther from a surface. Light attenuation varies with the inverse of the square of the distance, but other attenuation models can be used.

• Fragment shaders can compute the camera space position of the fragment in question by using `gl_FragCoord` and a few uniform variables holding information about the camera to window space transform.

• GLSL can have integer vectors, boolean values, and functions.

### Further Study

Try doing these things with the given programs.

• When we used model space-based lighting computations, we had to perform an inverse on our matrix from the matrix stack to transform the light position from camera space to model space. However, it would be entirely possible to simply build an inverse matrix at the same time we build a regular matrix on our matrix stack. The inverse of a rotation matrix is just the rotation matrix with a negated angle; the inverse of a scale is just the multiplicative inverse of the scales, and the inverse of the translation is the negation of the translation vector.

To do this, you will need to modify the `MatrixStack` class in a number of ways. It must store a second matrix representing the accumulated inverse matrix. When a transformation command is given to the stack, it must also generate the inverse matrix for this transform and left multiply this into the accumulated inverse. The push/pop will have to push/pop the inverse matrix as well. It can use the same stack, so long as the pop function puts the two matrices in the proper places.

• Implement the alternative attenuation described at the end of the section on attenuation.

### GLSL Features of Note

gl_DepthRange

A built-in OpenGL uniform defined for fragment shaders only. This uniform stores the parameters passed to `glDepthRange.` When those parameters change, all programs are automatically updated.

 `vec inversesqrt(` vec x`)`;

This function computes 1 / the square root of `x`. This is a component-wise computation, so vectors may be used. The return value will have the same type as `x`.

 `vec sqrt(` vec x`)`;

This function computes the square root of `x`. This is a component-wise computation, so vectors may be used. The return value will have the same type as `x`.