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.
This is the story of what happened in between.
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. Not skimming — actually reading, trying every function, 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 — Mystify-style bouncing curves — because I'd been unsatisfied with the fireworks screensaver from years earlier. I was redeeming myself.
All of this was pure C, pure math, learning by doing. No internet, no Stack Overflow, no tutorials — just 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 locally 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. It seemed like the obvious thing to do — there was knowledge I wanted and a place I could get it. Those courses gave me classes, inheritance, and object-oriented design patterns at exactly 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. No game mechanics, no story. Just: what can you make a computer do, right now, faster and better than anyone else?
This was exactly what I'd been looking for my whole life.
I started downloading tutorials — specifically tutorials 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 directly 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 — essentially image-based lighting before that term existed
- A bump map renderer with dynamic erosion, where a heightfield was continuously modified 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 significantly faster — I optimized until I'd extracted roughly 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. That's a high conversion rate from "people I met at a demoparty in Montreal."
The demo scene had a self-selection mechanism I haven't seen replicated elsewhere. To participate, you had to actually 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 — tutorials written by people who had actually solved the problems, shared freely 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. Fixed-point math, hand-written assembly kernels, software rasterizers, X-Mode tricks — none of it mattered anymore. The GPU did all of it, faster, in hardware.
I watched this happen in real time, and I noticed something: not all of my knowledge expired. The matrix math was still valid. The theory of lighting — how normals relate to reflected light, how perspective projection works, what makes a texture map look correct — all of that transferred directly to working with hardware accelerators. What expired was the tactical layer: the specific optimizations you make to realize that theory on this hardware, right now.
That distinction — between evergreen theoretical knowledge and time-limited tactical knowledge — has shaped how I think about learning ever since. The theory is worth investing in heavily. The tactics are worth knowing, but with the understanding that they have an expiry date.
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 entirely 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 fully 3D engine — the first in the series. The development cycle was four years long, and it's hard to trace exactly which decisions from those early prototypes persisted to the final product. But the foundational direction — that the game would be 3D, and roughly how — was established during that R&D period.
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, a benchmark that had been used to test renderers since the 1970s.
One thing I worked out that I was particularly pleased with: computing surface normals analytically using 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 directly 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 independently felt like something.
The source code is on GitHub, including the original 1997 README — complete with IRC shoutouts.
What I Took Away#
By the time I finished high school I had 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.
None of it came from school, except a Pascal course where I wrote a Missile Command clone. All of it came from reading manuals, following curiosity, finding communities of people who were better than me, and being proactive about closing my own gaps.
The recursive lesson: the most important thing I learned wasn't any specific technique. It was that you can teach yourself almost anything if you find the right resources and take the problem seriously. That turned out to generalize.
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