Graphics Programming: The Zero-Jargon Intro I Wish I Had
I've read a lot of dense graphics tutorials. This is something else, I promise.
How bad could it possibly be?
I once opened a Vulkan tutorial. Sixteen pages later, I had rendered… a triangle. One. Triangle.
That’s Vulkan being Vulkan, sure. But the truth is most graphics tutorials feel like reading IKEA instructions written by someone who’s never assembled furniture.
Why so dense?
Look, there ARE good learning resources out there. But graphics programming sits at this weird intersection of C++, linear algebra, and hardware architecture. Most tutorial writers are experts who’ve forgotten what it’s like to see “glVertexAttribPointer” for the first time and think “what fresh hell is this?”
What do I assume you know?
Let’s be real: you’ll need some 3D math eventually. But not today. We’ll build up to it. For now, if you know what a vector and a matrix are and you can write a for loop in C++, you’re good.
Graphics specific jargon? I’ll define it as we go. Promise.
The Graphics Pipeline: A Mental Model
We live in a 3d world, but screens are 2 dimensional. Most of your video games are 3d as well. Imagine a simple 3d scene with just a cube. The central problem in graphics is: How do we take that representation of the object and color the pixels on the screen to make it look convincing?
Let’s simplify it even further. How do we take an object and show any representation in pixels on the screen? Enter the Graphics Pipeline.
Think back to the cube scene. Our cube can be broken down into even smaller pieces. Every cube is 6 squares, right? What about even smaller? The simplest polygon is a triangle, and that’s exactly what we want. Any object can be broken down into a collection of triangles. The square sides of a cube are in reality just 2 triangles. Triangles are guaranteed to be flat (three points always define a plane), which makes math wayyyyy simpler.
Back to the pipeline. “Pipeline” is a pretty damn good name for it. The series of steps happen sequentially, in a specific order. On one end of the pipe, you feed in raw data (the position of cube, the color, if its shiny or rough, etc). The other side of the pipe gives you an image on screen.
We will talk about the stages in detail later, but for now here are the relevant pieces.
Vertex Processing → Rasterization → Fragment/Pixel Processing
- Vertex Processing figures out where on the screen the triangles that make up the object belong.
- Rasterization figures out which pixels are inside which triangle.
- Fragment processing figures out what the final color of each pixel should be.
(Yes, modern GPUs have more stages than this. We’re ignoring them for now. You’re welcome.)
Oops, did I say GPU?
The last topic I want to cover is an easy introduction to some hardware. When you’re writing code, it’s executing sequentially on the CPU. The CPU is really good at doing 1 task at a time, and you get a lot of flexibility in what those tasks can be.
GPUs, on the other hand, are super specialized pieces of hardware. They are specifically made to do tasks in parallel. Think about it: to render one frame, you might need to color 2 million pixels. The CPU would have to color them one at a time. The GPU can color thousands of them simultaneously.
Awesome! Why don’t we use a GPU for everything, then? Because you are extremely limited in the kinds of operations you’re allowed to do. GPUs are really good at performing the same operation on different sets of data - perfect for graphics, not so great for, say, parsing JSON
What’s next?
Diving into Vertex Processing!
For now, just remember: triangles go in, pixels come out. Everything else is details.