Week 3, oblique

This is an edition of Robin Sloan’s video game development diary.

Welcome: to returning readers as well as everyone newly subscribed. If you missed it, week 1 sets up the motivation behind this project. All the previous editions are available over on my blog.

The wonky k in the headine at the top of the page doesn’t seem so wonky anymore. Maybe we’re getting a little wonky, too.


Wot I got

This week’s work produced


Oblique strategy, part 1

Here’s one of my key references for the look of the map in Perils of the Overworld—and the game’s whole visual approach, really:

Oblique Drawing by Massimo Scolari

That’s Oblique Drawing: A History of Anti-Perspective (!) by Massimo Scolari, which I picked up many years ago because, no kidding, I thought I might someday do a project like this! And here we are. I’m glad I kept it around.

It’s an odd book—academic verging on abstruse—and, in truth, I can’t follow all of it, but I love Scolari’s introduction to the history of oblique “anti”-perspective and its uses in architecture and war—a way of drawing that does not distort scale, and can therefore serve as a practical reference, a source of truth, a tool—and I love the illustrations he has assembled, pages upon pages of them:

Oblique Drawing illustration

Oblique Drawing, Massimo Scolari

This one, in particular, justified the book’s whole purchase price:

Oblique Drawing illustration

Louis Ange, Plan d'une campaigne avec une perspective cavaliére, France, 18th century

Is it just me, or are Louis Ange’s forests… a tiny bit Super Mario Brothers?

Note the terminology in the title of the illustration above: perspective cavaliére, cavalier’s perspective. Scolari quotes France’s sixteenth-century Superintendent of Fortresses (!):

No one should expect to see the method or rules of perspective in these works; mainly, because it is not part of a soldier’s profession to produce them, and secondly, because the foreshortening involved would remove too much from the plans, whereas the entirety of these works lies in such plans and outlines as shall be called “soldierly perspective.”


Oblique strategy, part 2

That’s all to establish that oblique perspective has been part of this project from the start. One of my first lines of code summons not a PerspectiveCamera() but an OrthographicCamera().

This week, I saw a link posted by John Oram, a.k.a. Burrito Justice, who is, among many other things, a great curator and celebrator of maps. This link led me to a USGS publication called The Atlas of Oblique Maps, published in 1988, available in its entirety online. (Be careful with that link: it points to a 250 megabyte PDF!)

This work is just unbelievably beautiful:

Atlas of Oblique Maps illustration

The Atlas of Oblique Maps

For me, the appeal of oblique perspective is that it makes even an epic assembly like Cape Blanco look as though it could fit in the palm of your hand; like a model, even a toy.

The work in The Atlas of Oblique Maps isn’t just beautiful, but deeply human: there is simply no ignoring the fact that a particular person drew these maps. I swear I can almost hear the scratch of the pen. The lines are sketchy, the renderings playful; they wouldn’t be out of place in a comic book:

Atlas of Oblique Maps illustration

The Atlas of Oblique Maps

Isn’t this just the absolute best?

Atlas of Oblique Maps illustration

The Atlas of Oblique Maps

This book sent me rushing to my computer, to the POTO code, to the map.

More about that in a moment. First, here is your weekly:


Sound snack

Several writing sessions this week began with me playing one of Jesse Solomon Clark’s draft compositions and sort of “synchronizing” with the scene it suggested, so I asked Jesse if he would write a few notes about it. Press play, then read on:

Creating music for a project early in its development is really a treat; there’s a rare freedom there to imagine textures and scenes that don’t yet, and might not ever, exist. This phase is truly research and development for me, but these music sketches are often just as useful to my collaborators as they develop the work.

For this piece, I created a little film sequence in my head gleaned from the few details Robin provided about this location:

Suddenly! We are in the middle of PORT FABRI, a bustling city of commerce. Things feel huge and new, full of possibility and danger, so: hard-edged percussive and plucked sounds, brash horn rips—all with an undercurrent of activity. Next, we encounter narrow streets and foreign tongues, so: short and hectic musical phrases using disparate instruments from different cultures that clash and argue. We pop out of an alley and arrive at the docks to witness a fleet of ghost ships as they disappear into the mist: cue the soaring and dreamy orchestral strings that will take us to other lands to further our quest!

Jesse is right about these sketches being useful to his collaborators, i.e., me, because, in a very real sense, this theme has been co-creating Port Fabri with me all week. Pretty cool.


Oblique strategy, part 3

Okay, so I saw those sketchy lines in The Atlas of Oblique Maps, and I wanted them for myself. What next?

