In which you learn the least bit of terminology that you need to make some sense of how graphics applications are put together.
Most of the applications you've developed so far are written in a high-level language. Your source code gets compiled down to the machine code of your central processing unit. Your CPU's instruction set might be x86_64 or ARM. CPUs are general purpose hardware, ready to handle all sorts of programs that might be thrown at them.
Graphics programs tend to be computationally intense. They have a lot of data to process, and the pixels may need to be updated 60 times a second to feel interactive. For this reason, companies started to design specialized hardware for rendering images and 3D scenes in the 1990s. This special purpose hardware is called a graphics processing unit, or GPU. The instruction set of a GPU is much narrower than that of a CPU. It is designed to multiply matrices, fill in triangles, and look up pixels in images. GPUs have many processors and their own storage called video RAM (VRAM).
The graphics programs you develop will usually start off running on the CPU. The CPU code will read in files, set up the scene, and handle user events. But it will transfer the scene data to the video RAM of the GPU, where it will reside for quick access. When the CPU asks for a frame to be rendered, the GPU will pull vertices out of VRAM, position them on the screen using its many vertex processors, and color the pixels in between the vertices using its many fragment processors.
The image you see on your monitor is backed by a rectangular array of pixels called a framebuffer. This framebuffer lives in VRAM on the GPU. In an animated rendering, the framebuffer is usually cleared to some background color at the beginning of every frame to erase the previous frame. An infinite loop something like the following executes on the CPU:
while true
ask the GPU to clear its framebuffer
ask the GPU to draw object1
ask the GPU to draw object2
ask the GPU to draw object3
...
When you take a screenshot, you must transfer a portion of the framebuffer from the GPU back to the CPU, which saves the pixels to the file system.
The objects that are drawn on the screen are sparsely represented as vertices in three-dimensional space. A rectangle is represented with just four vertices. At the very least, each vertex must be located somewhere in space. A vertex might also have its own color. Later on you'll add even more properties to each vertex. These per-vertex properties are called vertex attributes.
Before an object can be rendered, you collect all its vertex attributes up into a big array and upload it to VRAM, where it's stored in a vertex buffer object (VBO).
When you ask the GPU to draw an object, the GPU will pull out vertices from the object's VBO and run them through a vertex processor. The code that the vertex processors run is called a vertex shader, which is code you write. In this course, that code is written in the OpenGL Shading Language (GLSL).
The primary job of the vertex shader is to turn the vertex attributes into a position on the screen.
An object generally will generally cover more pixels than its vertices. For example, a rectangle that fills a 512-by-512 framebuffer will have only four vertices, but 262,144 pixels. The GPU will fill in the pixels between the vertex locations automatically through a process called rasterization.
The code that the fragment processors run is called a fragment shader, which is also code that you write. The primary job of the fragment shader is to turn the outputs from the vertex shader into a pixel color. The color will be stored in the framebuffer.
The vertex shader and fragment shader are compiled together into a shader program.
You connect the vertex attributes stored in the VBO with the shader programs by way of a vertex array object (VAO). This is not a great name. If you pronounce it "vow", then the name makes more sense. A VAO is the marriage between a VBO and a shader program.