This manual explains how TORCS tracks are authored and processed. It starts with an easy conceptual view and then goes into reference-level detail. It focuses on TORCS behavior and data formats, and discusses AC3D/Blender only where needed for alignment-safe post-editing. It covers the most recent TORCS track XML format, version 4 (v4). The TORCS track editor is not discussed here.
When you create a TORCS track, there are two related descriptions:
Graphic/3d description (usually <name>.ac or <name>.acc)Think of it as:
.ac or .acc = how the track looksBoth should stay consistent. If they drift apart, players can see one edge and collide with another.
Typical loop:
name.xml.trackgen.accc.trackgen -r.accc into the final track model.For beginners: start with simple geometry and defaults, then add complexity in this order:
For a compact applied snippet that combines these concepts, see 11.1 Mini end-to-end XML example.
Track metadata and asset rights should be explicit from the beginning. Beware, if you are not clear about it or choose incompatible licensing with TORCS, your track cannot be integrated in TORCS or further developed by other people later:
author and description in XML HeaderDo not use random internet assets with unknown license state. Do not include commercial/proprietary assets unless redistribution and derivative-use rights are explicitly compatible with your track release.
If you reuse TORCS assets, your track is a derivative work of TORCS content and must be distributed under terms compatible with TORCS licensing (GPL version 2 or later).
Practical recommendation for README:
License section for XML/AC/ACC/texturesAuthors and attribution listThird-party assets table (source URL, license, modifications)trackgen, accc)trackgen basicsTrackgen takes the track XML file as input and generates the initial 3D-model or model parts (.ac files). Basic command:
Common options:
-c, -n: category and track name (required).-a: generate all (track + terrain path).-s: split track and terrain output.-S: split all output.-b: bump-track generation mode.-r: raceline-track generation mode.-z: calculate and exit (no full generation).-B: do not auto-generate border from rectangle; use relief border.-E <n>: export elevation image mode (detailed in chapter 14).-H <nb>: height step count for -E 4.-i <xml_path>, -o <ac_path>: useful for tests/custom paths.Example:
accc basicsaccc transforms or merges AC3D files.
Track-focused use cases:
+shad: generate a shading-oriented AC3D file.-g ... -l0 ... -l1 ...: combine multilayer geometry.+o: optimize track-zone grouping output.Car-oriented options (+s, +es, +et) are available but are not the primary path for basic track authoring.
Example track merge flow:
This is the critical rule when editing generated .ac files:
Graphic/3d descriptionIf you move/rotate/scale the generated road mesh in AC3D/Blender, visuals and physics drift apart.
(0,0,0)TORCS computes a bounding box from generated track geometry (track only, without terrain/scenery), then shifts all segment and camera coordinates so the minimum corner becomes (0,0,0).
x, minimum y, minimum z.width is stored as barrier metadata, not as extra boundary vertices.In practice this means: if you inspect the model, origin often appears aligned with the inner side of wall barriers (before barrier thickness), which is expected.
No. With standard generation and start direction, origin is deterministic:
xySo origin is in the back-right quadrant (including boundaries) when you face race direction on the grid.
When loading AC3D vertices, TORCS remaps axes as:
x_torcs = x_ac3dy_torcs = -z_ac3dz_torcs = y_ac3dSo AC3D up-axis (Y) becomes TORCS up-axis (Z), and AC3D Z maps to TORCS Y with sign inversion.
Safe edits:
accc while keeping base road geometry unchangedUnsafe edits:
Quick validation after edits:
trackgen closure deltas remain near zeroTypical layout (simplified):
Use exact key strings from track.h.
Main Track provides default values used by segments:
widthsurfaceprofil steps lengthImportant behavior:
Main Track/width used for runtime main segments).str, lft, rgt)Each Main Track/Track Segments/<segment> entry is one authoring segment.
type="str": requires lg.type="lft" or type="rgt": requires radius and arc.end radius optional: enables varying-radius turns.Example:
Plain language:
z ... values define height.grade defines longitudinal slope.banking ... defines left-right tilt.Loader resolution order (important):
z start overrides side-specific start)z end, else side-specific end, else grade)banking start/end) applied where specifiedPractical advice:
linear vs spline)profil controls how vertical profile changes inside a segment.
linear: constant slope across the segment.spline: smooth curve from start to end heights.What is a spline here?
TrackSpline): start and end heights plus tangent values shape the curve.Tangent fields:
profil start tangent, profil end tangentprofil start tangent left/right, profil end tangent left/rightGeneric tangents override side-specific tangents at the same boundary.
Key model:
One authored segment may become multiple runtime segments.
For profil="spline":
profil stepsprofil steps == 1: steps = int(length / profil steps length) + 1profil steps length missing: fallback to Main Track/profil steps lengthFor profil="linear": steps = 1 in loader behavior.
start width -> end width)Example:
lg = 180m, profil="spline", profil steps length = 15msteps = int(180/15)+1 = 13Outward from main track on each side:
Variable-width behavior:
start width, end width)banking type for sides:
leveltangentstyle="curb")height on curb-style border segments is not just decorative. It affects both sampled track height and generated geometry.
Runtime height sampling behavior (RtTrackHeightL()):
base_height + alpha * (curb_height + curb_roughness) / widthalpha runs across the curb width and is mirrored for right-border orientationcurb_roughness comes from surface roughness and wavelength along segment lengthPractical effect:
style="wall")There are two relevant collision paths:
friction, rebound, dammage)TR_WALL chainsImportant limitation from current simulation code:
Authoring implication:
style="wall" with meaningful heightstyle="curb" and tune heightUse border only when:
Use side only when:
Use both when:
Pit merge rule of thumb:
This is a full runnable example designed for copy/paste, just try it. It uses an oval layout (two 180-degree turns), a realistic pit lane layout with 20 pit slots, and demonstrates banking plus a descending counter-straight.
Suggested file path:
Generate with:
Raceline workflow (easy-start variant using global data/textures/raceline.png):
If you also use a baked shadow layer, a common layout is:
Raceline shaping keys in Main Track:
raceline widthscale: global width scaling for generated raceline strip.raceline int: safety margin to inside border (meters).raceline ext: safety margin to outside border (meters).The example uses 1.5 / 3 / 3 (same style as g-track-1) for a clearly visible, conservative driving line.
Notes:
accc fails with stripe: command not found, your environment is missing the external stripe tool used by this conversion path.stripe from source/build tooling so ACC merge can complete.stripe is already included.To render the combined model in-game, change:
to:
What this demonstrates:
Header, Graphic, Surfaces, Main Track).default-surfaces entity include.plan) border sections.marks as turn-marker distances on the turns.The loader reads segments sequentially and keeps state for several fields. So omitted values are resolved by per-field fallback chains. It is not purely "always from Main Track" and not purely "always from previous segment".
| Field | If omitted in current segment | Initial source |
|---|---|---|
surface (main segment) | keeps previous segment surface | Main Track/surface |
Left/Right Side/start width | defaults to previous side end width | Main Track/Left|Right Side/width |
Left/Right Side/width | defaults to segment start width | derived in segment |
Left/Right Side/end width | defaults to segment width | derived in segment |
side/border/barrier surface | keeps previous state | matching Main Track default subsection |
side/border/barrier style | keeps previous state | matching Main Track default subsection |
profil steps length | uses global value | Main Track/profil steps length |
| profile start tangents | continue from previous segment end tangents | 0 (if no prior data) |
z start left/right | continues from previous segment end heights | 0 at beginning |
Elevation precedence within a segment is separate from state carry-over:
z start overrides side-specific start heightsz end overrides side-specific end heightsz end is absent and grade is present, end center height is derived from gradePractical authoring rule:
Surfaces are defined in Surfaces/<name>. Segments and side elements reference surface names via surface.
Read by track loader (track4.cpp) into tTrackSurface:
frictionrolling resistanceroughnessroughness wavelengthdammagereboundDefaults used if a field is absent are in loader code (getTrackSurface).
Meaning at high level:
friction: tire grip potential.rolling resistance: baseline drag from surface contact.roughness and roughness wavelength: small-scale vertical disturbance model.dammage: collision damage factor for that material context.rebound: restitution-like response.Used mainly by trackgen rendering export paths:
texture nametexture type (continuous vs discrete)texture link with previoustexture start on boundarytexture sizetexture mipmapbump name, bump sizeraceline namecolor R1/G1/B1, color R2/G2/B2)Practical meaning:
texture size controls repetition scale.texture link with previous=yes keeps texture continuity across segments.texture start on boundary=yes aligns texture start with segment boundary.For track model loading, graphics uses this search order:
tracks/<category>/<trackname>data/texturesdata/img.Background loading uses a very similar order but checks data/img before data/textures.
Practical implication:
.png.rgbThe renderer applies filename heuristics:
_n... disable mipmappingshadow disable mipmappingSo texture mipmap in surface definitions is a hint, but these filename rules can still override mipmap behavior.
AC loading enables special alpha-test/blend handling when texture name contains:
treearbortrans-Additionally, material alpha from AC (mat->rgb[3]) is checked:
0.99, geometry is treated as translucent (alpha-test/blend path)>= 0.99, it follows the opaque path unless filename-triggered rules applyThis is commonly used for vegetation and fence-card textures.
Why this convention exists:
_n (no mipmaps) is a common TORCS pattern to reduce those artifactsYou can see this pattern in stock content (for example e-track-2 tree/arbor textures).
Graphic/Terrain Generation)Key fields:
track step: sampling step near track geometry.border margin: terrain extent around track bounds.border step: terrain mesh step for outer areas.border height: external border wall/height behavior.group size: split size for terrain grouping (performance/scene graph).surface: terrain base surface material.relief file: optional AC3D relief constraints.elevation map: grayscale height map input.maximum altitude, minimum altitude: grayscale-to-height mapping range.How elevation map is used:
[minimum altitude, maximum altitude]Important operational detail:
trackgen is invoked with -E, terrain loading path skips elevation-map loading and runs export flow (see chapters 14 and code path in GenerateTerrain).trackgen -E elevation export modes-E <n> writes elevation PNG outputs. The mode number selects which image(s) are written.
Supported values:
0: export all four maps (-elv, -elv2, -elv3, -elv4) in one run.1: export continuous grayscale height map from the combined generated scene AC.2: export continuous grayscale height map from terrain mesh AC (-msh).3: export occupancy-style map from terrain mesh AC (track/terrain footprint dark, outside white).4: export quantized (stepped) grayscale height map from track AC (-trk).From current implementation:
1 (or 0) -> <name>-elv.png2 (or 0) -> <name>-elv2.png3 (or 0) -> <name>-elv3.png4 (or 0) -> <name>-elv4.pngGeneration mapping in code:
-elv.png: continuous grayscale altitude map from <name>.ac (dispf=1).-elv2.png: continuous grayscale altitude map from <name>-msh.ac (dispf=1).-elv3.png: coverage mask from <name>-msh.ac (dispf=0):-elv4.png: stepped altitude map from <name>-trk.ac (dispf=2), using -H bins.Practical reading of the images:
dispf=1 and dispf=2 maps)-elv3.png is best for "where geometry exists" checking, not for exact altitude-H interaction-H <nb> sets quantization count for mode 4.1: single-image altitude overview after a generation pass2: inspect terrain-mesh-specific altitude without track-only export path3: create/edit masks and verify terrain coverage extents quickly4: produce banded contour-style map for manual elevation editing workflow0: generate complete diagnostic set for comparisonMain Track/Pits typically uses:
entry, start, end, exitsidespeed limitlength, widthThese are segment-name based references. Keep names unique and stable.
Common camera fields:
segmentto rightto startheightfov start, fov endOn turns, many tracks use unit="deg" for to start.
TORCS parameter handling converts values with unit=... to SI internally.
Examples:
deg -> radians% or percent -> divide by 100km, cm, mm, ft, in -> metersImplications for authors:
Advanced per-segment fields used by loader include:
env map indexmarksNotes:
env map index feeds environment mapping selection in graphics modules.marks defines turn-marker sign distances (for example 25;50;100) used by trackgen turn-mark generation in extension build paths.For a compact applied example that uses many keys from these tables together, see 11.1 Mini end-to-end XML example.
| Key | Scope | Meaning | Default/Fallback |
|---|---|---|---|
type | segment | geometry kind (str, lft, rgt) | required |
lg | str | straight length | required for str |
radius | lft/rgt | start radius | required for lft/rgt |
end radius | lft/rgt | end radius (varying-radius turn) | defaults to radius |
arc | lft/rgt | turn angle | required for lft/rgt |
z start | segment | center start height | overrides side start heights |
z end | segment | center end height | preferred end-height source |
z start left/right | segment | side-specific start heights | used when z start is absent |
z end left/right | segment | side-specific end heights | used when z end is absent |
grade | segment | longitudinal slope | used when explicit end heights are absent |
banking start/end | segment | cross-slope angles | applied to side heights where provided |
profil | segment | vertical interpolation mode | defaults to spline |
profil steps | segment | split count hint | if 1, may derive from step length |
profil steps length | segment/main | target split length | segment value or main-track fallback |
profil ... tangent ... | segment | spline shape control | side-specific or generic override |
surface | segment | material/surface name | inherits from Main Track/surface |
| Element | Key set | Behavior |
|---|---|---|
| side | start width, width, end width, surface, banking type | supports continuous width interpolation within segment |
| border | width, height, surface, style | width is constant per authored segment |
| barrier | width, height, surface, style | collision boundary layer outside side/border |
Side width fallback chain:
start width <- previous side end width when omittedwidth <- start width when omittedend width <- width when omittedStyle values seen in loader:
style: plan, curb, wallstyle: fence, wallStyle behavior notes:
curb: height acts as cross-width elevation offset (wheel-height relevant)wall: height defines vertical wall extrusion; used by wall collision solidsplan: flat strip behavior without curb/wall-specific offset semantics| Key | Category | Meaning |
|---|---|---|
friction | physics | grip coefficient |
rolling resistance | physics | rolling drag factor |
roughness | physics | disturbance amplitude parameter |
roughness wavelength | physics | disturbance spatial wavelength |
dammage | physics | damage factor |
rebound | physics | restitution-like factor |
texture name | rendering | base texture |
texture type | rendering | continuous or discrete mapping behavior |
texture link with previous | rendering | continuity across segment boundaries |
texture start on boundary | rendering | reset texture origin at boundaries |
texture size | rendering | texture repeat scale |
texture mipmap | rendering | mipmap hint value |
bump name, bump size | rendering | bump-texture and scale |
raceline name | rendering | raceline overlay texture |
color R1/G1/B1, R2/G2/B2 | rendering | color channels for surface definitions |
| Key | Meaning |
|---|---|
track step | sampling step along track for terrain generation |
border margin | terrain extent around track bounds |
border step | mesh step in border/outer terrain |
border height | border wall/height parameter |
group size | terrain grouping granularity |
surface | base terrain material |
relief file | optional relief geometry constraints |
elevation map | grayscale input map for altitude shaping |
maximum altitude / minimum altitude | map grayscale to world-height range |
trackgen: -a -s -S -b -r -z -B -E -H -i -oaccc: +o +shad -g -l0 -l1 -l2 -l3 -d1 -d2 -d3 -S -es -ntsBefore generation/testing:
radius and arc.Surfaces.track step, margins, alt range) are intentional.author, description) is present and accurate.After changes:
trackgenaccc post-processing if needed