Vertex Shader (
The vertex stage applies logic to a single vertex. They have access to many properties of their vertex, such as position, color, light level, and a few other things. The primary purpose of vertex shaders is to place the provided vertex at the correct location on your screen. They can also output various pieces of information to the fragment stage using
Geometry Shader (
The geometry stage applies logic to 3 vertices at a time. More specifically, they have inputs for 3 vertices which are part of the same triangle. You might think things would be square instead, since this is Minecraft, but even in Minecraft squares are always made of 2 triangles because that's what the GPU was designed to handle.
The geometry stage can choose to modify vertex positions or change the
varying data which is fed into the fragment stage (explained below), but the REAL power of the geometry stage is that it can change the number of vertices (or triangles) that get drawn. The number still has to be a multiple of 3, and the GPU often has limits on the maximum number of vertices which can be emitted, but the geometry stage is still very powerful nevertheless.
Fragment Shader (
After all the vertices of a specific triangle have been positioned, the GPU determines which pixels are inside it, and which are outside it. This process is called "rasterization". Once rasterization is finished, the GPU will call upon the fragment stage to choose a color for all the pixels that were inside the triangle. They can output more than one color by using more than one "framebuffer attachment".
Compute Shader (
The compute stage has no predetermined job. It can still have the usual uniform inputs, but it does not know about any geometry in the world. It does have one powerful feature though: it can write directly to a buffer at any location. Normally, when a fragment stage writes to a buffer, it is restricted to only writing at the location of the pixel it was assigned to. Compute shaders do not have this restriction.
At the time of writing this, compute stages in OptiFine have not yet been back-ported to any Minecraft versions prior to 1.16.5.
Data transfer between stages using
varyings can transfer data from a vertex stage to its associated fragment stage. A
varying is a single value that gets interpolated between all vertexes that it's part of. For example, say you have a triangle which outputs a
varying for "color". The first vertex outputs red, the second outputs green, and the third one outputs blue. A fragment in the middle of that triangle would read a gray-ish color. A fragment halfway between the red vertex and the green vertex (on the edge of the triangle) would read a dark yellow-ish color. You can change or disable this interpolation behavior by using interpolation qualifiers.