Unofficial fan project. Not affiliated with AMA Pro Racing, MX Sports Pro Racing, the SMX League, Monster Energy, or any venue.
Procedural motocross tracks in Blender 5.2: SVG centerlines, geometry nodes, Poly Haven PBR, Cycles transparent PNG. Eleven layouts in project.blend (procedural hills) or project_terrain.blend (USGS macro terrain).
| Stage | Where |
|---|---|
| Track definition | assets/tracks/<slug>/track.json (SVG fetched by download_track_assets.py) |
| Terrain heightmaps | terrain.png + terrain_meta.json (fetched by download_track_terrain.py) |
| Scene | mx_track_scene.py |
| Track mesh | MX_PathRibbon + Geo_RibbonProfile (Curve to Mesh quads) |
| Ground | MX_GroundField on {slug}_Ground |
| Terrain sampling | Geo_TerrainSample in mx_terrain_nodes.py |
| Materials | mx_surface_presets.py, mx_materials.py |
| Render | configure_render.py (procedural), configure_render_terrain.py (terrain) |
Per track: collection under Tracks, objects {slug}_Path, {slug}_Track, {slug}_Ground. Scene mx_active_track picks the visible layout and render folder. Terrain scenes also set mx_terrain_mode.
Switch track: Properties > Scene > MX Active Track, or 3D View sidebar MX Track panel (run register_mx_ui.py once per session).
Python modules are shared by both blend files. mx_terrain_mode on the scene selects terrain vs procedural behavior at import and build time.
Hill noise drives elevation on the centerline. span_m defaults to 420 m (stylized scale).
python download_track_assets.py
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project.blend --background --python build_tracks.py
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project.blend --background --python setup_path_ribbon.py
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project.blend --background --python configure_render.pyLaunch: open_blender.ps1
USGS 3DEP 1 m DEM macro hills; real-world span_m per venue (~1800 to 2100 m). Jumps are manual later.
The track ribbon is built flat, then each mesh vertex samples the heightmap and drapes onto terrain (needed on steep slopes). Ground uses the same sampler on its grid vertices. Terrain mode sets hill noise to zero, 6 width segments, and 0.25 m track Z clearance.
pip install -r requirements-terrain.txt
python download_track_assets.py
python seed_track_geo.py # if geo blocks missing
python download_track_terrain.py # ImageServer by default; add --use-tnm to try TNM Access
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" --background --python rebuild_terrain_project.pygeo.extent_m is sized to ~118% of span_m so the ground covers the full SVG layout. Re-run download_track_terrain.py --force after changing extent.
Rebuild node groups only:
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project_terrain.blend --background --python build_terrain_tracks.py
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project_terrain.blend --background --python validate_terrain_tracks.pyLaunch: open_blender_terrain.ps1
Alignment tuning: edit heading_deg, offset_m, span_m, track_width_m, or track_width_segments in assets/tracks/<slug>/track.json, then:
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project_terrain.blend --background --python import_track.py -- washougalbuild_terrain_tracks.py reapplies modifier defaults from code and track.json; hand-tweaked widths or Z offsets in Blender are overwritten.
Camera: auto-framed on track switch; optional render.camera overrides in track.json.
Use project_terrain.blend for LiDAR work and keep project.blend on procedural hills until every venue looks right. No merge is required to use terrain.
When ready to make terrain the default entry point, run merge_terrain_project.py after visual sign-off. It validates terrain tracks, backs up project.blend to backups/project_pre_merge_<date>.blend, and copies project_terrain.blend over it. The original procedural blend is also in backups/project_pre_terrain.blend from the first terrain rebuild. Restore either backup or run rebuild_project.py to get procedural hills back.
python merge_terrain_project.py{slug}_Track / PathRibbon: path, path scale, path segment length, track width, width segments, texture scale, Z offset, track material. Terrain mode adds hidden terrain image sockets.
{slug}_Ground / GroundField: ground size, subdivisions, grass texture scale, green boost, fade inner/outer, grass material.
mx_modifier_sync.py copies modifier floats into shader nodes (texture scale, grass tint, fade radii).
Cycles (HIP when available), 1920x1080, film transparent. F12 writes under renders/<slug>/. Terrain uses scaled camera clip and auto-framing (mx_camera_framing.py).
README stills:
& "C:\Program Files\Blender Foundation\Blender 5.2\blender.exe" project_terrain.blend --background --python export_readme_screenshots.py| Script | Purpose |
|---|---|
open_blender.ps1 |
Open procedural blend and track UI |
open_blender_terrain.ps1 |
Open terrain blend and track UI |
build_tracks.py |
Build all tracks (procedural) |
build_terrain_tracks.py |
Build all tracks (terrain) |
import_track.py |
Re-import one track after track.json edits |
download_track_assets.py |
Fetch third-party SVG centerlines |
download_track_terrain.py |
Fetch USGS DEM per track |
seed_track_geo.py |
Seed geo/terrain blocks in track.json |
rebuild_terrain_project.py |
New project_terrain.blend |
configure_render_terrain.py |
Cycles setup for terrain scale |
validate_terrain_tracks.py |
Headless terrain checks |
merge_terrain_project.py |
Gated promotion to project.blend |
validate_tracks.py |
Procedural scene check |
rebuild_project.py |
New project.blend |
export_readme_screenshots.py |
Cycles stills for docs/screenshots/ |
License: MIT (this project's code). Third-party maps, USGS elevation, and Poly Haven assets: assets/ATTRIBUTION.md.

