Extract and export 3D map geometry from Unreal Tournament 1999 (UT99) .unr files. This tool reads BSP polygon data from classic UT99 maps — including DM-Barricade, CTF-Command, DM-Morpheus, and any other stock or custom map — and exports them to standard 3D formats usable in Blender, Maya, Unity, Unreal Engine 5, and other 3D applications.
Output includes full UV coordinates, vertex normals, per-texture material groups, and lightmap UVs (as glTF TEXCOORD_1). Texture names are resolved from the original package's import/export tables, making it straightforward to reapply the correct source textures. v2.0.0+ can also extract actual texture images from .utx packages — decoded DXT1/3/5 compressed textures saved as PNG.
A cross-platform PySide6 GUI provides drag-and-drop batch processing with a real-time 3D wireframe preview (mouse-drag rotation, scroll zoom), a Catppuccin Mocha dark theme, progress ETA, and keyboard shortcuts. A CLI is also available for headless/scripted use.
Also works with Unreal Engine 1 games built on the same engine, such as Deus Ex, Rune, and Unreal (1998).
| Platform | Format | File |
|---|---|---|
| Linux | standalone binary | UT99-BSP-Extractor-linux |
| Linux | .deb (Debian/Ubuntu) | ut99-bsp-extractor_1.0.0_amd64.deb |
| Linux | .rpm (Fedora/RHEL) | ut99-bsp-extractor-1.0.0-1.x86_64.rpm |
| Windows | .exe | UT99-BSP-Extractor-windows.exe |
| macOS | standalone binary | UT99-BSP-Extractor-macos |
All assets built automatically by GitHub Actions on tag push.
- Cross-platform GUI — Native look on Linux, Windows, and macOS (PySide6)
- Batch processing — Drag & drop multiple maps, extract all at once
- 3D wireframe preview — Rotate with mouse, zoom with scroll wheel
- 3 export formats — OBJ (raw), OBJ+MTL (grouped by texture), glTF 2.0 (with lightmap UVs as
TEXCOORD_1) - Modern dark theme — Easy on the eyes, consistent across platforms
- Settings persistence — Remembers window size, last directory, format choice
- Keyboard shortcuts — Ctrl+O (add files), Ctrl+E (extract), Delete (remove)
- Context menus — Right-click queue items to remove, show in folder, quick-extract
- Progress ETA — Estimated time remaining during batch extraction
- Stats dashboard — Live polygon count, maps queued, last run time
- Texture extraction — Extract .png from
.utxtexture packages (DXT1/3/5 decode) - Flexible export options — Choose to export geometry only, textures only, or both, with or without texture references
- Lightmap UV support — Second UV set in glTF output (
TEXCOORD_1) - Python API —
from ut99bsp import extract_mapfor scripting
git clone https://github.com/Moloch-Lab/ut99-bsp-extractor.git
cd ut99-bsp-extractor
./install.sh # creates venv + installs package
./run.sh # launch GUIOr use the interactive installer to build a package for your OS:
./venv/bin/python3 installer.py # interactive CLI menu
./venv/bin/python3 installer.py --gui # GUI installer
./venv/bin/python3 installer.py --os linux --format appimage # non-interactive./run.shDrag & drop .unr files, select format (OBJ, OBJ+MTL, glTF), click Extract All. After extraction, click Preview to inspect the 3D geometry (drag to rotate, scroll to zoom).
# Via installed package:
venv/bin/ut99-bsp-extractor map.unr [output] -f {obj,objmtl,gltf}
# Or directly:
python rip_unr.py map.unr [output] -f {obj,objmtl,gltf}Formats:
obj— Wavefront OBJ (no material library)objmtl— OBJ + MTL (polygons grouped by texture)gltf— glTF 2.0 (.gltf+.binwith per-material mesh primitives, includes lightmap UVs asTEXCOORD_1)
Output defaults to <mapname>.obj in the current directory.
from ut99bsp import extract_map
result = extract_map("DM-MyLevel.unr", "output.obj", fmt="objmtl")
print(f"{result.polygons} polygons written to {result.output_path}")
# result.triangles -> list of 3-tuples for previewThe installer.py script builds distribution packages for your target OS:
| OS | Formats | Requirements |
|---|---|---|
| Linux | standalone binary, .deb, .rpm, pip |
dpkg-deb for .deb, rpmbuild for .rpm (optional) |
| Windows | .exe (via PyInstaller on Windows), pip | Windows + PyInstaller for .exe |
| macOS | .app (via PyInstaller on macOS), pip | macOS + PyInstaller for .app |
Run the installer interactively:
./venv/bin/python3 installer.py # CLI menu
./venv/bin/python3 installer.py --gui # GUI (requires PySide6)
./venv/bin/python3 installer.py --os linux --format binary # headlessut99-bsp-extractor/
├── src/ut99bsp/ # Python package
│ ├── __init__.py # public API
│ ├── extractor.py # package reading + BSP extraction
│ ├── exporters.py # OBJ/MTL + glTF writers
│ └── gui.py # PySide6 GUI
├── rip_unr.py # CLI script (imports from ut99bsp)
├── ut99_bsp_gui.py # GUI script (imports from ut99bsp)
├── installer.py # cross-platform installer / packager
├── pyproject.toml # build config
├── install.sh # one-step venv setup
├── run.sh # GUI launcher
├── build.py # PyInstaller packaging
└── requirements.txt # PySide6 dependency
- Parses the UT99 package file format (header, name/import/export tables, compact indices)
- Locates the Level export and follows its Model reference
- Reads the Model's native data: bounding structures, then BSP arrays (Vectors, Points, Nodes, Surfaces, Verts)
- Extracts polygon geometry by walking BSP nodes and computing UVs from texture axis vectors
- Writes unique vertices, normals, and UVs to the requested format
| Field | Type | Description |
|---|---|---|
Vectors |
TArray<FVector> |
Normal/axis vectors for surfaces |
Points |
TArray<FVector> |
Actual vertex positions |
Nodes |
TArray<FBspNode> |
BSP tree nodes with polygon references |
Surfaces |
TArray<FBspSurface> |
Surface properties (texture, UV axes) |
Verts |
TArray<FVert> |
Vertex-to-point mappings |
- Python 3.8+
- PySide6 >= 6.6 (GUI only; install with
pip install PySide6)
MIT