Here are some exercises to let you explore these concepts in some more depth and detail:
Move the directional lighting calculations out of the shader and store the results in the height map vertex buffer as a single additional float per vertex, so that we only have to calculate this once.
Adjust the lighting to make it dynamic. One way you can do this is by turning the particle shooters on and off and then adjusting the brightness of each shooter based on how many particles are still above the ground. If you’re feeling particularly creative, you can even time this to a beat.
Move the lighting calculations into the fragment shader so that the lighting is calculated for each fragment rather than for each vertex. When you pass your data ...