How I Learned 3D Graphics in a Basement in Ottawa
How I went from Apple IIe two-liners to C, x86 assembly, the demo scene, 3D engine prototypes, and a high school internship building technology for Wizardry 8.
Ben Houston • June 16, 2025 • 8 min read
In the previous post, I wrote about my first computer graphics program on an Apple IIe: a fireworks screensaver, two lines of code, published in Nibble magazine after I won their monthly one- and two-liner contest in June 1990. By the time I was eighteen I was working with a team of five developers and artists at a professional game studio, prototyping 3D engines that would form the basis of Wizardry 8.
Learning C on a 486 (1991-1993)#
In 1991, my dad bought a PC clone: an Intel 486 DX2/50 with a 300 MB hard drive and copies of Turbo Pascal and Microsoft C. I was twelve or thirteen. I read the manuals front to back, trying every function and figuring out what each one did. I learned how to initialize graphics mode, which gave me 16 colours at high resolution. That was enough.
I wrote a windowing system from scratch. I wrote an oscilloscope synthesizer where you could control Lissajous figures in real time with overlapping windows and live updates. I wrote a more ambitious screensaver with Mystify-style bouncing curves because I'd been unsatisfied with the fireworks screensaver from years earlier and wanted another shot at it.
All of this was pure C, pure math, learning by doing. I had the manuals, the compiler, and trial and error.
Algonquin College, Grades 10 and 11 (1994-1995)#
There was no C++ at my high school. In grade ten I looked up what was available in town and found that Algonquin College offered evening courses. I enrolled in Introduction to C++, attended twice a week for a term, and passed. Then I came back the following year and took Object-Oriented Design and Analysis.
I was fifteen and sixteen, taking college courses in the evenings to learn things my school couldn't teach me. I wanted that knowledge, and Algonquin had a place I could get it. Those courses gave me classes, inheritance, and object-oriented design patterns at the point I needed them. Within a year I was applying them in production code.
The Demo Scene (1995-1996)#
Around 1995 I got online for the first time, and I discovered the demo scene.
The demo scene is a subculture of programmers, artists, and musicians who compete to make real-time audiovisual demonstrations, "demos," that push hardware to its absolute limits. The whole form is the technical flex: make the computer do something faster, stranger, or more beautiful than anyone expected.
That culture matched the way I already wanted to learn.
I started downloading tutorials, with a focus on X-Mode, a special VGA graphics mode that allowed page flipping and gave you 256 colours instead of 16. I learned inline x86 assembly and started embedding it in my C code to control the graphics card, perform fast memory copies, and implement pixel shading kernels. The floating point unit on a 486 was too slow for real-time work, so everything had to use fixed-point arithmetic: 16-bit integers, multiply, shift, repeat.
Over 1995 and 1996 I built:
- A real-time texture mapper with perspective correction
- A reflection mapper using environment maps modulated with surface textures, an early form of image-based lighting before that term existed
- A bump map renderer with dynamic erosion, where a heightfield changed in real time while lighting was calculated on top of it
- A palette quantization system that pre-computed all possible colours given a set of input textures and lighting conditions, quantized them to 256 entries, and used lookup tables at runtime to render directly into the quantized palette
All of this ran at 30-40 frames per second, full screen, on a 486.
The bump map demo went through several versions. The first was clean and readable. Each subsequent version was less legible but much faster. I optimized until I'd extracted about a 10x speedup from the original code. I learned more about performance from that iterative process than from anything else I did in those years.
The source code for these demos is on GitHub and here.
The Scene as a Network#
In 1996 I competed at NAID (North American International Demoparty) in Montreal with a group of friends I'd met online through the scene. We put together a demo at the compo, a rushed collaborative thing assembled on-site, but the connections lasted far longer than the code.
Olivier Dagenais, who was in my demo group, is the godparent to my first child. Stefan Xenos, who I met through Olivier at that event, later became a semi co-founder of Exocortex and wrote significant portions of the fluid simulator at the core of our VFX tools. A demoparty in Montreal gave me friendships and collaborators that lasted for decades.
The demo scene had a self-selection mechanism I haven't seen replicated elsewhere. To participate, you had to make something real. The community was honest about quality. And because everyone was working at the edge of what was possible, the knowledge transfer was dense and fast. People who had solved the problems wrote tutorials and shared them because the culture valued it.
Learning the Right Lessons#
Something important happened when 3D graphics accelerator cards arrived in the mid-1990s.
Overnight, everything I'd spent years learning became obsolete. The GPU handled fixed-point math, hand-written assembly kernels, software rasterizers, and X-Mode tricks faster in hardware.
I watched this happen in real time, and not all of my knowledge expired. The matrix math was still valid. The theory of lighting transferred directly: how normals relate to reflected light, how perspective projection works, what makes a texture map look correct. The tactical layer expired: the specific optimizations you make to realize that theory on this hardware, right now.
Sir-Tech Canada, Fall 1996 - Spring 1997#
In grade twelve, I saw a job posting for a local games company called Sir-Tech Canada, the studio behind the Wizardry series of RPGs. They were looking for a 3D engine developer. I was seventeen.
I applied. I got the job. I arranged with my school to drop some courses so I could work half-days: early mornings at Sir-Tech, afternoons at school.
My mandate was to introduce the company to 3D development. The Wizardry series had been 2D up to that point. Working with a team of five developers and artists, we prototyped a series of 3D engines to explore what the next entry in the series could look like. The technical problems we were solving:
- Asset pipeline: loading 3DS MAX models (we used a beta of 3DS MAX) into Direct3D. The standard exporter baked animations to keyframes, which was lossy. We also explored loading native
.3DSfiles directly to get animation curves, a better approach that preserved animator intent and kept file sizes manageable. - Lighting models: we compared real-time Direct3D lights, pre-baked lightmaps, and environment-map-based shading where texture maps representing the environment were modulated with surface textures, the same technique I'd developed in the reflection and bump map demos.
- Multiple prototype engines exploring different tradeoffs across these dimensions.
I was there from Fall 1996 through Spring 1997. Wizardry 8 shipped in 2001 with a 3D engine, the first in the series. The development cycle was four years long, and it's hard to trace which decisions from those early prototypes persisted to the final product. But the team established the foundational direction during that R&D period: the game would be 3D, and we had a rough idea of how.
A Focus on the Foundations (Summer 1997)#
After the internship I got my hands on a book I'd been wanting: Advanced Animation and Rendering Techniques by Alan Watt and Mark Watt. I'd heard about it from the scene, and it was everything it was supposed to be: rigorous, mathematical, full of code examples.
I translated those examples into C and went further. I implemented Bezier curves and Bezier patch surfaces from scratch, then used them to render the Utah Teapot, the standard test model of 3D graphics and a benchmark used to test renderers since the 1970s.
One thing I worked out that I was proud of: computing surface normals from a derivative matrix. Rather than approximating normals by finite differences, I derived a matrix that, when applied in place of the standard basis matrix, gives you the tangent vector from calculus. I put a note in the README asking whether anyone had seen this technique before. It was a known idea, but arriving at it on my own felt like something.
The source code is on GitHub, including the original 1997 README with IRC shoutouts.
Finishing High School#
I finished high school having taught myself C, Pascal, C++, x86 assembly, 3D mathematics, real-time rendering, asset pipelines, and object-oriented design. I had published work in a national magazine, competed at an international demoparty, taken college courses while still in high school, and worked as a developer at a professional game studio.
School gave me one useful Pascal course, where I wrote a Missile Command clone. The rest came from reading manuals, following curiosity, finding communities of people who were better than me, and closing my own gaps.
The source code from this era is archived on GitHub:
- 2DBumpMapDemo1996: Real-time bump mapping with erosion, inline x86 assembly
- 3DMaskDemo1997: Phong texture bump and reflection mapping with palette quantization
- BezierCurveDemo1997: Utah Teapot and Mystify screensaver, post-Sir-Tech