Versant: Skiing in the Alpine. (Procedural Terrain, Hand-Solved Kinematics, No Authored Animations)

I wanted to build the feeling of skiing in the alpine. Going fast downhill with the mountains unfolding in front of you.

I thought this would be quick, because I already had some of the core pieces:

  • infinite terrain with no LOD and no seams from Eternal Ride, and
  • procedural rocks that turned out to be exactly the right machinery for snow chunks and ice blocks.

I thought to myself: “Drop a skier on the terrain, point him downhill, done by the weekend”.
But then I put a skier on it and it felt like… nothing :slight_smile:

The problem is that skis are long. A foot is basically a point; sample the ground under it and you’re finished. But a ski is nearly two meters of rigid plank lying across terrain that undulates underneath it, touching in only a few places. Get it wrong and the tips knife into the snow or the tails hover in mid-air, and either one tells your eye instantly that this is a toy.
So each ski is sampled along its length, seated on the highest contact, and pitched to what’s actually under it. And the leg above it has to solve backwards from wherever the foot ended up. Closed-form, one law of cosines per leg, per frame.

Poles made it worse. A pole is a stick your hand holds at one end and the snow catches at the other, and the two facts fight constantly. None of this fits canned animation clips, so I went down the kinematics rabbit hole and stayed there for too many weeks. Point uphill and stop, and it switches to a herringbone climb: tips splayed, poles planting behind, chevrons stamped into the snow alongside your carve tracks.

You get: a snowplow that flips through parallel as you cross the fall line, a hop with real flight and landing absorption, free-look, and a scroll that dollies the camera all the way down onto the skier’s head into first person. Touch mode has dual controls. The slope grade drifts through slow noise rather than sitting at a constant pitch, so the run breathes between mellow and steep, and the spawn scatters every load: you never start on the same patch of mountain twice.

Sound does about half the work of selling it, and I’m generating all of it. Wind is filtered noise that opens up with speed. The carve is a resonant band driven by how hard the edge is actually biting, not by how hard you’re pushing the stick, so it sings when you’re railing a turn and stays quiet when you’re just steering. Boot crunches, pole plants, the whump of clipping a tree: all synthesized.

Shadows turned into their own rabbit hole. The shadow map is fitted tight to the skier and holds only the skier (nothing static casts into it) so every tree and rock has its shadow drawn on the snow instead. Trees are billboards, a card bowed into a shallow cylinder with the texture painted into a canvas at load, and because a conifer is rotationally symmetric about its trunk one silhouette serves from every azimuth. Rocks were harder, because they’re irregular and randomly tumbled, and I spent a long time building increasingly elaborate machinery before noticing the obvious: the rock’s collision proxy is an ellipsoid, and an ellipsoid lit by a directional light casts exactly an ellipse. So the shadow is one conic solved in closed form (three dot products and a 2×2 inverse) with the rotation entering once, in the axis basis, and only the part of the rock standing above the snow doing the casting. Four multiply-adds in the fragment shader, no texture, no second depth pass.

There are no game elements. No score, no gates, no timer. I’m just very happy with the feeling of going fast downhill.

Performance is over the top for a showcase demo. I spent far too long on it for something with no win condition… But I take a lot of pride in the engineering of the engine itself.

Physics substeps so the sim is honest at any frame rate, and collision is swept, not sampled. No chance of tunneling no matter how fast you go and no matter your framerate.

Single file. Two CC-BY character assets (the skier, and the skis and poles extracted from a second model); the mountain, trees, rocks, snow, sky and sound are all generated.

CodePen | GitHub Pages | Source

Hope you enjoy!

4 Likes

A work of art!

2 Likes