Adventures with the OpenGL shader pipeline
For the past several weeks, I've been learning "modern" OpenGL programming practices, by which I mean using a GLSL shader pipeline with vertex and fragment shaders.
Even before starting Ambienome, I was already somewhat familiar with the old OpenGL "fixed function pipeline", using glBegin/glEnd, glColor, glVertex, etc. Ambienome is going to be visually simple enough that I probably could have used the fixed function pipeline, but I decided to learn the shader pipeline to improve my knowledge and skills, to allow nicer visual effects, and to leverage the GPU's number-crunching power as much as I can.
Grokking the shader pipeline was a challenge. There are many separate concepts to learn, and then you must understand how they fit together. Also, there are fewer learning resources for the shader pipeline than there are for the older fixed function pipeline. I relied mostly on Joe Groff's "An intro to modern OpenGL" article series, but if I were doing it over again, I might try to find a good book. Unfortunately, the selection is somewhat thin. I'm considering OpenGL Shading Language (the so-called "Orange Book") or the OpenGL ES 2.0 Programming Guide. (OpenGL ES 2.0 is conceptually very similar to the OpenGL shader pipeline, and also very similar to WebGL.) Unfortunately, the reviews suggest those two are not very well written, organized, or proofread. Real-Time Rendering looks like it might provide a good high-level understanding of shaders and rendering, but it's not specific to OpenGL or GLSL, and I'm not really interested in advanced photorealistic shader effects. Maybe if there are any book stores still open in this town, I'll see if any of these books are on the shelf so I can assess them before I buy.
Anyway, even after I had scraped together a modest understanding of the concepts behind the shader pipeline, applying that knowledge in practice took longer than I anticipated. It was fairly frustrating at times, partly due to some (minor) shortcomings of cl-opengl and lispbuilder-sdl, and partly due to me misinterpreting some vague parts of the OpenGL documentation. There were many times when I felt like putting the shader pipeline aside, and just using the fixed function pipeline for a while, so I could keep my momentum up. But I stubbornly stuck with it, and now I've got a working, reusable rendering framework built atop the shader pipeline. Huzzah!
My next task is to write code to algorithmically generate mesh data for several geometric primitives. Yesterday, I finished the code for a rectangle mesh built from triangle strips (well, actually one long strip with degenerate triangles connecting each row). Here's a screenshot of a 10×10 rectangle mesh rendered in wireframe mode:
It's not much to look at in itself. I could have achieved that in an afternoon using the fixed function pipeline! But that humble mesh, rendered here using the simplest possible vertex and fragment shaders, represents weeks of learning. Now that I have the basics working, I can write more interesting shaders to morph the shape and create cool visual effects. For example, Ambienome takes place underwater, so I'll probably write a shader to make things sway and ripple as if they were being affected by a water current.
Next, I'll be writing the code for a triangle mesh, and then a circle mesh. I have plans for more shapes, like teardrop, leaf, ring (circle with a hole in the middle), and tentacle (a Bézier curve with thickness controlled by another Bézier curve). But, I'm going to save those for later. Once I've got rectangle, triangle, and circle, I'm going to take a step back from the low-level foundation for a while, and start fleshing out higher-level concepts like components, creatures, and scenes.