The graphics framework I’m using for the map connects, through a few intermediate steps, to the GPU in your phone or laptop. The GPU (which stands for graphics processing unit, snooze) makes modern visual computing possible using One Weird Trick: rather than work its way through the pixels in order, one at a time, it draws many at once—whole swaths of the screen, blorped into place.

This strategy is breathtakingly efficient, but/and it raises a persistent question: how do you translate a qualitative aesthetic goal like

into a programmatic “recipe” that each pixel can follow simultaneously?

My instinct—maybe yours, too—is to say, “Let’s draw some nice sketchy lines on the hills; some will be short, others will be long…” but that’s the one thing we can’t do. There is no floating virtual pen. There are only individual pixels, and each one has to follow its own recipe, blind to its neighbors. It’s really very strange.

For a long time, I found the language of these recipes, which are called shaders, totally inscrutable; like, truly brick-wall difficult. This dialect of computer-ese just did not make sense to me. Then, last summer, in one of the more memorable learning breakthroughs of my recent life, it just… cracked open.

So, here is a zoomed-in section of the new map, which now takes inspiration from the sketchy lines in The Atlas of Oblique Maps:

Every pixel in the animation above is following the same recipe, all in lockstep. There’s a preamble in which the pixel is colored pale yellow, or blue, or shadowed by a mountain, but then, to determine whether it should turn inky black to form part of a sketchy line, each pixel asks:

  1. Does my position on the terrain line up with the spacing Robin wants for these sketch lines? If so:

  2. Is the terrain beneath me steep—i.e., is it pointing more “out” than “up”? If so:

  3. Wait! Does a semi-randomized noise value indicate I should be skipped, representing a broken part of the line? No? Phew. In that case:

  4. Turn inky black!

At each of those steps, there are many “knobs” you can twist to transform the appearance of the sketchy lines.

Maybe the lines should be longer, more continuous?

Maybe they shouldn’t be so orderly??

After getting the map to the point depicted above, I decided my excitement had sneakily morphed into procrastination. So, I’ll let it sit for a while now, and, in the next round of work, try to bring in some of the boldness of our lodestone, Evaline Ness’s map from week 1:

Map of Prydain by Evaline Ness

Map of Prydain by Evaline Ness

If you’re curious about the shader code that draws these lines, you can click or tap to reveal it here:

// SKETCH LINES

// this determines line spacing
float zFactor = 1.0 - abs(vNormal.z);
float fractFactor = max(ceil(zFactor * 3.0) * 16.0, 8.0);
// translation: "when the normal's z-component is larger,
// the lines are spaced more widely"

float combinedCoord = (vWorldPosition.x - vWorldPosition.y);
float f  = fract(combinedCoord / fractFactor);
float df = fwidth(combinedCoord / fractFactor);
float fs = smoothstep(df * 0.5, df * 1.0, f);

vec3 noiseFeed = vec3( vWorldPosition.x / 13.0,
                       vWorldPosition.y / 11.0,
                       vWorldPosition.z / 17.0 );

// this calls a perlin noise function swiped from the internet
float dashNoise = noise(noiseFeed);

// step cutoff value of 1.0 means solid lines
// step cutoff value of 0.0 means no lines
float stepCutoff = 1.0 - abs(vNormal.z * 1.8);
// the multiplier there is important aesthetically
// 2.0 produced very sparse lines

float dashNoiseStep = step(stepCutoff, dashNoise);
fs += dashNoiseStep;
fs = smoothstep(0.9, 1.0, fs);

outColor *= vec4(fs, fs, fs, 1.0);

The map is still a long way away from where it needs to be… but even now, it’s fun to toggle back to week 1 and remember the rather dank artifact we started with 😝


Chasing a ghost

Earlier this week, I wrote a blog post about a particular effect that I have often noticed, and admired, in film titles from the pre-digital era, which you can see here—the way the white logotype “detours” through blue as it fades into darkness:

I’m including a link here because there’s a good chance that some of what I learned about the effect will find its way into POTO.


For as much progress as I made this week, I still feel very behind, writing-wise, so

Wot I’ll do

is keep writing. I have some thoughts on ~worldbuilding~ that I began composing for this edition, but then soldierly perspective took over, so I’ll save it for next week.

From Oakland,

Robin

P.S. Most of The Atlas of Oblique Maps was drawn by a cartographer named Tau Rho Alpha, who turns out to be an interesting character. Clicking around, I found another USGS document he produced, this one in 1991. The PDF appears to be—get ready—

The HyperCard stack

What a beautiful, dizzying artifact.


This has been an edition of my video game development diary, sent by email every Sunday. You are hereby invited to subscribe: