GODOT SHADERS · LESSON 1

Pipeline and Your First Shader

A shader is really two functions: one turns a vertex into a screen position, the other turns a pixel (fragment) into a color. Thousands of them run at once, each with no idea what the others are doing. And with a single floor() we turn a smooth gradient into pixel art — quantization, the mathematical heart of this lesson.

01 / Pipeline

Pipeline — a pixel's point of view

A shader splits into two stages. The vertex stage moves a mesh's vertices to screen positions; the fragment stage fills in a color for each pixel on screen. Both are short functions that handle just one vertex or one pixel — but the GPU runs that function on thousands of pixels at once, each completely independent of the others.

So when you write a shader, think like this: "I am one pixel. I have no idea what color my neighbor is. All I can do is read my own coordinates and sample a texture." Hover over the grid below. Only that one pixel ever gets highlighted — every other one has already finished its own calculation using nothing but its own UV.

Hovered UV
Pixel coords (row, col)
Total pixels16 × 9 = 144

Each pixel computed its own color independently, using only its own UV. Hover to highlight just one with a violet outline — "known" and "unknown" pop up in a speech bubble. The other 143 pixels don't know this is happening; they already finished.

02 / Coordinate systems

Coordinate systems — relative to what?

A coordinate is just a value relative to an agreed-upon origin and axes. UV is a 0–1 coordinate glued to the mesh surface — move the object and the pattern moves with it. SCREEN_UV is a 0–1 coordinate glued to the screen — move the object and the pattern stays put. VERTEX is view space: coordinates with the camera as the origin.

ModeUV
Position(0.00, 0.00)
Rotation20°

In UV mode the gradient moves and rotates with the square — like a pattern printed on the object. In SCREEN_UV mode the gradient stays fixed to the screen, and the square is just a window sliding over it. SCREEN_UV is the seed of every post-processing effect (outlines included).

03 / Quantization

Quantization — the mathematical heart of pixel art

floor(x·n)/n — multiply, floor, divide back down. In plain words: force the resolution down. And one identity always holds: x = floor(x) + fract(x). floor gives you the stairs (integer part), fract gives you the sawtooth (fractional part) — add them back together and you always get the original value.

n (steps)6
Step count6
floor + fract≡ x (identity, zero error)

The two bands above are the original and its quantized result. The graph below is the decomposition — the stairs (cool) plus the sawtooth (warm) sum (solid gray line) lands exactly on the diagonal (violet, dashed). Raise n and the steps get finer, closer to the original.

04 / SubViewport

SubViewport pipeline — low-res render, then nearest upscale

The pipeline that actually makes 3D look like pixel art works like this: render the scene into a low-resolution SubViewport (say, 640×360), then upscale it by an integer factor with a Nearest filter to fill the screen. Upscale with Linear and the edges blur; with Nearest, every pixel stays a crisp square.

Internal resolution48 × 27
Scale
FilterNearest

Lower the internal resolution and the pixel blocks get bigger. Nearest gives you crisp pixel art; Linear gives you a blurry smear — same source, just a different way of scaling it up.

05 / Try it

Try it yourself

  1. 1
    Find the threshold — slide n up from 2 and watch for where the result starts to read as pixel art. There's no single right answer; just notice where it flips for you.
  2. 2
    Go a little deeper — on paper, sketch (floor(UV.y*4)/4) + fract(UV.y*4) and see why the color clamps to 1 toward the top band. Hint: divide the fract term by 4 too (fract(UV.y*4)/4) and the identity x = floor(x) + fract(x) rebuilds the original gradient exactly.