← All Work Brian Lee.

Graphics/3DMar–Apr 2026

Passenger

A cinematic Unreal Engine 5 short: a canyon, a train swallowed by roots, and hand-written painterly shaders that make real-time frames feel oil-painted.

Overview

Passenger crosses a canyon of sandstone walls scorched by a sun that has done this ten million times before. At the canyon's edge he finds a train, stopped long enough ago that birch trees have grown up through the floor, vines have claimed the grab rails, and wildflowers cover what was once the aisle. Inside, an apple — still quiet. He picks it up, and the world opens somewhere else.

Built entirely in Unreal Engine 5, with character rigging and animation from Maya. The two environments, a sun-scorched Utah canyon and an overgrown subway car, share one lighting approach: real-time global illumination grounds each scene in believable light before the stylized shaders go on top.

Scene 01 · Canyon

Building a Utah canyon in Unreal Engine 5

The canyon is assembled from Megascans photogrammetry (high-resolution rock faces and desert scatter), arranged to feel like it had always been there: no obvious tiling, no floating rocks, a sense of geological weight.

Lumen global illumination handles the bounce that wraps into the walls from the sun angle. As the virtual sun nears the horizon, Lumen re-solves the GI in real time: deep amber shadow on one side, burnt orange on the lit face. No baking, no lightmaps; the lighting reacts as the camera moves.

Lighting studies

Canyon at golden hour
Golden hour · warm directional light, Lumen pulling amber deep into the walls
Canyon at blue hour
Blue hour · sun below the horizon, cool skylight fills the scene

Scene 02 · The train

A subway car swallowed by a decade of growth

The train is built on a modular NYC-style kit (car shells, doors, ceiling marquees, grab rails), then stripped of every sign of function. Birch trees push through the floor, hornbeam foliage fills the door frames, meadow grass covers the aisle, vines loop the rails. The LED marquee still cycles “DELAYS AHEAD” — but there are no delays, because there is no train anymore.

All of the interior light comes from the sky through the broken canopy above. Lumen computes the soft, diffuse fill of overcast light filtering through leaves, with thin god rays catching mist scattered through the volume.

The train

Overgrown subway car — marquee
The LED marquee still cycles “DELAYS AHEAD”
Overgrown subway car — foliage
Foliage overtaking the abandoned car

Shaders

Hand-written post-process for a painterly look

The signature look is a custom anisotropic Kuwahara line shader: a Sobel operator detects the local edge gradient and its direction, which rotates four sampling quadrants to align with surface features. Each quadrant's mean and variance are computed, and the mean of the lowest-variance quadrant is returned, so flat areas resolve into coherent oil-paint patches while edges stay sharp. It's parameterised by brush radius, painterliness, and line thickness.

A second toon/cell pass samples BaseColor from the GBuffer and quantises the scene into tonal bands with separate shadow/highlight tints. Both materials read real GBuffer channels (BaseColor, WorldNormal, SceneDepth) through SceneTexture nodes, so the stylisation responds to actual geometry, not just the final pixel.

Cell shader · off / on

Canyon 1 — cell shader off
Cell shader off · canyon 1
Canyon 2 — cell shader off
Cell shader off · canyon 2
Train 1 — cell shader off
Cell shader off · train 1
Train 2 — cell shader off
Cell shader off · train 2
Canyon 1 — cell shader on
Cell shader on · canyon 1
Canyon 2 — cell shader on
Cell shader on · canyon 2
Train 1 — cell shader on
Cell shader on · train 1
Train 2 — cell shader on
Cell shader on · train 2

Technical breakdown

GBuffer passes: what the renderer sees

Unreal's Movie Render Pipeline can output individual GBuffer passes alongside the final composite, showing how the deferred renderer decomposes the scene before lighting. I used them to validate material authoring and debug the post-process shaders.

GBuffer

BaseColor pass
BaseColor · flat albedo
Roughness pass
Roughness · PBR channel
SceneDepth pass
SceneDepth · linear depth
WorldNormal pass
WorldNormal · encoded normals
Metallic pass
Metallic · PBR channel
Pre-tonemap HDR
Pre-tonemap HDR · before exposure

Maya pipeline

The stylised low-poly passenger was modelled, rigged, textured, and animated in Maya. The rig uses IK limb chains, a spline-IK spine, and foot orient constraints, driven by NURBS control curves. Core cycles (idle, walk, jump, sit, push-up, pickup) export as FBX clips into an Unreal Animation Blueprint that blends between them with a locomotion blend space and procedural secondary motion.

Character

Character rendered in the canyon
The stylised passenger rendered in-engine with Lumen GI

Maya rig

Maya rig — front
Front · joint hierarchy & control curves
Maya rig — side
Side · IK leg chain & foot constraints
Maya rig — top
Top · shoulder & arm control layout

Render

The film renders through Unreal's Movie Render Pipeline rather than a viewport capture. Temporal Super Resolution accumulated over 64 samples per frame kills real-time shimmer, output at 2560×1080 (2.4:1) to push the eye wide, with hardware ray tracing for reflections and shadows over Lumen GI.

Reflection

Writing the shaders by hand, rather than reaching for a plugin, is what made the look feel like mine, and reading the GBuffer directly taught me more about the deferred pipeline than any tutorial. The lesson that stuck: a real-time engine gives you a filmmaker's iteration speed, but only if you understand what it's actually computing each frame.

Outcome

2560×1080render resolution
64TSR samples / frame
2custom HLSL shaders