Procedural SDF Ornamentation for Unreal UI
An assortment of shapes using different render functions (gilt, fill, stroke)

An assortment of shapes using different render functions (gilt, fill, stroke)

An in-game menu where all shapes and ornaments are constructed via the library

An in-game menu where all shapes and ornaments are constructed via the library

An example of using the material function library to create a basic petal rosette

An example of using the material function library to create a basic petal rosette

Overlaying multiple guilloche patterns and driving their animation via Time

A small assortment of the primitive shapes in TritonOrnamentSDF.ush

A small assortment of the primitive shapes in TritonOrnamentSDF.ush

Procedural SDF Ornamentation for Unreal UI

A Belle Époque UI runs on ornament: filigree corners, Greek-key borders, laurel swags, gilt rules around every panel. The usual way to get that is to have someone draw a big folder of flourish and border textures, at every size and resolution you'll ever display them. I didn't want the folder. So the ornament in The Still Life isn't textures at all, it's math. Every flourish is a signed distance field evaluated live in the shader and drawn fresh at whatever size and DPI it happens to land on screen.

The reason that's worth doing is what a distance field gives you for free. It's razor sharp at any scale (the same corner-scroll function draws on a tiny button and on a full-screen frame, just evaluated at different sizes), it recolors and re-gilds without re-exporting anything, it animates if I want it to (borders can scroll, glows can breathe), and it costs almost nothing in memory. A whole screen's worth of trim is a handful of instructions instead of a stack of 4K PNGs.

The part I'm proudest of is how clean the contract stayed. Everything speaks one language: a shape function takes a coordinate and returns a signed distance, operators (union, subtract, smooth-union, onion, concentric) chain shapes into bigger shapes, and render functions (fill, stroke, glow, gilt) are terminal and turn that distance into pixels. That's the whole grammar. Because it composes, all the elaborate stuff, a Greek-key meander frame, a laurel border with a rosette at each corner, an acanthus filigree corner, is built out of the same dozen or so primitives, and adding a new motif never means touching anything underneath it.

It lives in two front-ends. There's the HLSL library for when I'm in code, and a mirrored set of material-editor functions so the exact same shapes, operators and render modes can be dragged together as nodes without writing a line. The genuinely fiddly problem was keeping it honest across sizes and DPI: the fields are authored in a normalized space, so a naive "two pixel" stroke would balloon or vanish as a widget resized. So there's a small set of helpers that read the field's own screen derivative and convert a fixed pixel size back into field units, which keeps a stroke width or a corner radius screen-constant no matter how large the widget gets or what DPI it's running at. The gilding does the opposite trick: it reads the SDF's gradient as a surface normal and lights it, so a flat gold fill picks up a soft beveled gold-leaf sheen from a faked light angle.

The motif set is deliberately period-correct rather than a generic shape pack: Greek-key frets, Vitruvian running waves, festoon swags, guilloché, multifoil gothic tracery, heraldic escutcheons and keyholes, the vocabulary a fin-de-siècle engraver would actually have reached for. Like a lot of this project it started as me being stubborn about not hand-authoring a hundred textures, and turned into one of my favorite systems in the whole thing.

More artwork