A Maya to Unreal cinematic shot pipeline.
An artist animates cameras and characters in Maya. One click exports them. One click in Unreal builds the Level Sequence: the cine cameras with the correct lens and filmback, the Camera Cut Track, the skeletal animation, the playback range and the frame rate.
Name and usecase inspired by Guild Wars 2 vistas: the camera leaves the player, moves across the scenery, and returns.
Unreal's FBX import can put a camera's animation onto a camera that already sits in a Level Sequence. It cannot build the structure around it. For every shot, somebody creates the CineCameraActor, binds it, imports onto the binding, and places the camera cuts, by hand.
The lens needs care too. The Sequencer FBX import writes the FBX film back and focal length onto the camera's spawnable template, not onto the camera in the viewport. It also writes Maya's default focus distance of 5 cm. So right after an import, the viewport shows Unreal's default sensor, which is 16.9 degrees too narrow for a 36 x 24 mm Maya camera, and a respawned camera is out of focus.
vista builds the structure, and it sets the lens from its own manifest after the import, on the live camera and on the template. The result does not depend on importer details.
flowchart LR
A[Maya scene] -->|scene_export| B[One FBX per camera<br/>One FBX per character]
A -->|scene_export| C[manifest.json]
B --> D[build_sequence]
C --> D
D --> E[Level Sequence<br/>cameras, lens, cuts,<br/>characters, range, fps]
- FBX carries the animation: camera transforms, focal length, skeletons, meshes.
- The manifest carries the structure: the scene range and frame rate, the shot list, the lens values in millimetres, the character list.
corereads and writes the manifest, decides the cut list, and runs the validation rules. It imports neithermayanorunreal, so it runs and tests in plain Python.
vista/
core/ manifest format, cut list, validation rules, last export (plain Python)
maya_tools/ scene export, FBX settings, dockable window (Maya)
unreal_tools/ sequence builder, Vista menu, panel functions (Unreal)
content/ EUW_Vista.uasset, the Vista panel
examples/ demo scene builder, headless batch export
tests/ pytest tests for core
install_maya.py drag into the Maya viewport to install
init_unreal.py adds the Vista menu when Unreal starts
- Multiple shots. Every keyed camera becomes a shot. Each shot gets its own spawnable CineCamera and a cut on the Camera Cut Track.
- Camera cut placement. A cut starts where its camera's keys start and holds until the next shot starts. The first cut starts at the scene start, the last holds to the scene end. No frame is left without a camera.
- Lens and filmback. Focal length, sensor size (converted from Maya's inches),
and the depth of field switch. Values are rounded, so a 36 x 24 mm Maya camera matches
Unreal's
Full Frame DSLRpreset. - Skeletal animation. Every skinned character in the scene exports with its baked animation and lands in the sequence on a Skeletal Animation Track.
- Frame rate and playback range. The sequence gets Maya's frame rate, including NTSC rates such as 23.976 (stored as 24000/1001), and Maya's playback range, last frame included.
- Validation. Rules check the manifest before any file is written. Errors stop the export with warnings explaining why.
- Rebuild. A second build clears and reuses the same sequence, so a level that plays it keeps its link.
- Restored editor state. The Maya selection is restored after export. The Unreal Interchange FBX setting is restored after the build.
- Last export. Maya records each export. In Unreal, Build Last Export needs no path.
- Setup. A drag-and-drop installer and a shelf button in Maya, a Vista menu in Unreal.
- Maya window. Dockable, PySide6, with a PySide2 fallback.
- Batch export. Headless with
mayapy, with exit codes for a build machine.
| Tool | Version | Notes |
|---|---|---|
| Maya | 2026 | Tested. Older versions with PySide2 should work through the fallback, untested |
| Unreal Engine | 5.5 | Tested. Plugins: Python Editor Script Plugin, Editor Scripting Utilities |
| Python | 3.11 | Only for running the tests outside Maya and Unreal |
Clone the repository anywhere.
Maya. Drag install_maya.py from the repository into the Maya viewport. It adds the
repository to Maya's Python path in userSetup.py, and puts a Vista button on the current
shelf.
Unreal.
- Open Edit > Project Settings > Plugins > Python > Additional Paths, and add the repository folder.
- Copy
unreal_tools/content/EUW_Vista.uassetinto your project'sContent/Vista/folder. The asset needs Unreal Engine 5.5 or later. - Restart the editor. The main menu bar now has a Vista menu.
Tests (optional).
py -3.11 -m pip install -r requirements.txt
py -3.11 -m pytest
Press the Vista shelf button.
| Control | Effect |
|---|---|
| Cameras, Characters | Tick what to export. Cameras without keys start unticked |
| Output folder, Browse | Where the FBX files and manifest.json go |
| Open the folder after export | Opens the output folder when the export is done |
| Check | Runs every rule. Writes nothing |
| Export | Runs every rule, then writes one FBX per camera and per character, and manifest.json |
Every export also records its manifest as the last export, so Unreal can find it without a path.
Without the window:
from maya_tools import scene_export
manifest_path, issues = scene_export.export_scene("C:/vista_out")Headless, from a command prompt:
mayapy examples/batch_export.py C:/vista_out path/to/scene.ma
Quick path: Vista > Build Last Export builds the manifest Maya wrote last.
Panel: Vista > Open Panel.
| Control | Effect |
|---|---|
| Browse | Pick a manifest file |
| Last Export | Fill in the manifest Maya wrote last |
| Lock viewport to camera cuts | After the build, the viewport shows the shot through the cameras |
| Check | Runs every rule. Builds nothing |
| Build | Builds /Game/Vista/LS_<scene name> and opens it in Sequencer |
The status line under the buttons shows the result. For details, type Vista in the Output Log
search field.
From Python:
from unreal_tools import build_sequence; build_sequence.build_from_manifest(r"C:/vista_out/manifest.json")examples/build_demo_scene.py builds a test scene: a small set, two keyed cameras
with different lenses and sensors, one camera with no keys (the export skips it and says so),
and optionally a Mixamo character with one or two animation clips. With two clips, the first
plays in shot A, and the second starts exactly at the cut to shot B.
The Mixamo files are not in this repository. Download them from mixamo.com: one character as FBX Binary, With Skin, and one or two animations as FBX Binary, Without Skin, 30 fps. A moving clip suits the wide shot A, and an in-place clip suits the close-up B.
mayapy examples/batch_export.py C:/vista_out --demo path/to/character.fbx path/to/first_clip.fbx path/to/second_clip.fbx
This builds the scene, saves it as C:/vista_out/vista_demo.ma, and exports it.
Every path is relative to the manifest file, so the output folder can move as a unit.
{
"version": 4,
"scene": { "name": "vista_demo", "frame_start": 1, "frame_end": 120, "fps": 30.0 },
"shots": [
{
"name": "shotCam_A",
"fbx_path": "shotCam_A.fbx",
"frame_start": 1,
"frame_end": 60,
"focal_length": 28.0,
"sensor_width_mm": 36.0,
"sensor_height_mm": 24.0,
"depth_of_field": false
}
],
"characters": [
{ "name": "Ch36", "fbx_path": "Ch36.fbx", "frame_start": 1, "frame_end": 120 }
]
}| Field | Meaning |
|---|---|
scene.frame_start, frame_end |
Maya's playback range. Every FBX is baked over it. The sequence plays it, both ends included |
scene.fps |
Maya's frame rate |
shots[].frame_start, frame_end |
The first and last key of that camera. The cut list is built from these |
focal_length |
Millimetres, at the shot's first frame. The FBX carries the animation |
sensor_width_mm, sensor_height_mm |
Maya's film aperture, converted from inches, 3 decimals |
depth_of_field |
Maya's depth of field switch. Off disables depth of field in Unreal |
characters[] |
One skinned character each. Its FBX holds mesh, skeleton and animation |
| Rule | Level |
|---|---|
| The export has no keyed camera | error |
| Two items export to the same FBX file name, for example `grp | camandgrp:cam` |
| A camera has no keys (it is skipped) | warning |
| A shot has keys outside the scene range | warning |
| A shot starts before the previous shot ends | warning |
| An FBX file named in the manifest is missing (checked in Unreal) | error |
| A shot's sensor matches, or does not match, an Unreal filmback preset | info |
Errors stop the export before any file is written. Messages name the camera and the frames, and say what to do.
corehas no application imports. The manifest format, the cut rule and the validation rules are plain Python. They are tested quick, and every front end (the Maya window, the batch script, Unreal) shares them.- Check first, then write. The export collects everything and runs the rules before it writes the first file. A failed export doesn't leave half-written files.
- Manifest dictates lens. The builder sets the lens after the FBX import, so importer behaviour cannot change the result.
- Depth of field switch, not focus distance. Maya's default focus distance is 5 cm, and Maya ignores it while depth of field is off. The manifest stores the switch. With the switch off, Unreal disables depth of field.
- Plain key curves stay curves. The FBX export bakes complex animation (constraints, expressions) but does not resample hand-keyed curves, so the curves stay editable in Unreal.
- Logic in Python, not in the widget. The Editor Utility Widget runs one line per button. Everything else is text in git.
- No cut to black. The cut rule always holds the previous camera until the next shot.
- Characters need a skinCluster. A rigid character built from parented pieces is not found.
- One Level Sequence per manifest. There is no Cinematic Shot Track with one sub-sequence per shot yet.
- Key ranges are whole frames.
- Non-default Maya rotate orders are untested.
- The camera import uses Unreal's legacy FBX importer. The builder switches Interchange off for the duration of the build and restores it after.
- CameraLink transfers an animated camera from Maya to Unreal with USD, and creates a Level Sequence with the camera, the frame range and the frame rate. vista works with FBX and a manifest, builds a whole shot list with a Camera Cut Track, and brings characters into the same sequence.
- mayafbx wraps Maya's FBX MEL commands in Python classes. vista calls the MEL commands directly, and resets the FBX settings before every export.
Many teams author cameras directly in Sequencer, against the real lighting and assets. vista is for the pipelines where layout and camera work happen in Maya.