Disclaimer: Not something I made. Needed a quick tool to convert VMF to GLTF, and couldn't find a proper one online, so had an AI code this. Wont take any credit for the code. Feel free to fork and rewrite as you see fit.

Convert Valve VMF map files to glTF 2.0 / OBJ / STL.
Handles multiple brushes, displacements, and point entities. Groups faces by VMF material name with stub colors (real VTF/VMT texture resolution is not implemented).
Has a GUI and CLI.
Example of displacement. Imported in blender:

Example of brush materials, model imported in Godot (randomly generated colors for brushes. I didn't want to use Valve files, but I wanted to preserve the materials as they were assigned):

Prebuilt Linux and Windows binaries are on the Releases page.
For the binary version, substitute python convert.py / python gui.py in the examples below with ./vmfconvert / ./vmfconvert-gui (or .exe on Windows).
- Python 3.10+
- No external dependencies
python convert.py <input.vmf> [output.{gltf,obj,stl}] [--scale N]Output format is picked from the extension (default .gltf).
Default scale is 0.0254 (1 Hammer unit = 1 inch = 0.0254m).
python convert.py map.vmf
python convert.py map.vmf out/map.gltf
python convert.py map.vmf out.obj
python convert.py map.vmf out.stl
python convert.py map.vmf --scale 0.1
python convert.py map.vmf out.gltf --scale 1python gui.pyTkinter-based. Pick an input VMF, format, scale, click Convert.
- glTF: one mesh per brush, one primitive per material within each brush. Includes
POSITION+ per-triangle flatNORMAL. Rootmaterialsarray has one stub PBR entry per VMF material name (deterministic color from hash of the name). Point entities (info_player_start,light_*,prop_static, etc.) are emitted as translation-only nodes withclassnameand all keyvalues preserved underextras. - OBJ: one
ogroup per brush,usemtlgroups per material, flatvnnormals, sidecar.mtlwritten alongside the.objwith matchingKdcolors. - STL: binary, flat face normals. No material support (format limitation); point entities are skipped.