DecalRoad is a strip-shaped decal object defined by a chain of road nodes. It is mainly used for roads, paths, painted surface strips, tire tracks, markings, and other long decal-like surfaces that follow terrain or static meshes.
A DecalRoad is not road geometry. It is projected/clipped onto existing surfaces, usually terrain, and rendered as a decal.
It is also one of the main sources of AI/navigation data. Roads with positive drivability can contribute to the navigation graph used by AI, traffic, and routing systems.
A simple DecalRoad entry in items.level.json:
{
"class": "DecalRoad",
"name": "road_main_01",
"material": "road_asphalt",
"textureLength": 8,
"drivability": 1,
"autoLanes": true,
"oneWay": false,
"renderPriority": 10,
"nodes": [
[0, 0, 0, 8],
[50, 0, 0, 8],
[100, 20, 0, 8]
]
}
Each node is stored as:
[x, y, z, width]
| Field | Type | Description |
|---|---|---|
class |
string | Must be "DecalRoad". |
name |
string | Scene object name. |
material |
string | Material used to render the road decal. |
nodes |
array | Road node list. Each node is [x, y, z, width]. |
textureLength |
number | Length in meters before the material texture repeats. |
renderPriority |
integer | Draw order. DecalRoads are rendered in descending priority order. |
zBias |
number | Additional depth/render bias. |
decalBias |
number | Height/bias above the clipped surface. |
distanceFade |
array[2] | Distance fading parameters. |
startEndFade |
array[2] | Fade length at start and end of the road. |
overObjects |
bool | Allows clipping over static mesh objects, not only terrain. |
hiddenInNavi |
bool | Hides this road from navigation display where supported. |
persistentId |
string | Editor/engine persistent ID. Usually generated automatically. |
DecalRoad stores its shape as an ordered list of nodes.
Example:
"nodes": [
[0, 0, 0, 8],
[50, 0, 0, 8],
[100, 20, 0, 10]
]
Each node contains:
| Index | Meaning |
|---|---|
0 |
X position |
1 |
Y position |
2 |
Z position |
3 |
Road width |
The road is generated between consecutive nodes.
The node width controls road width at that point. Width is interpolated along the road.
overObjects is disabled, node height is projected to terrain height during regeneration.By default, DecalRoad projects onto terrain.
It samples terrain height and adjusts generated edges to sit on the terrain surface.
This means the node Z value is often less important for terrain roads, because the road is snapped to terrain during regeneration.
If the level does not contain terrain and overObjects is not enabled, the road cannot generate correctly.
"overObjects": true
When enabled, DecalRoad can project over static mesh objects as well as terrain.
This is useful for:
When disabled, the road expects terrain.
overObjects, the road may fail to generate.The material field references a Material datablock.
"material": "road_asphalt"
The material should be authored for decal road rendering and usually tile along the road length.
Important material expectations:
If the material cannot be found, the road uses a warning material.
textureLength controls how often the road material repeats along the road.
"textureLength": 8
This means the texture repeats approximately every 8 meters.
Use lower values for dense repeating patterns, higher values for large markings or long texture spans.
renderPriority controls ordering between overlapping decal roads.
"renderPriority": 10
Decal roads are rendered in descending priority order.
Use render priority when layering:
zBias and decalBias affect how the decal road is offset/depth-biased against the target surface.
"zBias": 0,
"decalBias": 0
These help avoid z-fighting, where the road flickers against the surface underneath.
Use small values. Large values can cause visible hovering or sorting artifacts.
distanceFade controls distance-based fading.
"distanceFade": [300, 50]
The first value is the main fade distance, and the second value is the fade range.
If distanceFade is not set, the default is:
[300, 50]
The first value should generally be greater than the second.
startEndFade fades the road at its beginning and end.
"startEndFade": [5, 5]
This is useful for blending road decals into other surfaces or avoiding abrupt ends.
| Value | Meaning |
|---|---|
| First value | Fade distance at the start of the road. |
| Second value | Fade distance at the end of the road. |
DecalRoad can generate edges using either legacy or improved spline logic.
"improvedSpline": true
Uses the newer Catmull-Rom-based spline generation.
"smoothness": 0.5
Controls spline smoothness:
| Value | Description |
|---|---|
0 |
More linear |
0.5 |
Medium smoothness |
1 |
Fully smooth |
"detail": 0.1
Controls spline sampling step.
Smaller values create more subdivisions. For example:
0.1 = every 10%
0.2 = every 20%
0.5 = midpoint only
"looped": true
Connects the end of the road back to the start.
Useful for closed tracks or loops.
"startTangent": true,
"endTangent": true
Uses the first/last point as tangent markers for smoother endpoints.
DecalRoad supports two spline generation modes:
Both modes convert the road’s control nodes into generated road edges. These generated edges are then used for terrain/static clipping, UV generation, rendering, and AI/navigation data.
Legacy mode is used when:
"improvedSpline": false
or when the field is not enabled.
Legacy mode builds a Catmull-Rom spline through the road nodes and then decides where to place generated edges based on curve direction changes.
The process is roughly:
breakAngle.This means breakAngle controls how densely the road is subdivided on curves.
Example:
"improvedSpline": false,
"breakAngle": 3
Lower breakAngle values create more generated edges on curves, improving shape accuracy but increasing generated geometry.
Higher values create fewer edges, which can be cheaper but may look less smooth.
Improved mode is used when:
"improvedSpline": true
This mode also uses Catmull-Rom interpolation, but subdivision is controlled more directly by detail and smoothness.
The process is roughly:
startTangent or endTangent are enabled.looped is enabled, wrap node indices so the road forms a closed loop.In improved mode:
smoothness controls Catmull-Rom curve tension.detail controls sampling density.looped allows closed roads/tracks.startTangent and endTangent improve endpoint direction control.Example:
"improvedSpline": true,
"smoothness": 0.5,
"detail": 0.1
Here, detail: 0.1 means the curve is sampled roughly every 10% of each segment.
Use improved spline for new roads when possible. It gives more predictable control over smoothness, loop behavior, and subdivision.
Use legacy mode mainly for old content or when you need to preserve the exact shape of an existing road.
| Mode | Best use |
|---|---|
| Legacy | Existing old roads, compatibility. |
| Improved | New roads, smoother curves, loops, better control. |
breakAngle is used by the legacy spline algorithm.
"breakAngle": 3
The road is subdivided when the curve angle exceeds this threshold.
Smaller values generate more edge slices on curves.
During regeneration, the road nodes are converted into road edges.
Each generated edge contains:
These edges are then used to capture/clamp underlying terrain/static mesh triangles.
DecalRoad does not create a flat road mesh directly. Instead, it:
textureLength.This allows the road to follow the underlying surface.
Decal roads are grouped by material and render priority.
The static decal road manager rebuilds and batches road geometry for efficient rendering.
Roads are split into render nodes/batches for:
This is important because levels can contain many decal road segments.
The decal road renderer packs vertex positions relative to block origins.
Large decal road batches are split into blocks so packed local positions remain within a supported range.
If a road produces a batch that is too large or spans too far, errors may be logged about packed position range or vertex count.
For best results:
Decal roads can regenerate when the underlying surface changes.
Examples:
overObjects movesWhen terrain changes overlap a road, the road may be marked for regeneration.
DecalRoad can contribute to AI/navigation data.
Important pathfinding fields:
| Field | Type | Description |
|---|---|---|
drivability |
number | Determines whether/how AI uses this road. |
autoLanes |
bool | Automatically generates lane data. |
lanesLeft |
integer | Manual lane count on one side. |
lanesRight |
integer | Manual lane count on one side. |
oneWay |
bool | Marks the road as one-way. |
flipDirection |
bool | Reverses logical driving direction. |
gatedRoad |
bool | Marks the road as gated/private. |
autoJunction |
bool | Allows automatic junction connections. |
useSubdivisions |
bool | Generates higher-detail AI road data. |
hiddenInNavi |
bool | Hides road from navigation display where supported. |
drivability controls if and how the road is used by AI/navigation.
"drivability": 1
Typical values:
| Value | Meaning |
|---|---|
-1 |
Not used for AI/navigation. |
1 |
Normal/optimal road. |
0.5 |
Less preferred road, often dirt or rough road. |
0 |
Very poor route, generally avoided. |
If you want AI traffic to use the road, set drivability above 0.
If the road is visual only, use:
"drivability": -1
"autoLanes": true
When enabled, lanes are generated automatically from road width and road rules.
When disabled, use:
"lanesLeft": 1,
"lanesRight": 1
Manual lane settings are interpreted together with the level’s roadRules.rightHandDrive setting from info.json.
oneWay makes the road one-way:
"oneWay": true
By default, direction follows node order.
flipDirection reverses the logical direction:
"flipDirection": true
Use flipDirection if AI drives the wrong way.
"gatedRoad": true
Marks the road as gated/private.
This is used for:
In navigation processing, private/gated roads are treated differently from normal public roads.
"autoJunction": true
When enabled, the navigation system may automatically connect paths when they intersect.
Disable it for roads where automatic merging would create bad connections:
"autoJunction": false
Useful for:
"useSubdivisions": true
When enabled, the AI/navigation graph can use higher-detail road edge subdivision data instead of only road control nodes.
This can improve navigation path fidelity on curved roads.
"hiddenInNavi": true
Hides the road in navigation display where supported while still allowing it to exist in the graph depending on system behavior.
In modern items.level.json, road nodes are stored in the nodes array:
"nodes": [
[0, 0, 0, 8],
[50, 0, 0, 8]
]
Older TorqueScript serialization used repeated Node = "x y z width"; fields. Modern JSON should use the nodes array.
{
"class": "DecalRoad",
"name": "road_asphalt_01",
"material": "road_asphalt",
"textureLength": 8,
"renderPriority": 10,
"drivability": 1,
"autoLanes": true,
"autoJunction": true,
"nodes": [
[0, 0, 0, 8],
[50, 0, 0, 8],
[100, 20, 0, 8]
]
}
{
"class": "DecalRoad",
"name": "highway_ramp_01",
"material": "road_asphalt",
"textureLength": 12,
"drivability": 1,
"oneWay": true,
"flipDirection": false,
"autoLanes": false,
"lanesLeft": 0,
"lanesRight": 2,
"nodes": [
[0, 0, 0, 8],
[80, 10, 0, 8],
[160, 40, 0, 8]
]
}
{
"class": "DecalRoad",
"name": "bridge_decal_01",
"material": "road_asphalt",
"overObjects": true,
"textureLength": 10,
"drivability": 1,
"autoJunction": false,
"nodes": [
[0, 0, 20, 8],
[50, 0, 20, 8],
[100, 0, 20, 8]
]
}
{
"class": "DecalRoad",
"name": "painted_line_01",
"material": "road_line_white",
"textureLength": 4,
"renderPriority": 20,
"drivability": -1,
"decalBias": 0.001,
"nodes": [
[0, 0, 0, 0.3],
[30, 0, 0, 0.3]
]
}
DecalRoad for road decals and pathing surfaces, not raised road geometry.TSStatic or terrain for actual physical geometry.overObjects for bridges, overpasses, tunnels, or mesh roads.textureLength matched to the material’s intended scale.renderPriority for layered markings.drivability correctly:
1 for normal roads0.5 for rough/dirt roads-1 for visual-only decalsautoJunction for stacked roads, overpasses, or close parallel paths.Possible causes:
overObjects is falseroad_invisibleAdjust:
"decalBias": 0.001
or check material/render priority.
decalBias may be too high, or the road is projected over an unexpected object.
Enable:
"overObjects": true
Check:
"drivability": 1
Also check lane settings and whether the road contributes to the navgraph.
Toggle:
"flipDirection": true
or check node order.
Set:
"autoJunction": false
on problematic roads.
Adjust:
"textureLength": 8
Lower values repeat more often. Higher values stretch/repeat less often.
Check:
"distanceFade": [300, 50]
or increase the fade distance.
DecalRoad is a terrain/static-surface projected road decal object.
It is used both visually and for AI/navigation. Visually, it renders a textured strip clipped onto terrain or static meshes. For gameplay, it can contribute road/lane/drivability data to the navigation graph.
Use it for roads, paths, markings, and navigation-connected surfaces. For actual raised geometry, use TSStatic or terrain, with DecalRoad projected on top when needed.
See also: Material file format
, Decals format
, Navigation map (map.json)
, MeshRoad
.
Was this article helpful?