topic: Scenery

Standard Shading Options for X-Plane 10 Scenery

X-Plane 10 provides a rich set of shading options for almost all of the art asset types in the scenery system.  This document provides a file-format level reference for these common options, as well as brief descriptions of what the options do.

Not every option is available in every file format; the chart at the end of the document lists which ‘extended’ options are available in which formats.

The detail commands and tiling commands are mutually exclusive – that is, they cannot be used together.

The one major format that does not follow this syntax is the X-Plane OBJ modeling format; see the X-Plane 8 OBJ format documentation for syntax specific to OBJ8.

X-Plane scenery art asset control files are text files with one instruction per line.  The lines are listed here individually.

Commands to Control Texturing

The texturing commands specify the albedo (daytime) and possible emissive (night lit) texture.  Both textures are specified by file path relative to the parent directory of the art asset.

Emissive textures are optional; omitting the TEXTURE_LIT directive means no lit texture.  Albedo textures are mandatory.

The “no-wrap” variants provide edge clamping to avoid bleeding from one side of an orthophoto to another; they are only available for .ter and .pol files.  The default commands provide wrap-around blending, which make textures suitable for tiling.

TEXTURE <filename>
TEXTURE_NOWRAP <filename>
TEXTURE_LIT <filename>
TEXTURE_LIT_NOWRAP <filename>

Day time textures may have an optional alpha channel; see alpha options below for its interpretation.  Lit textures may have an optional alpha channel, but it is not recommended.

Commands to Control Normal Mapping

The normal map texturing commands add a normal map to the shader.  Like the texturing commands, the no-wrap variant clamps edges and is available only for .ter and .pol files.

Normal maps should be in PNG format and can be in one of three formats:

  • RGB files provide tangent-space normal maps.
  • RGBA files provide tangent space normal maps in the RGB channels and the specular level in the alpha channel.
  • Gray-scale files provide the specular level in the gray channel.
TEXTURE_NORMAL <ratio> <filename>
TEXTURE_NORMAL_NOWRAP <ratio> <filename>

Ratio is a decimal number specifying the resolution of the normal map relative to the albedo, e.g. a ratio of 4.0 means the normal map repeats 4 times for every tile of the albedo texture.  This ratio can be used to change ‘noisy’ normal maps to be higher resolution.

SPECULAR <ratio>

If present, the SPECULAR command provides a multiplier to the specularity level of the material.  This value is multiplied by the specular level channel of the normal map if present.  Ratio should be in the range 0..1.  A few special cases to note:

  • If the SPECULAR directive is present but no normal map is present, the specularity is applied, in a uniform way.  (In other words, SPECULAR 1.0 without a normal map makes a uniformly shiny surface.)
  • If the SPECULAR directive is omitted but a normal map is present, the specular multiplier is defaulted to 1.0 – in other words, you get the specularity of the normal map, unmodified.
  • If the SPECULAR directive is omitted and the normal is also omitted, the specular multiplier is defaulted to 0.0 – in other words, you get a matte surface.
BUMP_LEVEL <ratio>

If present, BUMP_LEVEL scales the height of the normal map bumps; ratio should be in the range of 0..1, where 1.0 leaves the bump map unmodified.  (This directive is designed to reduce bumpiness.)  If BUMP_LEVEL is omitted, the default multiplier is 1.0 (e.g. the normal map is not modified).

Commands to Control Decals

X-Plane 10 contains a new decal shading stage as part of some of the art assets.  The decal stage blends a higher resolution repeating texture into a base texture to create the illusion of high resolution.  Because the decal is part of the shading process (and not an additional layer on top of the terrain), the performance impact is quite low.

Shaders can use up to two decal commands (neither of which are required).  Shaders can also refer to a separate .dcl file (which might be in the library); if the .dcl file contains two decal directives, then no other decals can be included.

(In other words, you get two decal effects, not two decal commands – one command loading two effects from one file uses up the entire decal budget.)

General conventions: the decal commands take a scaling ratio, which specifies how many times the decal repeats for each iteration of the albedo texture.  Textures are specified as relative file paths.

The decal shaders can create decals from either the RGB part of the decal texture, the alpha channel (treated as a gray-scale decal that takes on the ‘tint’ of the albedo) or potentially both; each decal shader has to use the same scale for both RGB and A, but the two separate decal shaders can use separate scales.

If you only need a single-channel decal, use a gray-scale PNG to load an “alpha-only” decal into X-Plane; this can save significant VRAM.  On modern video cards, an RGB decal takes the same memory as an RGBA decal, so consider loading something into the alpha channel – you’re paying for the memory no matter what.

DECAL <scale> <texture file>
DECAL_RGBA <scale> <texture file>

These commands add a decal using only the alpha channel and only the RGB channel of the decal file, respectively.

DECAL_KEYED <scale> <r> <g> <b> <a> <alpha> <texture file>

This command creates a decal whose application is “color-keyed” to the albedo texture.  In other words, which decal is applied from your texture (RGB or A) will depend on the color of the albedo.

The values of R, G, B and A are coefficients that key in the RGB texture based on the RGBA values of your albedo.  In other words, if you set G to 1.0 then you will get 100% of your RGB decal when the green channel of the albedo is at 100%.  (This would be a good way to bring a grass decal in over vegetation, for example.)

The alpha parameter describes how much to bring in the alpha-channel decal when the RGB channel decal is not used.  If alpha is 0.0, then the alpha-channel decal is never used; if it is 1.0, it is used for any pixels where the RGB decal is not used.  Generally you would set this to 1.0 if you have two complementary decals, e.g. a vegetation decal in RGB (keyed to green) and a concrete decal in the alpha channel.

DECAL_PARAMS <scale> <dither>
      <r> <g> <b> <a> <m> <k> 
      <r> <g> <b> <a> <m> <k> <texture file>
DECAL_PARAMS_PROJ <scale_x> <scale_y> <dither>
      <r> <g> <b> <a> <m> <k>
      <r> <g> <b> <a> <m> <k> <texture file>

Note: these advanced commands take all of their parameters on one line; they are only listed in multi-line format for readability.  They are not for the faint of heart.

These commands provide complete low level access to the decal shader.  For the non-projected form, scale is the ratio of repeats (higher numbers mean the decal repeats faster than the albedo).  For the projected format, the decal does not follow the albedo, but rather repeats every scale_x meters horizontally and every scale_y meters vertically.

Dithering: increasing this parameter from 0 to 1 mixes the alpha channel of the decal into the alpha channel of the albedo.  This can be used to create high frequency alpha variation (for examlpe, for the edges of textures).

Tip: to create a ‘ragged edge’ look for a texture with alpha, put an alpha decal on it, turn up the dither parameter (to route the decal alpha to the main alpha) and then use the dithering stage below (See alpha below) to ‘cut’ the alpha at a fixed level.  The result will be a high frequency ragged edge, useful for making the edges of dirt roads and other rough surfaces.

Following the dither are two sets of six parameters that increase the decal.  The first four (RGBA) bring in the decal based on the albedo’s red, green, blue and alpha channel.

The fifth parameter (“m” for modulator) brings in the decal based on another part of the shader; this parameter has no effect except in certain cases documented below.  Finally the constant (“k”) term brings in the decal no matter what.

Note that the levels of all parameters are added before the decal is brought in.  So, for example, if you have k = 1, G = -1, and all else are 0, you will get a decal that shows up except when the albedo is green (e.g. a decal that avoids vegetation).

The first set of six parameters sets levels for the RGB decal, the second six for the alpha decal.

DECAL_LIB <file path or library path>

What, you don’t want to hand-enter 15 numeric parameters?  Decals can be loaded from other files, which can be in the library; DECAL_LIB loads a decal from another file into an existing art asset.  Whether this command uses one or two decal shaders depends on the particular file loaded.

Commands to Control Blending and Alpha

These commands control how the alpha channel of a texture is processed.  They take effect after decaling; if the dither option is used in decaling, the alpha’s decal may be included in these calculations.

NO_ALPHA

This command strips all alpha information from the shader.  The most common use for this command is to recycle a texture whose alpha channel contains noise in a context where the alpha effect is not desired.

DITHER_ALPHA <softness> <bleed>

This command creates a dithering effect instead of an alpha-translucency effect where alpha is not 1.0.

The softness parameter needs to be greater than 0.0 and less than 1.0; it describes the softness of the dither – numbers closer to 1.0 look more like conventional translucent alpha; numbers closer to 0.0 look more like a hard cutoff.

Bleed is how much of the original alpha ‘bleeds through’ when the dithering effect is not dominant. A bleed of 1.0 would mean the shader is at least as opaque as without the dither; a bleed of 0 means we have only dither.

NO_BLEND <alpha cutoff level>

No-blend cuts off alpha blending on the graphics card; all pixels whose alpha is below the cutoff level are discarded, all that are above are opaque.

Alpha blending can cause Z-buffer artifacts, including halos of sky around vegetation and missing scenery through translucent windows.  If you can live without blending, you can use NO_BLEND to get a hard alpha cut that will not have z-buffer artifacts.

Note: DITHER_ALPHA can make cut-off effects but does not fix z-buffer problems; use NO_BLEND when the z-buffer is the problem.

Commands to Control Real-Time Shadows

NO_SHADOW

The command NO_SHADOW exempts the art asset from shadow generation.  Besides fixing cases where shadows look ugly (e.g. billboards) it can improve framerate.

Misc. Commands

You can enable or disable two-sided drawing with

TWO_SIDED <on/off>

The on/off value should be 1 for on or 0 for off.  Two-sided geometry is generally not recommended in most scenery-system cases.

One exception: .for (forest files) do not accept this directive; forest billboards are always drawn two-sided.

Tiling Shader Options

Some art assets allow for the use of tiling shader commands.  The tiling shader breaks up your albedo (and lit) textures into tiles and reorganizes them to create tiling patterns that repeat over a larger distance.

TEXTURE_TILE <x_tiles> <y_tiles> <x_pages> <y_pages> [<texture>]

This turns on texture tiling, which divides the albedo into a grid and randomly permutes the tiles like a number puzzle. This can help hide repetition.

  • x_tiles and y_tiles define the number of grid divisions for your albedo texture.
  • x_pages and y_pages are the number of pixels in the mapping texture used to pick tiles.
  • map.png is a texture used to pick tiles.
  • If you don’t provide map.png, X-PLane uses a noise texture – in that case, use 256 x256 for pages.

If you provide a ‘mapping’ tile, the red channel selects an X tile offset, and the green channel defines a green channel offset; the colors are mapped evenly based on the number of tiles.  For example, if you set up 8 tiles in X, then the red channel values for the 8 tiles are 0,32,64,96,128,160,192,224.

Detailing Extension

The detailing commands use two additional textures to provide additional day time texturing options:

  • A control texture is a texture whose four channels control the use of other textures.  The control texture uses the same UV map as the albedo texture.
  • A terrain texture runs at its own resolution and provides a separate source of tiling terrain, e.g. a repeating grass or concrete texture.

The textures are specified as follows:

TEXTURE_DETAIL <x_res> <y_res> <texture_file>
TEXTURE_CONTROL <texture_file>

x_res and y_res set the size of the entire terrain in texture (in meters). The control texture will precisely overlay the albedo.

The control texture’s channels do the following:

  • The red channel brings in the RGB decal – more red = more decal.
  • The green channel brings in the terrain texture – more green = more terrain. The terrain always appears under the translucent parts of the albedo (as defined by the albedo’s alpha). Think of this as a separate layer mask for a terrain layer that is fully under the albedo.
  • The blue channel brings in the alpha-channel decal (as a gray-scale decal). More blue = more decal.
  • The alpha channel creates static baked shadows. An alpha of 0.0 is most shadowed and an alpha of 1.0 is not shadowed. When the sim is in dynamic shadow mode, the baked shadows are shown only in visibility ranges where dynamic shadows do not apply.

While the terrain acts as a layer “under” the albedo, both decals act on top of both. (Technically, the gray-scale detail does apply on top of the RGB detail). The The baked shadows affect all layers.

The level of decals are controlled not only by the control red/blue channel, but by the decal’s “m” control (see above).  Basically the “m” modulator on the decal is multiplied by the control channel’s red and blue to provide the final decal level.

When a second decal is used, the modulators are reversed – the red channel controls the alpha of the second decal and the blue channel controls the rgb of the second decal.

Availability of Extensions

All basic functionality is available in all art asset types.  Tiling and detailing are mutually exclusive and only available in some art asset types.  No-wrap albedo/lit textures are only available in .ter and .pol files.

Art Asset No-wrap Detailing Tiling
Facades
Auto-Gen
.Pol
.lin
road.net
.ter
.bch
Comments Off on Standard Shading Options for X-Plane 10 Scenery

Forest (.for) File Format Specification

Revision History:
         11/08/22   Updated for X-Plane 1200 
         07/20/21   Corrected density_params
         07/23/20   Added Y_QUAD's rotation parameter again
         07/22/20   Reorganized, formatted, and units added
         07/08/20   Updated for clarity
	 03/20/12   Updated for X-Plane 1000
	 12/26/07   Updated for X-Plane 900
	 01/08/06   Updated for X-Plane 860
	 07/19/06   Initial Draft

FOREST CONCEPTS

FILE TYPE AND COMPATIBILITY

A .for file describes how to build 3-d trees out of a texture. Forests are placed in X-Plane by either placing a DSF polygon referencing the .for file or by referencing the .for file in an autogen art asset and placing tree annotations into the autogen tiles.

Starting with X-Plane 12, .for files can be used to define actual 3-d trees made of 3-d mesh. The general placement rules for trees still apply for 3-d trees, but the .for file has been expanded to provide additional ways to describe a tree’s look and behavior.

The forest file is essentially a set of rectangles describing where in the texture each tree resides. Lines starting with a # are comments.

LAYERS AND GROUPS

A .for file defines tree layers. Each layer is identified by an index number, starting at 0 by convention.  When a forest is built in a DSF, trees are placed from each layer, allowing for a multi-layered effect (E.g. underbrush and larger trees).  When trees are placed in autogen, the autogen tile specifies the specific layer it randomly picks a tree from.

Trees in layers may optionally be split into groups. This allows for clustering – with the right randomization parameters, X-Plane can cluster trees from the same group together, creating areas of similar-species trees.  If groups are not used in the .for file, one group is automatically created per layer to hold all trees in that layer.

PERLIN NOISE

In X-Plane 10, some of the randomization for forests can be specified via perlin noise.  The parameters are four pairs of wavelengths (in meters) and amplitudes (a ratio between 0 and 1).  For example:

CHOICE_PARAMS 500 0.75 10 0.25 0 0 0 0

sets up a perlin noise pattern to pick tree groups with the groups mostly changing about every 500 meters.  The second wave with 10 meters and 25% power helps “muddle” the edge of the transitions.  Perlin noise always consists of four wavelength/amplitude pairs; you can set unused amplitude/period pairs to 0,0.

Perlin noise constructs a normalized wave form between -1 and 1.  That is, an amplitude of 1 will maximally modulate between the minimum and maximum height of the trees.

Zero or all of the perlin _PARAMS can be used in the same .for file.

MESH BASED 3-D TREES

Starting in X-Plane 12, .for files have additional support for 3-d trees. Now trees can be either 3-d mesh based trees, or legacy 2D billboard trees. 3-d trees differ from 2-d trees in that they can have up to 3 meshes and up to 4 LOD steps to decrease the amount of detail present. This is necessary to increase performance by reducing visual quality of trees in the distance. A 3-d tree will always have a 2-d billboard tree as its last LOD step to further reduce the amount of computational power required for drawing. As a side effect, even if you only author 3-d based trees, you must still provide an atlas texture for the last LOD step.

Additionally, in X-Plane 12, the material parameters for .for files have been greatly expanded. A .for file now supports the standard X-Plane material commands that can be found in this article: Standard Shading Options for X-Plane 10 Scenery. This is regardless of whether the .for file describes legacy quad trees, or modern 3-d based trees. When providing 3-d trees, .for files have an additional material that will be used. You can switch between materials using the SHADER_2D and SHADER_3D commands. Subsequent commands will change the parameters for either the 2D or 3D shader. By default the 2D shader is active.

The default 2D shader starts out with double sided material and alpha testing with an alpha cut off value of 0.5. This matches the behavior of X-Plane 11 and prior.

FOREST HEADER

A .for file has a standard X-Plane header:

A

800

FOREST

The rest of the .for file contains commands that specify the forest file.

COMMANDS

TEXTURE <filename>

This defines the texture to be used for the forest. The entire forest must be built out of a single texture file. The file name is specified relative to the .for file, just like OBJ8 files. Lit textures are not allowed for forests.

[X-Plane 12] Starting in X-Plane 12, additional material commands are available that also supersede the TEXTURE command. You can find the new material commands here: Standard Shading Options for X-Plane 10 Scenery.

LOD <max lod>

This defines the farthest distance the trees can be seen. Lower values cause forests to disappear faster but result in faster frame rate.

[X-PLANE 9] In X-Plane 9, the LOD command is ignored; X-Plane calculates the viewing distances for all forests based on user settings. X-Plane will attempt to draw the forest for as long of a distance as possible, with a density approaching what is specified in the scenery file.

[X-PLANE 12] In X-Plane 12, the LOD command is no longer ignored. Instead, X-Plane will still calculate a maximum internal rendering distance based on the graphics settings set by the user and use the smaller of the two.

SCALE_X <x scale>
SCALE_Y <y scale>

These define the coordinate scale that is used to define the texture coordinates for the forest. This does not have to be the same as the size of your texture. Basically all texture coordinates are interpreted as if on a texture of these dimensions and then fit to the actual texture. (This command is provided to allow you to easily input numbers read off Photoshop rather than working in fractions.)

SPACING <x spacing> <z spacing>

This defines how far apart the trees are in meters. Smaller numbers pack the forest tighter and cause the sim to run slower (since more trees must be used to fill an area).

RANDOM <x spacing> <z spacing>

This defines how much, in meters, each tree may deviate from a perfect grid filling. So a random of 0 0 means a perfect grid.

TREE <s> <t> <w> <h> <offset> <frequency> <min h> <max h> <quads> <layer> <notes>

Each tree command (there can be more than one) defines a tree. Each tree is defined by a quad in the texture. The parameters are:

  • s – the horizontal texture coordinate of the lower left corner of the rectangle.
  • t – the vertical texture coordinate of the lower left corner of the rectangle.
  • w – the width of the tree texture rectangle.
  • h – the height of the tree texture rectangle.
  • offset – the distance from the left to the center of the tree in pixels.
  • frequency – the percentage of the time this tree is used. The sum of all percentages of all trees must add up to 100%.
  • min height – the minimum height of this tree type in meters.
  • max height – the minimum height of this tree type in meters.
  • quads – the number of polygons used to make the tree (1 or 2)
  • layer – this defines the layer the tree will belong to.  If the tree is within a group the tree layer must match the previous group layer.
  • notes – all further text on the line, used as a comment

Each tree is built from 1 or 2 quads. The texture dimensions define the aspect ratio and texture used. The quads are scaled based on the possible height range. You can specify where the center of the tree is – it doesn’t have to be the center of the texture, allowing for asymmetric trees.

[X-PLANE 9] X-Plane 9 limits the number of quads to two at most, and will reduce a tree to one quad based on distance from the viewer and rendering settings. So the number of quads parameter should be considered a maximum. (X-Plane 9 will not promote a one-quad tree into a two-quad tree.)

SKIP_SURFACE <surface type>

[New to 860:] Starting with X-Plane 860, you can use one or more SKIP_SURFACE directives to tell X-Plane not to put trees down on a certain surface type. The legal surface codes are the same ones allowed for OBJ8 ATTR_hard commands. You can use this command more than once to keep trees off many surface types.

Warning: because X-Plane builds both trees and other scenery types while you fly, in small pieces, you cannot use SKIP_SURFACE to keep trees off of scenery elements that are built during flight. (This is all scenery types except terrain.) For example, if you use SKIP_SURFACE concrete to try to keep trees off of roads, only trees that are “planted” by X-Plane after a road is built will be properly excluded.

Y_QUAD <s> <t> <w> <h> <offset_center_x> <offset_center_y> <y_quad_width> <elevation> <rotation>
  • s – the horizontal texture coordinate of the lower left corner of the rectangle.
  • t – the vertical texture coordinate of the lower left corner of the rectangle.
  • w – the width of the tree texture rectangle.
  • h – the height of the tree texture rectangle.
  • offset_center_x – the pixel offset on the x-axis where the Y_QUAD will sit on the tree trunk
  • offset_center_y – the pixel offset on the y-axis where the Y_QUAD will sit on the tree trunk
  • y_quad_width – the pixel width of the quad, based on the aspect ratio of the UV map
  • elevation – the pixel height, relative to the pixel height of the vertical TREE
  • rotation – rotation in degrees about the y-axis relative to the principal vertical quad

[New to 1000:] X-Plane 10 allows for an optional vertical base quad in a tree. The Y_QUAD directive applies to the previous TREE directive, but horizontal quads will only be created when the tree is built by the autogen system via specific annotations. The UV map is established via a quad (from the lower left corner) – the pixel offset establishes where the tree trunk sits on the 2-d quad.

The tree has a width parameter specifying the width of the quad (the aspect ratio is defined by the UV map) and an elevation for how far off the ground the quad is.  Both of these parameters are described in the unit of pixels of the vertical billboard.  In other words, if the vertical billboard of a tree is 100 pixels tall and you specify an elevation of 15 pixels, the horizontal billboard is always 15% of the way up the tree (whatever its final height is).  The motivation behind using vertical-billboard pixels here is to allow the UV map resolutions of the horizontal and vertical quads to be different; by sizing the horizontal tree in terms of the vertical one, a tree of fixed proportions can be built.

GROUP <layer> <percent>

[New to 1000:] X-Plane 10 can group trees into clusters – the groups should be consecutive in the file.  The layer parameter is the same as the layer of a tree itself – and all trees in a group should share the group’s layer.  The percentage of all groups should add up to 100%.

X-Plane will select trees by group when perlin noise is used, creating forest clusters.  When trees are in a group, the percent occurrence of all trees within a single group should add up to 100%.

DENSITY_PARAMS <amp 1> <dist 1> <amp 2> <dist 2> <amp 3> <dist 3> <amp 4> <dist 4>

[New to 1000:] this changes the pattern of tree density to follow perlin noise.  Note that the density is also affected by the polygon forest density (0-255) in the DSF, so this parameter effectively only changes the shape of trees for partial density forests.

CHOICE_PARAMS <dist 1> <amp 1> <dist 2> <amp 2> <dist 3> <amp 3> <dist 4> <amp 4>

[New to 1000:] this changes the pattern of tree selection to follow perlin noise.  Combined with forest groups, this can be used to organize a forest into tree stands of one group of trees or another.

HEIGHT_PARAMS <dist 1> <amp 1> <dist 2> <amp 2> <dist 3> <amp 3> <dist 4> <amp 4>

[New to 1000:] this changes the randomization of height from truly random tree height variance to perlin noise, which can create clusters of height changes.

NO_SHADOW

[New to 1005:] this disables shadow casting for the forest.

TREE2  <s1> <t1> <w> <h> <sw> <percent> <min_height> <max_height> <nominal_height> <lod_far> <quads> <type> <notes>

[New to 1200:] like the TREE command, but it has 2 additional parameters. Nominal_height is the height of an unscaled tree. This is used to scale 3-d trees and billboard trees to the same height. Lod_far works just like the LOD command, but is specific to this one tree instead of overriding the far LOD globally.

MESH <name> <lod near> <lod far> <vcount> <idx count> <bend_scale> <max_displacement> <displacement_speed> [<NO_SHADOW>]

[New to 1200:] Starts a new 3D mesh with the given name. The near and far LOD values are the LODs for when to show and hide the mesh. X-Plane will blend between multiple LOD steps, but will always have the mesh fully faded in when lod_near meters away from the camera and fully faded out when lod_far meters away from the camera.

vcount and idx count are the number of vertices and indices in the 3D mesh, which will have to be specified using the VERTEX and IDX commands directly following the MESH command.

Bend_scale, max_displacement and displacement_speed are all parameters used to implement bending in the wind for 3-d trees. The bend_scale is the scalar value for the overall bendiness of the tree: at 0.0 the tree will resist bending in the wind completely. The max_displacment is the maximum amount of horizontal displacement the tree will experience while the displacement_speed is a scalar on the wind speed, which can be used to make trees that are resistant to bending in small wind speeds.

The NO_SHADOW parameter can be optionally defined and will prevent a mesh from casting shadows. This is useful when building small clutter objects with the vegetation system without increasing the computational burden too much. Please note that the .for file system is NOT suited to implement lots of ground clutter objects or grass systems, and performance and VRAM usage will suffer as a consequence. Small meshes are not well suited for the forest system!

VERTEX <x y z n n n s t w w w>

[New to 1200:] Must come after a MESH command and defines a vertex of the tree. xyz is the vertex position, nnn is the normal and s t is the UV coordinates of the texture used by the 3D material. The w w w parameters specify additional vertex weights that affect the displacement, branch attenuation and tree phase in that order.

The displacement value is single scalar defining how much the vertex is affected by the overall displacement of the tree. Leaves and branches tend to have high value for the overall displacement while the trunk tends to have a smaller displacement value.

Branch attenuation is the amount of flutter the vertex experiences in its movement in the wind. This value should be quite high for leaves and very close to or 0 for branches and the trunk.

Phase is the overall phase of the wind animation. Since the animation is derived computationally, giving different branches and leaves a different value here will make it so that the whole tree doesn’t move as if it were a single object.

IDX <n …>

[New to 1200:] Must come after a MESH command. Describes the index of the vertex to be used. More than one index can be specified at one time.

MESH_3D <name>

[New to 1200:] Must come after a TREE or TREE2 command. A single tree always starts with a TREE or TREE2 command describing the overall parameters of the tree. When followed by one or more MESH_3D parameters, the tree becomes an X-Plane 12 style 3-d tree. Each MESH_3D command defines an additional LOD step.

In practice your file will look something like this:

MESH foo_name …

VERTEX …

IDX …

TREE2 …

MESH_3D foo_name

SHADER_2D

[New to 1200:] Subsequent commands will affect the 2D shader.

SHADER_3D

[New to 1200:] Subsequent commands will affect the 3D shader.

EXAMPLE FILE

A

800

FOREST

# Conifer cold wet

#This tells us the bitmap that will be used for these trees.

TEXTURE forest.png

#This tells us how far away trees disappear – in this case 5 km.

#(This is a bit too soon – 10 km or 20 km looks better.)

LOD 5000

#This defines the texture size for the coordinates given below.

SCALE_X 1024

SCALE_Y 1024

#Tree spacing: place a tree and shrub every 20 meters.

SPACING 50 50

#Vary their placement by up to 10 meters in any direction.

RANDOM 20 20

#low-left coord tex size center percentage    —-height—-

# tree  s         t         w         y         offset occurrence            min          max          quads         type         name

#—————————————————————————————————

TREE         44        896        52        127        25        12.5                10        28        1        1        connifer 1

TREE         194        896        44        127        22        12.5                10        28        2        1        connifer 2

TREE         238        896        65        127        32        12.5                10        28        1        1        connifer 3

TREE         443        896        66        127        33        12.5                10        28        2        1        connifer 4

TREE         584        896        77        127        39        12.5                10        28        1        1        connifer 5

TREE         712        896        62        127        32        12.5                10        28        2        1        connifer 6

TREE         777        896        61        127        29        12.5                10        28        1        1        connifer 7

TREE         840        896        72        127        36        12.5                10        28        2        1        connifer 8

SKIP_SURFACE water

Comments Off on Forest (.for) File Format Specification

OBJ8 (.obj) File Format Specification

This is the OBJ8 File Format Specification, (c) 2005-2022 Laminar Research, All Rights Reserved.

Revision History

11/09/22    Added X-Plane 12 TEXTURE_MAP info
11/03/21    Added new X-Plane 12 attributes including rain and lighting
01/11/21    Added note about plugin objects and ATTR_hard/_deck
11/12/20    Clarified ATTR_cockpit_device and panel texture mode further
11/05/20    ATTR_cockpit_lit_only added, panel details sections updated
09/23/20    Clarification on LIGHT_SPILL_CUSTOM's dref parameter
09/14/20    Deprecated smoke_white/black
01/07/20    One more LOD rules clarified, formatting updated
06/11/19    More details about ATTR_shadow and GLOBAL_no_shadow
04/29/19    Added previously undocumented SCENERY_SHADOWS conditional and ATTR_shadow details
02/04/19    Clarified SLOPE_LIMIT degree limits
01/31/19    Clarified LOD rules
01/29/19    Added MAGNET directive
10/15/18    Added PARTICLE_SYSTEM and EMITTER directives, some formatting
09/28/18    Fixed typos and adds that ANIM_rotate and ANIM_trans's dataref is optional
02/22/18    Fixed typo in ATTR_manip_command_xxx manipulators
11/17/17    Updated for X-Plane 1110
07/12/17    Updated for X-Plane 1100
10/16/16    Updated for X-Plane 1050
07/31/12    Updated for X-Plane 1010
03/14/12    Updated for X-Plane 1000
12/03/09    Added normal maps and parameterized lights for 940
06/16/09    Added new manipulators for 930b13
04/28/09    ATTR_light_level edited
04/06/09    Fixed Typos
02/04/09    Updated for X-Plane 930
09/25/08    Updated for X-Plane 920
12/26/07    Updated for X-Plane 900
04/05/07    Clarified use of custom lights
07/12/06    Revised for X-Plane 850
09/16/05    Initial Draft

Change History

The initial OBJ8 format was supported starting in X-Plane 816. X-Plane 850, 900, and 920 extended the format.

Changes for 1200

  • New ATTR_hud_glass/_reset directive
  • New Rain and Thermal directives
  • v12 GLOBAL_luminance and photometric directives

CHANGES FOR 1130

  • New PARTICLE EMITTER support, MAGNET point VR support

CHANGES FOR 1110

  • New VR-friendly manipulators: ATTR_manip_command_knob2, ATTR_manip_command_switch_left_right2, ATTR_manip_command_switch_up_down2, ATTR_manip_drag_rotate, and ATTR_axis_detent. Added MAGNET (but mistakenly forgotten to put into the spec until after the release of 11.30)
  • ATTR_cockpit_lit_only added

CHANGES FOR 1100

  • NORMAL_METALNESS and BLEND_GLASS added
  • ATTR_cockpit_device added

CHANGES FOR 1050

  • New manipulators and manipulator mouse wheel support.

CHANGES FOR 1010

  • ATTR_no_shadow and GLOBAL_no_shadow can be used to turn off shadowing on a per-batch or per-object basis.
  • GLOBAL_cockpit_lit can be used to get translucency with the cockpit texture and correct lighting.
  • ATTR_manip_drag_axis_pix provides non-linear pixel-space dragging.

CHANGES FOR 1000

X-Plane 10 introduces a number of major new features:

  • Draped geometry.  An object can contain a second shader definition and geometry that is draped onto the scenery in the same coordinate reference system as the object itself.
  • Global state.  Object draw state can be declared to be global to the entire object.  When this happens, the state is factored across the entire object.  For a scenery with a large number of objects with common state, this can improve performance greatly compared to traditional ATTRibutes.
  • Extra meta-data.  The OBJ format has a number of meta-data items in the header that interact with the library.
  • Custom spill: while spill lights are supported with the X-Plane 9 parameterized and named light scheme, it is also possible to build a fully customized spill light.
  • Additive LOD.  It is possible to create LODs within the object that are drawn at the same time (e.g. the detail is added to the base mesh), saving memory and improving performance.
  • Shadow blending: a new blending mode provides blended behavior for drawing but non-blended behavior for shadows.
  • Instancing: the X-Plane 10 OBJ engine supports instancing under some conditions.  This spec will note features that are and are not instancing compatible.
  • In X-Plane 10, objects support conditional directives – see the beginning of the syntax section.

CHANGES FOR 940

The following features are available in X-Plane 940:

  • TEXTURE_NORMAL for attaching noraml and specular maps to an object.
  • LIGHT_PARAM for customized lights.

CHANGES FOR 930

The following features are available in X-Plane 930:

  • ATTR_light_level and ATTR_light_level_reset
  • ATR_draw_enable/disable
  • ATTR_solid_camera/no_solid_camera

CHANGES FOR 920

The following features are available in X-Plane 920 and later.

  • Manipulators

CHANGES FOR 900

The following features are available in X-Plane 9 and later.

  • Key Frames
  • Panel Regions
  • Deck-style hard surfaces

CHANGES FOR 850

The following features are available only in X-Plane 850 and later.

  • Custom and named lights.
  • Layer groups.
  • More control of blending and hard surfaces.
  • Show/hide animation commands

OBJECT CONCEPTS

FILE TYPE AND COMPATIBILITY

X-Plane 8 and 9 object files (OBJ8) are text files that consist of records (one per line) describing a single 3-d model.

OBJ8 is not meant to be forward compatible; it is assumed that when the file format is extended, readers written to this specification will not be able to meaningfully display the future model file (which may depend on new features).

OBJ8 is meant to be backward compatible; it is assumed that readers of a future OBJ8 revision will continue to read current OBJ8 files.

COORDINATE SYSTEM AND GEOMETRY

OBJ8 models are specified in meters. In their native orientation, the positive Y axis points up, the positive X axis points east, and the positive Z axis points south. (This is a right-handed coordinate system.) The point 0,0,0 is a point on the ground where the object has been placed in x-plane scenery. The X-Plane scenery file referencing the object may rotate the object clockwise around the Y axis.

STATE, COMMAND

An X-Plane 8 OBJ model is specified via commands, which build the model in a certain order. There are four kinds of fundamental commands:

  • Geometry commands create geometry, to be drawn in the order they are created.
  • State commands affect how future geometry is drawn.
  • Action commands have an affect on the sim.
  • Animation commands change the shape of the subsequent geometry in real-time.

State has ‘memory’. For example, all geometry is drawn with only the front visible, until you set the drawing state to “two-sided mode”. At this point, all geometry is drawn with both sides visible until the drawing state is set to “one-sided” mode again.

State change is more than just a way to specify how to draw certain geometry; state change actually affects drawing performance in the simulator. The simulator must stop bulk-drawing geometry to change state, so minimizing the number of state commands will generally improve performance.

Because X-Plane does not reorder geometry commands it is up to the writer to maximize performance by minimizing state commands within the scope of the flexibility of geometry order. Generally speaking, the number of commands (not counting the various tables) is a good proxy for the efficiency of your object–fewer commands is more efficient.

Objects also have global properties; these do not interact with the mesh and have no ordering – they are simply meta-data for the object.  For example, the textures that are applied to the object are global properties.

TABLES

The geometry data (locations, texture coordinates, normals, etc.) for an OBJ8 model are stored in tables, separate from the command section. Table data may be shared in any order desired by the author.

There are three separate geometry tables for triangles, lines, and point lights. There is also a separate index table that provides index numbers into the geometry or line tables for lines and lights. This second level of indexing allows a contiguous range of indices to refer to a smaller set of shared points. A single triangle command then dispatches a contiguous index range. Lights are not indexed; the light command refers directly to consecutive light table points.

GLOBAL PROPERTIES

Global properties refer to properties global to the entire object.  For example, the object’s textures and weight are all global properties.  They do not apply to any one part of the mesh.

OBJ7 NOTE: unlike OBJ8, night lighting is not automatically loaded by looking for a _LIT file. A light map must be specifically indicated.

LEVEL OF DETAIL

An OBJ8 model consists of one or more “level of detail”. A level of detail can be thought of as a fully self-contained independent model within the object that shares all of the table data and attributes of the OBJ8 model. At any one time, only one LOD is ever drawn.

LODs are specified for ranges in meters (this range is the range of the viewer to the object). This allows you to change the appearance of an object to a simpler model when viewing from far away.

State is fully independent for LODs. In other words, if you set two-sided drawing in one LOD, the first triangle in the next LOD will be one-sided again automatically.

If you do not specify any LODs, the entire model is treated as a single LOD, whose range is calculated automatically by X-Plane.

X-Plane 10 features two methods of LOD:

  • Selective LOD.  X-Plane will draw the one LOD whose range brackets the camera distance.  LOD distances must be consecutive from closest to farthest.
  • Additive LOD.  X-Plane will draw every LOD whose range brackets the camera distance.  LOD distances must all start from zero and be ordered from closest to farthest.

ANIMATION

With OBJ8 it is possible to animate models. Animation is done by specifying transformations of ranges of geometry.

Animation is specified by pairs of begin/end animation commands. These commands may be nested to form hierarchical animations. Zero or more rotation and translation commands may be used in each nesting level.

Animation is driven by datarefs. A dataref is a flight simulator variable with a published well-known string name. 1100+ datarefs are defined by X-Plane and listed on the X-Plane SDK website; plug-ins can also create additional datarefs that can drive animation. Animation commands allow for a scaling of datarefs to convert easily from the native units of the sim to ranges that are useful for animation.

To calculate the extent of a translation or rotation, X-Plane finds a pair of key frames, or dataref/animation pairs, and then interpolates between the appropriate pair. Values that are not between any pairs are extrapolated from the nearest pair.

X-Plane 8 only allows for two key frames (a “start” and “end”). X-Plane 9 allows for two or more key frames.

MANIPULATION

A manipulation is an action taken by a user on an object that changes the state of X-Plane. By setting the manipulation state, you define what clicking on triangles within an object accomplishes. Manipulations interact with animations under certain conditions.

The current manipulation is changed via manipulator commands, which are a form of state command; any given triangle can only have one manipulation associated with it.

X-Plane 920 supports the following types of manipulations:

  • No Manipulation. If a mesh section is tagged as having no manipulation, it is not processed for click testing. The mouse clicks go “through” those triangles. This is the fastest manipulation – all other manipulations consume per-CPU resources.
  • Panel Texture Manipulations. A click to the triangle causes a click to the 2-d or 3-d panel, with the texture coordinates “mapping” where the click takes effect. Click locations are undefined if the panel texture is not in use. (In practice, this manipulation is never available on a non-panel-textured triangle, due to the OBJ file syntax.) The mapping correctly maps through both ATTR_cockpit and ATTR_cockpit_region.
  • XY Drag Manipulations. Two datarefs are changed based on the drag distance along the X and Y axis in screen space. This is primarily provided for 2-d controls like yokes.
  • Axis Drag Manipulations. A dataref is changed based on a drag along an arbitrary object-space axis. The axis is “locked” at the moment of click, so changes to the drag location (in object space) due to the pilot’s head turning or due to animations do not affect the axis. Effectively at the instant of click-down the axis is converted from 3-d to 2-d pixels on screen and left that way. This provides a more predictable drag experience for users.
  • Command Manipulations. Clicking on the mesh section causes a command to be actuated while the mouse is down.
  • Command Axis Manipulations. Dragging along either dimension of an arbitrary object-space axis invokes one of two commands, depending on the drag direction.
  • No-Op Manipulations. No action is taken, but this manipulator “blocks” the click, so that no further mouse processing is done. This makes triangles “solid” for mouse clicking.

X-Plane 930 adds the following “dataref” manipulators (that is, manipulators that change a dataref in response to a click):

  • Push button. The dataref is changed on click, and then on release.
  • Radio button. The dataref is changed on click by multiple manipulators.
  • Toggle button. The dataref is changed on click between two different values.
  • Delta. The dataref is changed slightly on click or hold, with limits on total range.
  • Wrap. The dataref is changed slightly on click or hold, and wraps around when out of range.

X-Plane 10.10 adds the following manipulator:

  • Drag-Axis.  The dataref is increase by dragging to the right or up (user’s choice) and decreased by dragging to the left or down.  The travel of the drag is specified in pixels, and it can be set for non-linear response (slow changes with small movements, and disproportionately large changes with big movements.

X-Plane 10.50 adds the following new manipulators:

  • Command knob/switch manipulators.  These manipulators run a pair of commands as the knob/switch is moved up and down.
  • Dataref knob/switch manipulators. These manipulators provide similar functionality to the command manipulators, but using datarefs for the case where commands don’t exist.  The command manipulator is preferred.
  • A wheel attribute can be added to existing manipulators to allow the mouse wheel to affect them.

X-Plane 11.10 adds the following new manipulators:

  • 2-position knob/switch manipulators.  These manipulators take a single command that toggles in the sim, but they semantically describe a motion (rotating, moving up/down and left/right).  They are designed to let simple toggle-based two-position switches work in VR.
  • Rotation manipulator (with optional detents) – this models a rotating handle like a throttle quadrant.
  • Detents on linear axes – a detent can be added ‘to the side’ on a linear axis, e.g. like a Cessna flap lever.

Manipulations are affected by the animation commands that surround them – that is, if an axis manipulation is inside a rotation, the axis will rotate based on the rotation.

Manipulations also take into account the animations on the triangles that are clicked. This includes all animations that affect the triangle. In other words, if you set a command manipulation, draw some triangles, then animate and draw more triangles, both groups of triangles are click-tested, and the click-test location will match the animation, even though the animation is after the beginning of the manipulation. (In other words, mouse click testing always matches drawing.)

OBJECT GEOMETRY TYPES

The fundamental geometry types for OBJ8 are:

  • Triangles. Triangles are textured and have a normal defined per vertex for lighting purposes. The front of the triangle is the face where the vertices appear in clockwise sequence.
  • Lines. Lines have an RGB color.
  • Lights.While RGB lights are possible, named lights are strongly recommended.

OBJ7 NOTE: RGB values in OBJ8 are always from the scale 0-1, even for lights and lines. This means the special light commands map to 9.9, 9.8, etc. instead of 99, 98.

MESH PLANES

Conceptually an object has four “planes” of information that a triangle can be part of:

  • Drawing plane – the user can see the triangle. All triangles normally are in the drawing plane.
  • Physics plane – the triangle causes collisions in the physics engine. Authors put a triangle in the physics plane with ATTR_hard, etc.
  • Manipulation plane – the triangle can be clicked with the mouse. Authors put a triangle in the manipulation plane with a manipulator or ATTR_cockpit. Only triangles in the cockpit object can be in the manipulation plane.
  • Camera plane – triangles will impede the movement of the 3-d camera. Authors can put a triangle in the camera plane to constrain where the user can look in 3-d. Only triangles in the cockpit object can be in the camera plane.

A triangle can be in no planes, or more than one plane. Attributes are used to control whether triangles go to each plane.

The choice of which plane a triangle is in is static. Planes are different from hide animations; a triangle hidden by a hide animation is hidden from everything – physics, drawing, clicking, and camera movement. Planes are provided to allow authors to use different geometry for camera constraint, clicking, physics and drawing.

Lines, lights, and smoke puffs do not ever go in the physics manipulation or camera planes. Therefore it does not make sense to include them in a non-drawn part of the OBJ file.

Some example uses might illustrate the motivation behind multiple planes:

  • A manipulatable triangle can be made non-drawable, allowing an author to place large, easy-to-click “hot-spots” in front of the mesh of a switch that might otherwise be hard to click due to its shape.
  • An author can make a separate mesh to constrain the camera that is not drawn–this separate mesh can be water-tight, much lower in triangle count, and be inset from the walls a bit to keep the camera from getting into strange places.

[New in 1000:] Draped geometry does not sit in the “mesh planes” it is essentially separate geometry carried along for draping purposes.

DRAPING

For scenery objects in a DSF, X-Plane can “drape” the triangles in the mesh onto the ground.  During the draping process, triangles are subdivided as necessary to ensure that the triangle can be coplanar with the ground (even if the ground is not flat).  The subdivided triangles are then moved verticaly at each vertex to make the entire mesh coplanar with the ground.  The draped triangles are drawn with polygon offset to ensure perfect tiling; in this way triangles can be drawn over the ground even if it is not flat.

Draped triangles effectively exist “outside” of the object – that is, they ignore all attribute state, have their own global properties, and are not subject to the main LOD system.  The triangles are specified within an LOD in the file, but that is only for syntax reasons.

OBJECT STATE

OBJ8 defines and tracks the following object state:

  • [deprecated] Flat/Smooth shading (default is smooth). In flat shading, the entire triangle is drawn with the same brightness. In smooth shading, the corners of the triangle have the shading levels appropriate for their normals, and the interior is interpolated. Note that since flat shading can be simulating via per-vertex normals, it is usually better to only use smooth shading. (Flat shading is deprecated – flat shaded geometry should be created by creating vertices with the face normal in the modeling command; the extra vertex count is less costly in performance than the attribute.)
  • [deprecated] One-sided vs. Two-sided geometry (default is one-sided). With one-sided geometry, a triangle is only drawn if the front of the triangle is visible to the user. With two-sided, both sides are drawn.  It is often optimal to double geometry to avoid small groups of two sided geometry in a one-sided object. (Two-sided drawing is deprecated; modeling exporters should duplicate the geometry with flipped orientation and normals – this ensures the lighting queues on the back side of geometry are not wrong.  Again, the duplication of vertices is cheaper than the attribute!)
  • Panel vs. object texture (default is object). Normally triangles are textured via the texture (and light overlay) named in the TEXTURE and TEXTURE_LIT attributes. When panel texture is turned on, the plane’s 2-d panel is used as a texture.  The lighting model for panel texturing may be “flat” (meaning no lighting calculations are provided) or “real” (meaning the full 3-d lighting system is used, matching the rest of the object); which lighting system is invoked depends on which attribute is used to select panel-texture drawing.
  • Polygon offset amount (default is 0). This is an amount to draw your geometry above the terrain, with zero being none and one being the minimum amount above the terrain that can be represented by the OpenGL hardware. The object is not drawn differently in its position; this offset is only used to make the decision about whether your object appears “on top of” the terrain in a two-dimensional flat screen sense.  [New in 1000:] draping provides an alternative to polygon offset.
  • Blend off/on/shadow (default on). Normally an alpha pixel in the object texture that is neither fully opaque nor fully transparent is drawn as translucent with the background showing through. However this can cause artifacts in some conditions. When blending is turned off, all alpha values above a fixed alpha percent are treated as fully opaque and all alpha values below that alpha percent are treated as fully transparent.  [New in 1000:] In shadow mode, shadows are not blended but primary drawing is; this is available only in XP1000.  The cutoff ratio for non-blended geometry can be altered with state commands.  NOTE: even if a bitmap has only fully opaque or transparent pixels, some may be rendered translucent due to the effects of interpolation as a texture is resampled.
  • Polygon physical properties (default is none). Normally triangles in an OBJ8 model do not interact with the X-plane physics model; when this state is on, they do. Doing physics calculations against triangles can be slow for large numbers of triangles, so do not simply turn this on for every object. [New in 850:] Starting with X-Plane 850 you can specify the type of physical surface for geometry. Before 850, the choice was simply physical or not. [New in 900:] Starting with X-Plane 900 you can specify a hard surface to be a “deck”, meaning the user can fly under it or land on top of it. Before 900 only “solid” physical surfaces were available–flying under a solid physical surface counts as a collision.
  • Materials. You can change the balance of color contributions from the lighting model for your geometry. Those parameters are:
    • [deprecated] Diffuse (RGB) – the brightness of the geometry due to the sun.
    • [deprecated] Emissive (RGB) – the brightness of the geometry due to it radiating light.
    • [deprecated] Shininess (RGB) – the sharpness of specular highlights (0-1).

(It is strongly recommended that albedo and emissive color changes be made using the day and lit textures and not these material attributes!  Texturing is very cheap and usually already necessary; attribute changes are expensive.  Shininess can be set by globally setting specularity to 1 and using a gray-scale or RGBA normal map to set per-pixel specularity.)The relationship between these colors and OpenGL: the diffuse color sets the diffuse and ambient OpenGL colors. The emissive color maps to the emissive OpenGL color. The shininess ratio sets all three components of the specular hilight color with a specular exponent of 128. The defaults are full diffuse, no shininess and emissive, but use ATTR_reset to restore the default lighting properties for X-Plane.

  • [New in 920:] The current manipulation.
  • [New in 930:] Enable/disable state for the drawing and camera planes.
  • [New in 1010:] Whether shadow-casting is enabled/disabled.

TEXTURE APPLICATION

X-Plane’s lighting/texturing model consists of separate albedo and emissive inputs. An X-Plane object can reference three textures:

  • The “daytime” (albedo) texture for the object, specified via the TEXTURE command. This command is mandatory – if the texture name is blank, a gray proxy texture is used.
  • The “_LIT” (emissive) texture for the object, specified via the TEXTURE_LIT command. This command is optional.
  • A normal map, specified by TEXTURE_NORMAL. The normal map is optional, and is ignored unless the user has enabled per-pixel lighting. The normal map contains specular strength in the alpha channel.

Normally these three textures are used to texture triangles. When ATTR_cockpit_region or ATTR_cockpit is used, the panel, the panel replaces the albedo and emissive textures, and normal mapping is disabled. When ATTR_cockpit_lit_only is used, the panel replaces only the emissive texture (which is useful for computer screens).

When ATTR_cockpit_device is used, the image of the screen for that GPS device replaces the lit texture; the albedo and normal map are retained from the object itself. ATTR_cockpit_device is not a seperate panel mode. The same .obj can have ATTR_cockpit_devices and use of the panel texture

For more information on Normal Map format and application, see: Normal Maps.

[New in 1100:] NORMAL_METALNESS can be appended after a TEXTURE_NORMAL or TEXTURE_DRAPED_NORMAL directive to set the texture to use the blue channel to set base reflectance (how much light is reflected off of the surface at an orthogonal angle). See the X-Plane 11 Material Model for more..

IMPORTANT: the shininess level in the normal map alpha channel is modulated by the input to ATTR_shiny_rat/GLOBAL_specular, which defaults to 0.0. Thus you must use ATTR_shiny_rat to see the effects of the alpha channel in a normal map.

OBJECT GLOBAL PROPERTIES

X-Plane 9 objects have only a few properties: the texures used for albedo, emissive, and normal/specular, and the weight of the object.

X-Plane 10 introduces a large number of new global properties:

  • A second set of textures (albedo/emissive/normal+specular) for draped textures.  If these are not specified, the object textures are used.
  • LOD and layer group properties for draped geometry.
  • Tinting for instancing.  These are ratios to vary the albedo color and emissive level on a per-instance basis to add variation to instanced objects.
  • Slope-limit.  This allows the sim to eliminate library object choices during placement based on the slope of the ground.
  • Wet/dry requirement.  This allows the sim to eliminate library object choices during placement based on the underlying surface.
  • Tilting.  This declares that the object tilts to be normal to the ground (e.g. the Y axis is normal to the ground, not facing the gravity vector).

With X-Plane 10, the following state can be set globally as a global property on the object.  This effectively changes the state of the object as it begins.  State that can be set:

  • Blending (GLOBAL_no_blend/GLOBAL_shadow_blend/ATTR_no_blend/ATTR_blend/ATTR_shadow_blend).
  • Specularity (GLOBAL_specular, ATTR_shiny_rat).

With X-Plane 11, another blending change can be set, BLEND_GLASS. BLEND_GLASS makes an object’s glass to make the diffuse channel translucent while keeping specular effects, for reflections on clear glass. Read more about it in X-Plane 11’s Material Model.

COCKPIT FEATURES

The OBJ format is used to model objects that are part of airplanes, part of the cockpit environment, and part of the scenery system. Some features are only appropriate to the cockpit.

Cockpit features can only be used in objects that are attached to the object as the “cockpit object”–this object undergoes special processing. Other attached airplane objects and scenery objects cannot use these features.

Panel Texture

Changing the object texture to the “panel” texture does two things: it changes the texture used to draw from the OBJ’s texture (specified with the TEXTURE command) to the 2-d panel.  There are a number of ways to use the cockpit texture; the following table summarizes them.

The panel texture can be accessed by ATTR_cockpit, ATTR_cockpit_lit_only, or by using ATTR_cockpit_region with one or more COCKPIT_REGION definitions in the header of the OBJ file.  Optionally GLOBAL_cockpit_lit can be added to either directive.  The following table summarizes the effects of the various command combinations:

ATTR_ cockpit cockpit_region cockpit cockpit_region cockpit_lit_only
Use Regions No Yes No Yes No
GLOBAL_cockpit_lit No No Yes Yes Yes
Transparency Yes No Yes Yes Yes
Power of 2 Not Required Required Required Required Required
3-d Lighting No Yes Yes Yes Yes
Min Version 8.x 9.x 10.x 10.x 11.1x

(cockpit and cockpit_region listed twice to show historical changes.)

  • Use regions: do you need to define cockpit regions to use this attribute, or is the entire panel used?
  • Transparency: will translucent areas of the panel appear translucent in the object?
  • Power of 2: must the region or panel be a power of 2 in dimension.
  • 3-d Lighting: will the texture region be lit in 3-d by spill lights and the sun?
  • Min Version: the minimum version of X-Plane supporting this combination of attributes.

[New in 1010:] GLOBAL_cockpit_lit can be used to induce 3-d lighting even on non-region ATTR_cockpit. This provides authors a way to use translucency and 3-d lighting at the same time.

[New in 1100:] As of X-Plane 11, the sim always acts as if GLOBAL_cockpit_lit is present.

[New in 1110:] GLOBAL_cockpit_lit also now works with ATTR_cockpit_lit_only

Cockpit Regions

[New in 900:] Instead of using the entire cockpit panel as a texture (using ATTR_cockpit), an object can establish up to four cockpit “regions”. These are textures defined by a sub-rectangle within the 2-d cockpit. Cockpit regions differ from using the full cockpit as follows:

  • Cockpit regions must be a power of 2 in width and height.
  • There can be up to four cockpit regions.
  • Cockpit regions are not transparent–if the 2-d panel is transparent, the cockpit region texture in that area is undefined.

Cockpit regions are recommended for efficiency reasons: between the use of transparency, non-power-of-2 panels, and the huge amount of a 2-d panel that is not useful for rendering, the 2-d panel ends up using a lot more VRAM and building a lot more texture area dynamically than necessary. By simply using a few smaller cockpit regions over key parts of the 2-d panel, greater frame rate can be achieved.

OBJECT SYNTAX

OBJ8 files are ASCII text files; the legal character set is the set of printable 7-bit ASCII files.

Lines are defined by newline character sequences, which are one of:

  • Macintosh: a single CR (13)
  • Unix: a single LF (10)
  • DOS: a CR followed by an LF

Any one choice of newline sequences may be used consistently throughout the file.

One or more Tabs (8) and/or spaces (32) are treated as white space.

A sequence of legal characters that does not contain any newlines may be referred to as a line, and a sequence of legal characters that does not contain any newlines or whitespace may be referred to as a word.

Word and keyword identification is case-sensitive. Numbers are represented by an optional minus sign, one or more digits, optionally followed by a period and one or more digits. All numbers in objects may be floating point.

The object file consists of a 3-line header followed by a series of records, each of which is one line. A record’s type is identified by the first word of the record. Blank lines are legal after the header, and records starting with a # are treated as blank lines, allowing for comments.

The header lines consist of:

  • Line 1: either the characters A or I – it is recommended that A be used for Macintosh line ending files and I for Unix or DOS line ending files.
  • Line 2: the file version number (currently 800) followed by optional whitespace and additional comment characters.
  • Line 3: the word OBJ.

Each single-line record is identified by its first word; see the command listing below for precise record descriptions.

Coordinates are specified as a triplet of numbers representing XYZ Cartesian coordinates in meters.

Normals are specified as a triplet of fractions forming a 3-space vector whose length is 1. The vector is interpretted in the same coordinate space as the geometry.

Texture coordinates are specified as a pair of fractions from 0-1. The first one represents a ratio from the left to the right side of the texture, the second from the bottom to the top.

Colors are represented as fractions from 0-1 representing minimum to full color intensity. Colors are usually RGB triplets.

OBJECT SEMANTICS

Records fall into three categories: attributes, data, and commands. The order of the file must feature all attributes first, then all data, then all commands. Attribute records can be in any order. Data record types can be in any order, but ordering within a type of data record defines the indexing interpretation. Commands are executed in the order of the records in the file and are never re-ordered at any point (allowing for certain translucency and authoring tricks).

LODs

An OBJ may optionally feature LODs in one and only one of two modes: Selective LOD or Additive LOD mode. The LOD feature is turned on by using one or more ATTR_LOD directives. An OBJ’s ATTR_LODs must follow these rules:

  • The first (or only) ATTR_LOD must be the first command record
  • The near value of the first (or only) ATTR_LOD must be 0
  • All LODs must be ordered from nearest to farthest
  • If every ATTR_LOD’s near value is 0, the OBJ is using Additive LOD mode. Otherwise the OBJ is in Selective LOD mode.
  • An object must be exclusively Additive or Selective, no switching is allowed
  • If using Selective mode, each ATTR_LOD’s near distance must match the previous ATTR_LOD’s far distance (or be 0 for the first ATTR_LOD). No overlaps or gaps between ranges are allowed
  • No ATTR_LOD’s near and far can be equal

All possible optimizations are applied regardless of whether or not an OBJ has LODs. There is no requirement for an object to reset state to its initial setting at the end of an LOD; the simulator takes care of this.

All animation commands must be within an ANIM_begin / ANIM_end pair.

All ANIM_begin/ANIM_end pairs must be properly balanced within each LOD.

Animation commands (ANIM_rotate and ANIM_trans) must occur immediately after ANIM_begin. However any number of animation commands may be used consecutively after a single ANIM_begin.

The POINT_COUNTS and TEXTURE attributes are required.

Hard polygons are not allowed in any LOD except for the first one.

Cockpit features (panel texture/panel regions, manipulation, camera plane enable) can only be used in objects that are attached to an airplane via the COCKPIT_INN.obj or COCKPIT_OUT.obj mechanism.

[New in 900:] Key frame tables must be listed from lowest to highest key frame dataref value.

This is not required, but it is recommended: if your object has lights and multiple LODs, use the exact same lights in each LOD. X-Plane’s OBJ engine does special processing on lights to both increase the distance at which they are visible and improve framerate. If the lights specified in each LOD are different, you may either get incorrect drawing, or lower framerate. The fastest code path is to let X-Plane do the same lights at every LOD.

Conditionalization

[X-Plane 1000:] X-Plane 10 supports the conditionalization of OBJ files.  Conditionalization is a process whereby the contents of a file are skipped or used depending on rendering settings.  Typical uses of conditionalization are to change the appearance of an object when shadows are enabled, or when HDR is on.

Conditionals for OBJs occur in the form of these commands:

IF <var>
IF NOT <var>
ELSE
ELSE IF <var>
ELSE IF NOT <var>
ENDIF

The file lines inside the conditions are only used when the variable is true (or false).

The variables supported in X-Plane 10 are:

GLOBAL_LIGHTING – True when HDR mode is on

GLOBAL_SHADOWS – True when any level of global shadowing is enabled. At this level airplanes have shadows, scenery may or may not

SCENERY_SHADOWS – True when GLOBAL_SHADOWS is true and scenery is shadowed

VERSION10 – Always 1.  Since conditionals are not supported in v9, you can put v9 only art in place using IF NOT VERSION10.

Note: conditionals do not use datarefs!  The conditionals change the nature of the file once at load time, and the file is reloaded when rendering settings change.  This has two key implications:

  1. Conditionals are not useful for real-time or dynamic changes/tricks.  You cannot, for example, change textures with a dataref using this feature.
  2. Since conditionalization happens on load, there is no penalty for using an attribute that is conditionalized out.  For example, if you use ATTR_emission_rgb for night lighting only when global lighting is off, this attribute effectively does not exist when lighting is on, and thus with lighting on your object has no attributes and will hit the fast path for code.

GLOBAL PROPERTY RECORDS

Global property records define the overall properties of the entire object.  Besides a few bits of meta-data (e.g. how much does the object weigh) global properties can set the default shader state for the entire object.

Optimization Note: global properties set the default shader state of the object, and therefore they had different performance characteristics than the regular ATTR commands, which only set an attribute for part of a mesh.

  • Global attributes are hardware-instancing friendly.
  • Global attributes force another shader-layer into the overall scene-graph.
  • Do use global attributes when you do not need any other ATTRibutes.  For example, if an entire object is ATTR_no_blend, it is often a good idea to use GLOBAL_no_blend.
  • Do not use global attributes if you need multiple attributes.  If an OBJ ping-pongs between ATTR_blend and ATTR_no_blend, the global attribute isn’t any help – you still are stuck with two draw calls and no hardware instancing.
  • Global attributes are superior to ATTRibutes when an object is used multiple times in a DSF.
  • Global attributes are not superior to ATTRibutes when an object is used only once.

Special notes for GLOBAL_no_shadow: GLOBAL_no_shadow cannot appear in the same file as ATTR_shadow and it can appear in non-instanced scenery files.

GLOBAL_luminance <nts>

[New in 1200:] Sets the nits value for the lit texture used for rendering.

PARTICLE_SYSTEM <particle_file_path>

[New in 1130:] The .pss file that defines particle systems for EMITTERs in this OBJ. If particles are used, a particle system file must be provided. An OBJ with a PARTICLE_SYSTEM directive but no EMITTERs results in a warning, not an error. Only one PARTICLE_SYSTEM per OBJ is allowed.

TEXTURE <tex_file_path>

This defines the texture to be used with this object. Use this record with only white space to indicate that the object has no texture requirement.

TEXTURE_LIT <tex_file_path>

This defines the lighting overlay. Omit this record if you do not require a lighting overlay.

TEXTURE_NORMAL <tex_file_path>

[New in 940:]This defines an additional texture to be used as a specular + normal map. See “texture application” above for the formats of texture and normal maps.

TEXTURE_MAP <usage> <tex_file_path>

[New in 1200:] Provide a texture file with a given usage. Valid usages are normal, material_gloss, gloss.  The channels of each texture are interpreted depending on usage. TEXTURE_MAP cannot be used with TEXTURE_NORMAL.

Usage Red Green
normal Normal X Normal Y
material_gloss Material-dependant gloss
gloss gloss Ignored

WEATHER SYSTEM

RAIN_scale <ratio>

[New in 1200:] Scales the visual output of rain to match texture resolution.

THERMAL_texture <tex_file_path>

[New in 1200:] Texture file of condensation pattern on windshield. Max 1 per OBJ

THERMAL_source <temperature_dataref> <toggle_dataref>

[New in 1200:] Temperature dataref controls the temperature output of the heater. Toggle dataref controls if the heater is on or off. 1st directive is 1st thermal source and so on.

WIPER_texture <tex_file_path>

[New in 1200:] Path to a wiper gradient texture, which uses its RGBA slots (1 per wiper in the rain system) to define the wiper’s path across the windshield. One texture is used per OBJ.

WIPER_param <dataref> <start> <end> <nominal_width>

[New in 1200:] Parameters per-wiper. dataref is the wiper animation controller, start and end define the ranges of the start and end dataref values of the wiper animation. Nominal width is the width of the wiper as the percent of the wiper animation arc that is covered by the blade at rest – basically the width of the physical blade. 1st directive is the 1st slot and so on.

POINT_COUNTS <tris> <lines> <lites> <indices>

This defines the size of the data tables. Four integer numbers define the number of entries in each table.

slung_load_weight <mass weight in pounds>

This defines the weight of the object, for use in the physics engine if the object is being carried by a plane or helicopter.

ATTR_layer_group <name> <offset>

[New in 850:] X-Plane draws scenery in “layer groups” – all elements in the same layer group are drawn before all other groups, but within a layer group the drawing order may be optimized by X-Plane. Normally layer groups are determined by X-Plane based on the type of drawing. Objects have always had their own layer group.

When the ATTR_layer_group is included somewhere in an object (it need only be used once, even if you have multiple LODs) then the object is drawn in a different layer group. The offset is used to prioritize further–for example. the group + 1 is drawn after the group, and the group – 2 is drawn two layers before objects. You can use an offset from -5 to + 5.

The valid layer names are:

terrain, beaches, shoulders, taxiways, runways, markings, airports, roads, objects, light_objects, cars

Note: the group “airports” covers all airport drawing. Within this group are the sub-groups shoulders, taxiways, runways, and markings. Markings are for taxilines and thus are on top of all other layers.

COCKPIT_REGION <left> <bottom> <right> <top>

[New in 900:]This defines a cockpit region – the rectangle of the region is in pixels where 0,0 is the lower left of the 2-d cockpit panel. The cockpit region can have any position as long as (1) its width and height are powers of (2) it does not go off the edge of the 2-d panel. Panel regions are referred to by index numbers: the first COCKPIT_REGION is number 0. There can be up to four cockpit regions in an object.

GLOBAL_luminence <luminance>

[New in 1200:] The baseline luminance for the LIT texture, in nts. Value is clamped at 65530.

GLOBAL_no_blend <ratio>

[New to 1000:] This sets the default state of the object to alpha testing (but not blending) where ratio is the alpha cutoff ratio, from 0.0 to 1.0.  This is comparable to ATTR_no_blend.  See the note above about hwen to use global vs per mesh attributes.

GLOBAL_shadow_blend <ratio>

[New to 1000:] This sets the default state of the object to shadow blending – that is, blending for drawing but alpha testing with ratio as a cutoff when shadow maps are drawn.  For example, if you have a hanger with a skylight (and the skylight is 10% alpha to put some “dirt” on the window) you can use this to “cut” the window for the shadow (using alpha testing) while keeping blending for primary drawing.

GLOBAL_specular <ratio>

[New to 1000:] This sets the default specular level of the object to <ratio>, from 0 to 1 – this is similar to ATTR_shiny_rat.  Note that you must set a non-zero specular level to use the specular channel of a normal map, because X-Plane draws the product of the overall specular gain and the alpha channel – this is a “master level”.  If you have a normal/specular map attached to an object, you should almost always use GLOBAL_specular 1.0 and not ATTR_shiny_rat.

GLOBAL_tint <albedo tint> <emissive tint>

[New to 1000:] This establishes a variance in brightness for instanced objects.  If an object is subject to hardware instancing, the two tint ratios are used to darken the albedo and emissive light levels.  The ratios are from 0.0 (no darkening, the default) to 1.0 (total darkening).  Small amounts of global tint can break up repetition.

GLOGAL_no_shadow

[New to 1010:] This marks an object as being entirely excluded from shadowing.  The object will cast no shadows.  If you don’t want shadows for your object, it is typically better for performance to try clever tricks with ATTR_shadow_blend or GLOBAL_shadow_blend – those attributes are really meant for objects that do cast shadows but have translucency (e.g. a window in a building).

SLOPE_LIMIT <min pitch> <max pitch> <min roll> <max roll>

[New to 1000:] This directive establishes the maximum slope limit an object will tolerate (in degrees) for library objects placed in a DSF.  When X-Plane selects the object, it will look at the actual pitch (forward-back tilt relative to the object) and roll (side-to-side tilt relative to the object) and will skip objects that have too much tilt.  Minimum pitch represents the ground sloping down at the front of the object, and minimum roll represents the ground sloping down to the left of the object.

Typically the way you would use this directive is: you would create several objects that share a common library virtual path, and then mark each one with slope limits based on its tolerance to slope.  At least one object would be built with a basement or other feature to handle steep slope.  As the object is placed, the sim can then avoid using objects that will look wrong on slope.

This directive applies only to objects placed into a scenery tile.

<min pitch> <max pitch> and <min roll> <max roll> must be within -90 to 90 degrees, inclusive.

TILTED

[New to 1000:] This directive causes objects placed on a scenery tile to sit “on” the ground even if it is sloped; the coordinate system of the object is rotated so that the Y axis is normal to the ground (instead of the Y axis being aligned with gravity).  For example, a parked car object that is tilted will appear to “sit” on the ground even on a slope.

This directive applies only to objects placed into a scenery tile.

REQUIRE_WET/REQUIRE_DRY

[New to 1000:] These directives establish whether an object should be used over wet or dry terrain when placed from the library.  Typically you would make two objects with the same virtual library path and mark one as REQUIRE_WET and the other as REQUIRE_DRY.  The sim will then, when looking through library objects, choose the right object based on the physical properties of the mesh.  For example, the bridge pylon bases come in pairs (a wet and dry version) with these marking, so that the pylons that are in water can have water marks.

This directive applies only to objects placed into a scenery tile.

ATTR_layer_group_draped <group> <offset>

[New to 1000:] This directive establishes the layer group for draped geometry from this object.  group and offset are the same syntax as ATTR_layer_group.  If no layer group is specified, draped geometry will go into the “objects” layer -5.

ATTR_LOD_draped <max LOD>

[New to 1000:] This directive establishes the maximum LOD distance for draped geometry; if it is omitted, draped geometry will take the maximum OBJ LOD distance.

GLOBAL_cockpit_lit

[New to 1010:] This directive changes ATTR_cockpit to use 3-d lighting, and it changes ATTR_cockpit_region to allow translucency.

Standard Shader Commands

The texturing of the draped triangles can be customized to use another texture besides the object’s texture.  To do this, include standard shader commands in the OBJ – the albedo texture of the standard shader (“TEXTURE”) should be listed after all regular textures have been specified.

OBJs support all of the standard shader features, for use in the draped texture:  TEXTURE, TEXTURE_NOWRAP, TEXTURE_LIT, TEXTURE_LIT_NOWRAP, TEXTURE_NORMAL, TEXTURE_NORMAL_NOWRAP, NO_BLEND, TWO_SIDED, SPECULAR, BUMP_LEVEL, and NO_SHADOW.  See the separate “standard shader” file specification for these commands that are common to a large number of file formats.

DATA RECORDS

VT <x> <y> <z> <nx> <ny> <nz> <s> <t>

This defines a single entry in the triangle vertex table. These are indexed starting from zero based on the record order. The eight numbers represent a triplet coordinate location, a triplet normal, and a pair forming a texture coordinate. This table is only used for triangles.

VLINE <x> <y> <z> <r> <g> <b>

This defines a single entry in the line vertex table, a triplet coordinate location and a triplet color value (RGB, from 0-1). This table is only used for line primitives.

VLIGHT <x> <y> <z> <r> <g> <b>

[deprecated] This defines a single entry in the light vertex table. Again we have a coordinate triplet and RGB triplet. Colors are 0-1 with some special rules:

  • If any value is negative, the light is considered to be flashing.
  • If the triplet value is all 9.9, it is a pulsing red light.
  • If the triplet value is all 9.8, it is a strobe light.
  • If the triplet value is all 9.7, it is a traffic-light.

WARNING: the specialized light values based on the 9.x series may not be supported precisely in future OBJ specs, and are not recommended. They are provided for compatibility.

IDX <n>
IDX10 <n> <n> <n> <n> <n> <n> <n> <n> <n> <n>

This defines one or ten entries in the index table. The index table is used to refer to vertices in the triangle or line vertex tables. Indices are zero based, and numbers are zero based into the vertex tables. In other words, an index whose value is “4” can refer to the 4th index in either the line or the triangle table, depending on the command using these indices. IDX10 is provided to pack 10 indices onto one line.

COMMAND RECORDS

GEOMETRY COMMANDS

TRIS <offset> <count>

This command draws count/3 triangles based on the vertices referenced by the indices starting at ‘offset’ in the index table and running consecutively upward. (In otherwords, the indices must be adjacent, but they can refer to non-adjacent vertices). Count must be a multiple of 3. Vertices come from the triangle table.

LINES <offset> <count>

This command draws count/2 line segments based on the vertices referenced by the indices starting at ‘offset’ in the index table and running consecutively upward. Vertices come from the line table. Count must be a multiple of 2.

[deprecated] LIGHTS <offset> <count>

This command draws ‘count’ point lights whose positions are stored consecutively starting at ‘offset’ in the light table. Unlike the LINES and TRIS command, this command does not utilize the index table. This means that while triangles and lines can issue the same vertex multiple times in a single command, the lights command cannot repeat a light vertex multiple times without multiple light commands.

NOTE: the ability to share vertices efficiently is important for triangles and lines which may be parts of meshes, but is not useful for lights.

LIGHT_NAMED <name> <x> <y> <z>

[New in 850:] Named lights allow a light to be created based on pre-existing types. The X Y Z parameters specify the light location.

Note: the list of available lights will be published in the future.

LIGHT_CUSTOM <x> <y> <z> <r> <g> <b> <a> <s> <s1> <t1> <s2> <t2> <dataref>

[New in 850:] A custom light allows an object to contain a light with almost any properties. Here are a few differences between custom lights and traditional object lights:

  • Custom lights are always textured. The RGB color is a tinting of this texture.
  • Custom lights get their texture from the object texture – you must draw some kind of light halo into the object.

A custom light has nine parameters (besides location). Each time the light is drawn, the parameters from the OBJ file are run through a dataref, which may modify or replace some or all of the parameters. How the dataref interacts with the parameters depends on the light–for example, some simply replace all parameters, some modify only one parameter, and some use the parameters as hints for their operation. See the plug-in SDK dataref docs for specific dataref info – X-Plane ships with several datarefs that are useful for custom lights, and plug-in authors can add more.

If the dataref is not found (or if “NULL” is passed as a dataref name) then the 9 parameters are drawn unmodified. In this way a custom light gives you complete control over the drawing of lights even without plug-ins.

The parameters are:

  • RGBA – the color of the light (a tint that is applied to the texture) and alpha level, which makes the light dimmer. An alpha of 0.0 means the light will not be drawn.
  • s – the size of the light – this is not in a particular unit (like meters), but larger numbers produce bigger brighter lights.
  • s1,t1,s2,t2 – the texture coordinates (fractions from 0 to 1). S refers to horizontal coordinates, and T for vertical coordinates.
LIGHT_PARAM <name> <x> <y> <z> [<additional params>]

[New in 940:] A parameterized light is like a named light, except that some of the attributes of the light can be numerically modified. X, Y, and Z define the position of the light. The name selects a pre-defined light. The additional parameters vary in number and definition based on the particular parameterized light selected.

LIGHT_SPILL_CUSTOM <x> <y> <z> <r> <g> <b> <a> <s> <dx> <dy> <dz> <semi> <dref>

[New in 1000:] This creates a spill light with completely customized parameters.  The parameters are:

  • x,y,z – the location of the light in 3-d space.  The light’s position and orientation do change with animation.
  • r,g,b,a – the color and brightness of the light.  Alpha acts to dim the light.
  • s – the size of the light in meters.  The size is the distance in meters at which the light is completely attenuated.
  • dx, dy, dz – the direction the light points – a vector of length 1 in local coordinates.  This points from the light to its target.  For omnidirectional lights, you can leave these as 0,0,0.
  • semi – the width of the light.  For an omnidirectional light, pass 1.0. For directional cones, semi is the cosine of half the spread of the light – so a light with a 90 degree total cone width has a semi-width of 45 degrees, so the semi parameter is cos(45 degrees), or about 0.7.
  • dref – the name of the dataref to use to modulate the light or “none” if none.  <dref> should be a 9-float array dataref that optionally modifies the parameters (excluding x,y,z and dref).

MAGNET <name> <type> <x> <y> <z> <psi> <the> <phi>

[New in 1110:] Defines the mounting point on a yoke in the airplane where a VR tablet can be attached.

  • name – Human readable name for debugging purposes
  • type – “xpad”, “flashlight”, or “xpad|flashlight”
  • x, y, z – position in space of the magnet
  • psi, the, phi – degrees roll, pitch, heading in Eulers

EMITTER <name> <x> <y> <z> <psi> <the> <phi> [index]

[New in 1130:] Defines a particle emitter

  • name – Name of the emitter. Using a name that isn’t found in the specified PARTICLE_SYSTEM file is an error.
  • x, y, z – position in space of emitter
  • psi, the, phi – degrees roll, pitch, heading in Eulers
  • index – Optional, if left out it is assumed to be 0

ACTION COMMANDS

[deprecated] smoke_black <x> <y> <z> <s>
[deprecated] smoke_white <x> <y> <z> <s>

These commands cause the object to periodically emit a puff of block or white smoke from the location specified by x,y,z. S is a size number indicating the relative intensity of the smoke.

TODO: what is the units of the smoke puff size parameter?

STATE COMMANDS

ATTR_LOD <near> <far>

LOD indicates the beginning of a new LOD, which should be used to represent the object when the viewer is between near (inclusive) and far (exclusive) meters.

[deprecated and ignored] ATTR_ambient_rgb <r> <g> <b>
[deprecated and ignored] ATTR_specular_rgb <r> <g> <b>
[deprecated] ATTR_emission_rgb <r> <g> <b>
ATTR_shiny_rat <ratio>

These commands change the material state for geometry based on the OpenGL lighting model.

ATTR_reset

This command resets the material state to its default.

ATTR_poly_os <n>

This command sets the polygon offset state to N, a non-negative integer.

ATTR_cockpit

ATTR_cockpit sets the current texture to the panel texture and the current manipulator to the panel-click manipulator.

The panel texture uses “flat” lighting (materials and lights are ignored, color matches the 2-d or 3-d panel) when it is invoked using this attribute.

ATTR_cockpit_lit_only

ATTR_cockpit_lit_only acts like ATTR_cockpit, but only replaces the emissive texture.

ATTR_cockpit_region <region number>

[New in 900:] The ATTR_cockpit_region attribute changes the texture of the object to a specific region of the cockpit texture. Use ATTR_no_cockpit when done. The current manipulation is set to panel clicking.

The panel texture uses “real” lighting (materials and lights are utilized, color matches the object texture) when it is invoked using this attribute.

ATTR_cockpit_device <name> <bus> <lighting channel> <auto_adjust>

[New in 1100:] The ATTR_cockpit_device command changes the lit texture of the object to the screen of a given GPS device for an aircraft; it is legal only in aircraft-attached objects.  Use ATTR_no_cockpit when done.  Parameters:

  • Name is the device name, one of GNS430_1, GNS430_2, GNS530_1, GNS530_2, CDU739_1, CDU739_2, G1000_PFD1, G1000_MFD, G1000_PFD2.
  • The bus is a little-endian bitfield, indicating all the electrical system bus indices (zero-based) that this device gets power from.
  • The lighting channel is the zero-based index for the instrument lighting rheostats that control the screen’s brightness.  (Cockpit device lighting is not subject to ATTR_lit_level.)
  • Auto-adjust is 1 if the screen brightness increases to be readable during the day, and 0 if screen brightness is “washed out” by the sun.

The rest of the state commands affect the above published state.

ATTR_hud_glass

Mesh becomes the HUD glass. Fully compatible with all cockpit panel modes.

ATTR_hud_reset

ATTR_hud_glass is turned off.

ATTR_light_level <v1> <v2> <dataref> [<brightness>]

[New in 930:] ATTR_light_level changes the brightness of the _LIT texture for the object. The dataref is interpreted as a value between v1 and v2. Values outside v1 and v2 are clamped. This attribute overrides the sim’s decision about object lighting. If brightness (nts) is given, photometric features are enabled. It is the maximum brightness of your LIT texture.

ATTR_light_level_reset

[New in 930:] ATTR_light_level_reset resets the _LIT texture to the default brightness. (This brightness is typically full at night or none during the day.)

ATTR_shadow_blend <ratio>

[New in 1000:] This command temporarily sets blending mode to testing for shadows but blending for primary drawing, with the ratio (0-1) being the cutoff level for shadows.

ATTR_draped

[New to 1000:] This marks the beginning of draped geometry.  Draped geometry is effectively excluded from the OBJ.

ATTR_no_draped

[New to 1000:] This marks the end of draped geometry.  Draped geometry is effectively excluded from the OBJ.

ATTR_shadow

ATTR_no_shadow

[New to 1010:] This turns shadow casting off for a range of triangles within any object.

ATTR_hard

Makes TRIS collidable. This can only be used in .objs placed with a .dsf, not made with plugins.

ATTR_no_hard

Resets ATTR_hard or ATTR_hard_deck

ATTR_hard_deck

[New in 900:] Starting in X-Plane 9, ATTR_hard_deck can be used instead of ATTR_hard. It sets a hard surface, but allows the user to fly under the surface (for example the deck of a bridge). This is also limited to .objs placed with a .dsf.

Command                 State Catagory           New Value
ATTR_hard               Hard Polygon            On
ATTR_no_hard            Hard Polygon            Non-Off*

ATTR_shade_flat**       Shading                 Flat
ATTR_shade_smooth**     Shading                 Smooth*

ATTR_no_depth           Depth Check             Off
ATTR_depth**            Depth Check             On*

ATTR_no_cull**          Two-Sided Geometry      Two-sided
ATTR_cull**             Two-Sided Geometry      One-sided*

ATTR_no_blend           Blending                Off
ATTR_blend              Blending                On*

[new in 1000]
ATTR_shadow_blend       Blending                Shadow-only

[new in 1010]
ATTR_shadow             Shadow Casting          Shadow Casting*
ATTR_no_shadow          Shadow Casting          No Shadow Casting

[new in 930]
ATTR_solid_camera       Camera plane            Enable
ATTR_no_solid_camera    Camera plane            Disable*
ATTR_draw_enable        Draw plane              Enable*
ATTR_draw_disable       Draw plane              Disable

* This is the default
** These are deprecated

[New in 850:] Starting in X-Plane 8.50 ATTR_no_blend can take an optional decimal ratio (between 0.0 and 1.0) that specifies the cutoff for the alpha channel. Alpha levels below this level are rendered as fully transparent and alpha levels above this level are fully opaque. If this fraction is not specified, no_blend uses a default cutoff ratio of 0.5.

[New in 850:] Starting in X-Plane 8.50 ATTR_hard can be followed by an additional surface name. This surface name controls the bumpiness of the hard polygon, allowing an object to emulate some of the natural X-Plane surfaces, like grass and rocks. If no surface type is specified then a smooth surface is used.

The valid recognized surface names are:

water, concrete, asphalt, grass, dirt, gravel, lakebed, snow, shoulder, blastpad

ANIMATION COMMANDS

ANIM_begin

This command marks the beginning of an animation subsection. All further geometry commands are affected by the animation commands between this ANIM_begin and the command until an ANIM_end is encountered.

ANIM_end

This defines the end of an animation section. Geometry following this is not affected by the animation commands.

ANIM_rotate <x> <y> <z> <r1> <r2> <v1> <v2> [dataref]

This defines a rotation command. X, Y and Z define an axis of rotation – they should form a unit-length vector. r1 and r2 represent the angle of counterclockwise rotation when the dataref is at its minimum and maximum values respectively, when looking down at the ‘arrow’ of the vector. (So if the vector is 0,1,0 then a positive rotation is counterclockwise when viewed from above.). They are in degrees. v1 and v2 are the minimum and maximum dataref values for calibration purposes. Dataref (optional) is the string name of a sim dataref.

ANIM_trans <x1> <y1> <z1> <x2> <y2> <z2> <v1> <v2> [dataref]

This defines a translation command. x,y,z 1 and 2 are two offset distances, for when the dataref is at its minimum and maximum values; v1 and v2 are the expected min and max for the dataref and dataref is the string name of the dataref.

ANIM_hide <v1> <v2> <dataref>

[New in 850:] If the dataref’s value is within the two values (inclusively) then drawing is suspended. Drawing is resumed when a show command restarts drawing or when the animation group (defined by ANIM_begin/ANIM_end ends).

Note: hiding animation suspends all triangle/polygon, line and light drawing but does not stop the processing of attributes. State will change even after a hide commands. Thus the state of any given part of the object does not depend on animation commands.

ANIM_show <v1> <v2> <dataref>

[New in 850:] If the dataref’s value is within the two values (inclusively) then drawing is resumed. This has no effect unless drawing was previously suspended.

Shows and hides are not counted, e.g. if you hide twice and show once, drawing is resumed.

ANIM_rotate_begin <x> <y> <z> <dataref>

[New in 900:] This begins an ANIM_rotate command, but with a key frame table to follow. XYZ is the axis of rotation.

ANIM_rotate_key <value> <angle>

New in 900:] This adds a key frame to a rotation animation. The value represents a possible dataref value–the angle is the corresponding rotation.

ANIM_rotate_end

[New in 900:] This ends a rotation animation with key frames. It is required after the key frames and must be used to balance every ANIM_rotate_begin.

ANIM_trans_begin <dataref>

[New in 900:] This begins an ANIM_trans command but with a key frame table that follows. The dataref is specified, but the actual translates are per-keyframe.

ANIM_trans_key <value> <x> <y> <z>

[New in 900:] This adds a key frame to a translation animation. For the given value, three distances, in X, Y and Z are provided – these are distances to translate the contained geometry.

ANIM_trans_end

[New in 900:] This ends a key-framed translation animation and must be used to balance any ANIM_trans_begin commands.

ANIM_keyframe_loop <loop>

[New in 900:] Normally the dataref value for an animation is looke up in the key frame table and an animation is intepretted or extrapolated. If the ANIM_keyframe_loop command is present, the corresponding animation (the animation defined right before the ANIM_keyframe_loop command) will have its dataref divided by the loop amount and the remainder is used. This makes it possible to change an ever-increasing dataref into a looping dataref.

MANIPULATION COMMANDS

All manipulations except for ATTR_manip_none take a cursor manipulation (defining which cursor to show while the user’s mouse is over the mesh) and a tool tip (shown if the user has help-tips enabled and the cursor hovers over the mesh). The help tip string can be any string without newlines; the cursor enumeration is one of the following names:

four_arrows
hand
button
rotate_small
rotate_small_left
rotate_small_right
rotate_medium
rotate_medium_left
rotate_medium_right
rotate_large
rotate_large_left
rotate_large_right
up_down
down
up
left_right
right
left
arrow

ATTR_manip_none

[New in 920:] This sets the current manipulation to no manipulation – clicks to the geometry will track through to any mesh behind this one.

Note: click-testing the mesh burns CPU on a per-triangle basis; click-testing very complex meshes can be quite slow. By putting an ATTR_manip_none attribute after ATTR_cockpit but before TRIS, you can create triangles that use the cockpit texture but do not have the associated cockpit manipulator. For geometry that does not need click testing (e.g. an EFIS screen with no buttons) this can reduce the number of click-tested triangles and improve through-put.

ATTR_manip_drag_xy <cursor> <dx> <dy> <v1min> <v1max> <v2min> <v2max> <dref1> <dref2> <tooltip>

[New in 920:] This sets the current manipulation to an X-Y axis manpulation. The parameters v1min and v1max define the minimum and maximum values to be written to the first dataref as the mouse is dragged along the X axis. The parameters v2min and v2max define the minimum and maximum values to be written to the second dataref as the mouse is dragged along the Y axis. Two dataref names and a tool tip follow.

When an axis drag begins, the position of the axis on screen is based on the current dataref value. For example, if the X dataref has minimum and maximum values of 0 and 4 and is currently set to 1, then when the click starts, 25% of the axis will be to the left of the current mouse position and 75% will be to the right. If the dx axis length is 200 then the user can drag 50 pixels to the left and 150 pixels to the right to manipulate the dataref.

ATTR_manip_drag_axis <cursor> <dx> <dy> <dz> <v1> <v2> <dataref> <tooltip>

[New in 920:] This sets the current manipulation to an axis in 3-d space. dx, dy, and dz describe an axis (the length is in meters). v1 and v2 define the range that the dataref can take. Like the above xy drag, the axis’ relative position is determined by the current dataref value. The axix’s orientation is affected by animations, but is “frozen” on mouse-down.

ATTR_manip_command <cursor> <command> <tooltip>

[New in 920:] This sets the current manpiulation to a comand, specified by the command parameter. The command will be actuated while the mouse is held down over the mesh.

ATTR_manip_command_axis <cursor> <dx> <dy> <dz> <positive command> <negative command> <tooltip>

[New in 920:] This sets the current manipulation to an axis drag where dragging in the direction of the vector invokes the positive command and dragging in the negative direction invokes the negative command. The command is invoked until the mouse is released or returns to the neutral or opposite position. Axis definition is the same as in ATTR_manip_drag_axis.

ATTR_manip_noop

[New in 920:] This sets the current manipulation to “no-op” (no operation). Unlike “none”, the mouse click is “swallowed” by the triangles and will not actuate clicks on a mesh behind the no-op mesh.

ATTR_manip_push <cursor> <v_down> <v_up> <dref> <tooltip>

[New in 930:] This sets the current manipulation to be a “push” button. When the mouse is clicked, this manipulator sets the dataref to the “down” value; when the mouse is released, the dataref is reset to the “up” value. The intention is to model push buttons.

ATTR_manip_radio <cursor> <v_down> <dref> <tooltip>

[New in 930:] This sets the current manipulator to be a “radio” button. Whe nthe mouse is clicked, the dataref is set to the down value. By setting different meshes to have radio manipulators with the same dataref but different values, you can create radio-button-like behavior.

ATTR_manip_toggle <cursor> <v_on> <v_off> <dref> <tooltip>

[New in 930:] This sets the current manipulator to a “toggle” dataref. When the mouse is clicked down, if the dataref is already at the “on” value, it is set to the “off” value – otherwise it is set to the “on” value. This can be used to make toggle switches like a gear handle.

ATTR_manip_delta <cursor> <v_down> <v_hold> <v_min> <v_max> <dref> <tooltip>

[New in 930:] This sets the current manipulator to a “delta” manipulator. When the mouse is first clicked, the dataref is incremented by the “down” value. if the mouse is held it is further incremented by the “hold” value (for every seocnd the mouse is held down). The dataref will be clamped between the minimum and maximum value. To decrement, use negative values.

The intention of the delta manipulator is to build multiple “hot spots” with invisible meshes, one to increment, one to decrement.

ATTR_manip_wrap <cursor> <v_down> <v_hold> <v_min> <v_max> <dref> <tooltip>

[New in 930:] This sets the manipulator to the “wrap” manipulator. The wrap manipulator functions the same as the delta manipulator, except if the dataref exceeds the range min to max, the dataref will wrap around to the other side of the range. This can be use for a control like an OBS knob.

ATTR_manip_drag_axis_pix <cursor> <dx_pix> <step> <exp> <v1> <v2> <dataref> <tooltip>

[New in 1010:] This sets the current manipulator to a drag axis that can be either horizontal or vertical – the user chooses.  Up and right drags increase.  The length of the axis is defined in screen pixels by dx_pix.  The dataref is always modified in increments of “step” if it is not zero.  “exp” is the power of an exponential curve that controls the speed at which the dataref changes.  Higher numbers cause a more “non-linear” response, where small drags are very precise and large drags are very fast.  An exponent of 1.0 sets linear response, similar to the other manipulators.

ATTR_manip_wheel <delta>

[New in 1050:] This can be used after any manipulator that uses a single dataref that does not automatically support the mouse wheel; it adds a mouse wheel action to the manipulator such that each click of the mouse wheel moves the dataref by <delta> units.

ATTR_manip_command_knob <cursor> <positive cmd> <negative cmd> <tool tip>
ATTR_manip_command_switch_up_down <cursor> <positive cmd> <negative cmd> <tool tip>
ATTR_manip_command_switch_left_right <cursor> <positive cmd> <negative cmd> <tool tip>

[New in 1050:] These manipulators add a switch or knob manipulator that executes a command when the switch or knob is moved. The UI gesture the user uses will be appropriate for the type of switch/knob and is selected by X-Plane; use the knob variant for rotating knobs, and the up/down or left/right variant for switches whose main motion is vertical or horizontal.

Two commands are provided, one for increasing the switch position (e.g. switch rotates clockwise, switch moves up, etc.) and one for decreasing the switch position.

The cursor selected should be one of the two-way cursors (e.g. rotate_small); when X-Plane provides two click zones for the manipulator automatically, it will use the right one-way cursor (e.g. rotate_small_left or rotate_small_right automatically).

Mouse wheel support for command knob/switch manipulators is automatic – each single click of the mouse wheel runs the increase or decrease command once.

ATTR_manip_axis_knob <cursor> <min> <max> <click delta> <hold delta> <dataref> <tooltip>
ATTR_manip_axis_switch_up_down <cursor> <min> <max> <click delta> <hold delta> <dataref> <tooltip>
ATTR_manip_axis_switch_left_right <cursor> <min> <max> <click delta> <hold delta> <dataref> <tooltip>

These manipulators work the same as the above command manipulators – a gesture matching a knob, left/right or up/down switch is created. These manipulators are dataref-driven – you provide minimum and maximum values and a dataref to be changed.

Click delta is the amount the manipulator changes when the user moves the manipulator a single unit.  Hold delta is the number of units-per-second if the user does a continuous hold on the manipulator. If the mouse wheel is clicked once, the click delta is used.

Like the command knob/switch manipulators, the cursor is automatically changed to indicate whether an increment or decrement will be used.

ATTR_manip_keyframe <dataref value> <angle>

[New in 1100:] ATTR_manip_keyframe can be used to add intermediate key-frame points to a rotational manipulator; the end points of the key frame table are taken from angle1, angle2, and v1min/v1max of the main manipulator; intermediate points can be added in between . Dataref value is in units of dataref 1 and angle is in degrees.

ATTR_manip_command_switch_left_right2 <cursor> <command> <tooltip>
ATTR_manip_command_switch_up_down2 <cursor> <command> <tooltip>
ATTR_manip_command_knob2 <cursor> <command> <tooltip>

[New in 1110:] These commands create a two-way switch based on a single toggle-command.  They will press the command once each time they are clicked with the mouse, but they are  support up/down left/right and rotate hand gesture in VR.

ATTR_axis_detented <dx> <dy> <dz> <v_min> <v_max> <dataref>

[New in 1110:] ATTR_axis_detented can follow ATTR_manip_drag_axis and adds a second direction of dragging for detenting.  dx, dy, and dz define the direction to drag to overcome detents; the dataref will go from vmin to vmax as it is dragged to the full length of dx, dy, dz.

ATTR_axis_detent_range <start> <end> <height>

[New in 1110:] specifies a detent region in a detented-axis manipulator.  Start and end are values that the main axis dataref goes through (start must be smaller than end); height is in units of the second dataref and specifies how high the user must drag to the side to enter this range.

You may use more than one ATTR_axis_detent_range to create complex detent patterns.  You can include zero-length detents that are lower than their neighbors to create “stop pits’, but do not create zero length detents that are higher than their neighbors; they will not stop a drag.

ATTR_manip_drag_rotate <cursor> <x> <y> <z> <dx> <dy> <dz> <angle1> <angle2> <lift> <v1min> <v1max> <v2min> <v2max> <dataref1> <dataref2> <tooltip>

[New in 1110:] This creates a rotational manipulator.

  • <x> <y> <z> – The rotation origin point
  • <dx> <dy> <dz> – The axis of rotation
  • <angle1> <angle2> – The manipulator rotates around an axis that goes through the point X,Y,Z and has a direction dx,dy,dz.  The angle range (in degrees) from angle1 to angle2 is treated as counter-clockwise when dx,dy,dz points to the viewer — this is the same convention as rotation animations use.  Dataref1 is affected by rotating the manipulator.

The rotation manipulator can optionally be made to pull out from the rotation point to go over detents.  In this case, dataref2 (and v2 min/max) define the movement of this dataref; the manipulator is lifted “lift” meters when the dataref is at v2 – the lift is always away from the center of rotation.  If detenting is not desired, set v2 min/max and lift to 0, and use “None” for dataref2.

Like the drag axis manipulator, you can follow ATTR_manip_drag_rotate with ATTR_axis_detent_range to specify detent regions of the rotational manipulator.

Comments Off on OBJ8 (.obj) File Format Specification

When to Use Global or Mesh Attributes in X-Plane 10

X-Plane 10 object attributes are properties of an .obj model file that control how drawing looks.  Examples of attributes include:

  • One or two sided drawing.
  • Alpha blending vs. alpha testing.
  • Specular levels (“shininess”).

In X-Plane 10, there are now two ways to set these attributes:

  • “Globally” via a command in the top of the .obj file that affects the drawing of the whole object or
  • “Per mesh” via a command that affects the next set of triangles.  (This is the only way to set these attributes in X-Plane 9.)

Which command should an exporter use?  What is best for performance?  Here are a few guidelines.

  • For scenery: The cost of a global attribute is higher than the cost of a mesh attribute, but you “pay” for a global attribute per .obj file, while you pay for a mesh attribute per placement.  Thus if you ues a single object 10 times (a jetway for example), you pay for a mesh attribute 10 times but a global attribute only once – a big win!
  • If an object will be used multiple times in a scenery system, try to use the global attributes when possible.
  • Try to make all objects that share a texture use the same global attributes. For example, if you have a normal object, every object that uses that normal map should use the same global specular attribute.
  • If an object has multiple attributes (e.g. part of the mesh is blended, part is not blended) try to set the global attributes to match the other objects that use the same texture.
  • For airplanes: global and per mesh attributes have the same cost, so there is no particular performance win or loss.
Comments Off on When to Use Global or Mesh Attributes in X-Plane 10

How to Debug Scenery Pack Loading

What do you do if your scenery simply isn’t showing up in X-Plane?  This article explains some debugging techniques to trouble shoot your package.

X-Plane puts a log file (called Log.txt) into the X-Plane directory; this file is rewritten each time X-Plane runs.  So to use the log file, run X-Plane, go to the airport where your scenery is placed, then quit and do not restart X-Plane.  Now you can view the log.

Did X-Plane Find my Scenery Pack?  In the Right Order?

The first questions to answer are: did X-Plane find my scenery pack?  Is another scenery pack higher priority?  To tell, open the log file and look for the scenery package list – it’s near the top and looks like this:

I found the following scenery packages (prioritized in this order):
  0 Custom Scenery/KSEA Demo Area/
  1 Custom Scenery/KSEA Demo Terrain/
  2 Resources/default scenery/1000 autogen/
  3 Resources/default scenery/1000 decals/
  4 Resources/default scenery/1000 forests/
  5 Resources/default scenery/1000 roads/
  6 Resources/default scenery/1000 urban terrain/
  7 Resources/default scenery/1000 world terrain/
  8 Resources/default scenery/700 roads/
  9 Resources/default scenery/900 beaches/
 10 Resources/default scenery/900 europe objects/
 11 Resources/default scenery/900 forests/
 12 Resources/default scenery/900 roads/
 13 Resources/default scenery/900 us objects/
 14 Resources/default scenery/900 world object placeholders/
 15 Resources/default scenery/airport decals/
 16 Resources/default scenery/airport scenery/
 17 Resources/default scenery/default apt dat/
 18 Resources/default scenery/default atc/
 19 Resources/default scenery/sim objects/

In this case, there are 20 scenery packs – the highest priority one is the “KSEA Demo Area” pack and the lowest priority one is “sim objects.”  If your scenery pack is not listed, it is not in the Custom Scenery folder.  If there is another pack with higher priority, you may need to rename it to be earlier in the alphabet.

Did X-Plane Load My DSFs?

Every time X-Plane loads a DSF, it puts out a log message.  This is why it is important to go somewhere in your scenery’s area, e.g. to an airport.  Here is the log for the airplane starting at KSEA:

0:00:00.000 I/SCN: DSF load time: 701866 for file Custom Scenery/KSEA Demo Area/Earth nav data/+40-130/+47-123.dsf (0 tris)
0:00:00.000 I/SCN: DSF load time: 5123485 for file Custom Scenery/KSEA Demo Terrain/Earth nav data/+40-130/+47-123.dsf (243770 tris)

Every pack that is loaded is listed – in this case the KSEA Demo Area is an overlay, and the base mesh is loaded next.  Once X-Plane loads a base mesh, no more overlays are loaded.

Possible causes of not loading include the path to your DSF being wrong, and the priority order of the scenery being wrong.

Detailed Error Messages

If there is a problem with your scenery pack, X-Plane will show a dialog box that reads:

Error loading the scenery package:

Custom Scenery/KSEA Demo Area/

The scenery may not look correct.

Please see the log.txt file for detailed error information.

This message will show only once for your scenery pack the first time the error is hit for each session of X-Plane.  The message is simply meant to alert you that the log needs inspecting for problems.

When you open the log file you will find one or more lines like this:

Custom Scenery/KSEA Demo Area/KSEA_objects/DeltaCargo.agp:3:The file has an invalid .agp header.

The log will contain (hopefully) detailed information about the particular files that had problems and what was wrong with them.

Comments Off on How to Debug Scenery Pack Loading

DSF Usage In X-Plane

Revision History:
         2/22/23   Updated for X-Plane 11, 12
         7/ 6/16   Added data validation rules
        12/ 8/13   Clarified DSF DEM handling
         2/18/12   Updated to docuemnt 7z
         2/12/12   Updated for X-Plane 1000
         2/ 4/09   Updated for X-Plane 930
        12/26/07   Updated For X-Plane 900
         7/25/07   Initial Draft

This document outlines how the DSF file format is used by X-Plane. DSF is a container format; new features can be added to the X-Plane scenery system without changing the file format. This document lists the different legal DSF configurations that X-Plane understands.

Note: this document is a low level reference, intended for programmers who intend to create tools to edit DSF files. Authors who want to edit DSFs should simply use higher level tools like OverlayEditor, or PhotoSceneryX.

DSF Compression

Starting with X-Plane 10, X-Plane will read 7z-compressed DSF files (a single DSF compressed into a 7z archive) natively. X-Plane thus installs its DSFs without decompressing them, to save disk space. You may need to un-7z DSFs to read them. 7z compression is optional.

DSF Properties

DSF contains a series of properties, with string values. These are the properties X-Plane recognizes:

Bounding Box and Location Properties

All DSFs must contain four properties indicating the bounds of the DSF tile. These bounds are in degrees and must be integers. DSFs should contain a planet tag, which is optional, and assumed to be earth if missing.

Property Name Default Value
sim/north (Required) degrees
sim/south (Required) degrees
sim/east (Required) degrees
sim/west (Required) degrees
sim/planet earth mars

Object Density Control Properties

X-Plane only loads part of the facades and objects in a DSF, based on the “number of objects” setting in the rendering options. The “require” properties force X-Plane to load certain objects. Each require statement applies to either facades or objects, and specifies both the minimum setting where the objects are guaranteed loaded and the minimum index within the DSF of the object/facade it applies to.

More than one requirement statement can be used; all are combined together to meet all requirement constraints. Thus you can bring in objects incrementally through proper organization of the DSF object definition order.

Property Name Value Minimum Sim Version
sim/require_object obj_level/first_required_index 8.0
sim/require_agp agp_level/first_required_index 10.0
sim/require_facade obj_level/first_required_index 8.0

Overlay and Exclusion Properties

The overlay properties control how a DSF is used as an overlay to other DSF files. The overlay property signals to X-Plane that the DSF should be loaded as an overlay and not a base mesh.

The exclude properties cause X-Plane to eliminate scenery from lower priority DSFs that are loaded underneath the overlay. Each exclusion zone is a rectangle specified in latitude and longitude. A DSF may contain multiple exclusion zones of the same type, and they may overlap.

Property Name Value
sim/overlay 1
sim/exclude_obj polygonal exclusion
sim/exclude_fac polygonal exclusion
sim/exclude_for rectangular exclusion
sim/exclude_bch polygonal exclusion
sim/exclude_net polygonal exclusion
sim/exclude_lin polygonal exclusion
sim/exclude_pol polygonal exclusion
sim/exclude_str polygonal exclusion
sim/filter/aptid airport ID

The quality of culling depends on the type of scenery being excluded. In some cases, culling may over-remove or under-remove scenery.

[X-PLANE 9] X-Plane 9 improves the quality of forest exclusion. While X-Plane 8 forest exclusions remove a forest polygon if any vertex is in the exclusion zone, X-Plane 9 forest exclusion zones exclude on a per-tree basis for more precise cuts.

A rectangular exclusion is four floating point coordinates lon/lat coordinates in the form of

west/south/east/north

[X-PLANE 12] A polygonal exclusion is a rectangular exclusion (for compatibility) or:

west/south/east/north;lon1,lat1,lon2,lat2,lon3,lat3,lon4,lat4

The rectangle should be a bounding box around the polygon, and the polygon should contain at least three points and no overlapping edges or holes. Concave exclusions are allowed. Like rectangular exclusions, the exclusion is a containment test with any point in the geometric primitive, so containing a single corner of an AGS will remove the entire AGS, for example.

The intent of poylgonal exclusions is to allow simple shapes to be modeled directly instead of using a large number of thin axis aligned bounding boxes. The outer AABB provides backward compatibility with X-Plane 11.

[X-PLANE 11.50] X-Plane 11.50 can exclude by airport ID – see the section on custom DSF comments for more. Each sim/filter/aptid establishes a zero-based indexing scheme to airport IDs for this purpse.

LOD Properties

[X-Plane 930:] Historically, X-Plane measures the distance of a mesh patch based on an arbitrary center point computed from the geometry. Since two different LOD mesh patches may have different vertices, their centers will be different. This cannot be predicted by authors. So for example, if a first patch has an LOD of 0 -> 20000 and the second one has 20000 -> -1, the first mesh patch may not disappear when the second one appears because they are being measured using different center points.

Setting the property sim/lod_mesh to 1 changes X-Plane’s behavior in the following way: the center point for LOD calculations of a mesh patch with a non-zero LOD start value will be taken from the previous mesh patch in the command stream.

This in turn means that a series of consecutive mesh patches with increasing LODs (starting at 0) will all have the same center point, and can be switched between using consecutive LOD values. (Also note that when this option is used, the closest LOD must come first, to establish the center point!

Other Properties

For historical reasons X-Plane will only flatten a terrain mesh if these properties are present.

Property Name Value
sim/creation_agent X-Plane Scenery Creator 0.9
sim/internal_revision 0

Raster Layers

X-Plane interprets multiple types of raster data in the DSF:

DEM Name Contents Supported In
elevation MSL Elevation Data X-Plane 10
sea_level Bathymetric Depth X-Plane 11
soundscape Sound codes X-Plane 12
spr1 Seasons: start of spring, day of year X-Plane 12
spr2 Seasons: end of spring, day of year X-Plane 12
sum1 Seasons: start of summer, day of year X-Plane 12
sum2 Seasons: end of summer, day of year X-Plane 12
fal1 Seasons: start of fall, day of year X-Plane 12
fal2 Seasons: end of fall, day of year X-Plane 12
win1 Seasons: start of winter, day of year X-Plane 12
win2 Seasons: end of winter, day of year X-Plane 12

Elevation Raster Data

[X-PLANE 10] Elevation should be specified via a raster DEM file. If the vertex elevation is the flag value -32768.0 then the DEM elevation is sampled. This method is recommended because X-Plane can use the elevation DEM for other purposes as well as meshing.

Bathymetric Data

[X-PLANE 11] The depth of the sea floor is specified via a bathymetric DEM; elevations are absolute MSL meters. The behavior of the depth vertex variable varies by version and data.

Sim Version Bathymetry Present DSF Depth Coord/Flag
X-Plane 10 No (not used) Depth
X-Plane 11 No Depth
X-Plane 11 Yes 0 for coastline, 1 for use bathymetry
X-Plane 12 Yes (required) ratio for interpolation: 0 is ground elevation, 1 is bathymetry sample

Sound Raster Data

[X-PLANE 12] A sound raster file specifies codes that drive environmental sounds throughout the scenery. Codes are:

0 or invalid = barren
30 = water (we don't differentiate between water body types because we don't have the data on the DSF yet)
40 = forest
50 = rural
60 = urban low
80 = urban town
100 = urban high
120 = industrial

Airport sounds replace some of these data points based on the apt.dat data loaded at runtime.

Seasonal Data

[X-PLANE 12] X-Plane 12 supports a set of 8 seasonal raster files that define the time of year of seasons. Each of the four seasons has a start and end day; within that range, the season is selected; between the ranges (e.g. blended between end of summer and start of fall) the seasonal art is interpolated.

All eight raster layers must be present. Days are days since January 1, and seasons can “wrap aorund”, e..g winter could start on day 310 and end on day 20.

Mesh Types and Coordinate Organization

X-Plane uses .ter files to specify the way mesh patches are drawn. The coordinate organization is:

  1. Longitude
  2. Latitude
  3. Elevation
  4. Normal – X
  5. Normal – Z
  6. Additional Coordinates…

These .ter files may contain “border” textures–the border feature of a .ter file is only used if the overlay flag is set in the mesh patch.

Mesh normals: the normal vector is stored as the X and Z ratio of the normal vector, based on a coordinate system of Y = up and Z = north at the mesh point’s location.

Additional coordinates are ordered optionally S1, T1, then optionally S2, T2. If an odd coordinate is provided, it is treated as alpha. If an alpha is needed but not present, X-Plane generates one using seeded random numbers.

Base Texture is Projected Composite Texture Is Projected Border+Overlay Flag ST1 Controls ST2 Controls
no no no base
no no yes base border
no yes no base
no yes yes base border
yes no no base
yes no yes base border
yes yes no
yes yes yes border

X-Plane 8 does not use the alpha channel right now that a DSF may have.

Water Handling

A mesh layer with the name water or terrain_Water is treated as water data mesh triangles; unlike regular mesh triangles, no .ter file is provided.

Water mesh triangles have a number of properties that are unique to water.

Water meshes ignore the normal parameters and have two ST coordinate controls after them:

  • “Fetch ratio”, a ratio from 0.0 to 1.0 that controls the scaling of waves. Use 1.0 for open ocean and 0.0 for ponds.
  • Depth. This is an actual depth measurement for X-Plane 10 and earlier. In X-Plane 11 and later, if a bathymetric DEM is present, then this is a flag: 0.0 for coastline and 1.0 for in-water. See raster data handling for more info.

In X-Plane 12, if a .ter file has the WATER_COLOR_MASK directive, then it is water provided via a .ter file. In this case, four ST coordinates are expected: fetch ratio, bathymetric depth flag (this directive should always be used with raster bathymetric depth) and a pair of ST coordinates defining the UV mapping for the water texture in the .ter file.

Raster Data and Meshes

If  elevation raster data is present, it will be used for the elevation of a mesh point as long as:

  • The patch vertex’s elevation is -32768.0 or
  • The patch vertex’s terrain type is water.

If elevation rater data is present, all normal vectors can be left as 0.0 – X-Plane will calculate them from raster data, for all terrain types.

(By convention v10 DSFs produced with LR’s scenery tools use explicit elevation for all water vertices and all coastal vertices, to ensure precise water elevation even near dams and to keep a water-tight seal between land and water.  Interior land elevation points come from raster DEMs for data compression.)

Object Types and Coordinate Organization

Objects are placed with three or four coordinate values:

  1. Longitude
  2. Latitude
  3. Heading
  4. MSL height (optional in v10)

X-Plane 8 and 9 only allow AGL positioned objects (3 coordinates); X-Plane 10 allows for an optional 4th coordinate, interpreted as the MSL height of the object in meters. (See Special DSF Comments for AGL placement).

AG Points (X-Plane 10 only) may only have three coordinates (lon, lat, heading) and are always draped.

Polygon Types and Coordinate Organization

Only one beach .bch definition may be used per DSF. Subtypes within the beach are used to create variety.

X-Plane uses a number of graphic resource files for DSF polygons. The meaning of the coordinates varies based on the type.

File Type Minimum Sim Version Holes Allowed? Parameter Meaning Coordinates
Facade (Flat, No Wall Choice) 8.0 No Height (meters) Lon Lat
Facade (Flat, With Wall Choice) 10.0 No Height (meters) Lon Lat Wall Type
Facade (Curved, No Wall Choice) 10.0 No Height (meters) Lon Lat Bezier Lon Bezier Lat
Facade (Curved, Wall Choice) 10.0 No Height (meters) Lon Lat Wall Type Bezier Lon Bezier Lat
Forest 8.0 (10.0 for line and point fill, 12.0 for height/MSL control) Yes Density (0-255) + Fill (0=solid,256=line,512=points) Lon Lat height (optional) MSL (optional)
Beach (MSL) 8.0 No 0=chain,1=ring Lon Lat Elevation dx dz subtype
Beach (AGL) 10.0 No 0=chain,1=ring Lon Lat subtype
Line (straight) 8.5 No 0=chain,1=ring Lon Lat
Line (curved) 8.5 No 0=chain,1=ring Lon Lat Ctrl Lon Ctrl Lat
String 8.5 No Spacing (meters) Lon Lat
String (Curved) 8.5 No Spacing (meters) Lon Lat Ctrl Lon Ctrl Lat
Draped Polygon (no UV) 8.5 Yes Texture Heading Lon Lat
Draped Polygon (curved, no UV) 8.5 Yes Texture Heading Lon Lat Ctrl Lon Ctrl Lat
Draped Polygon (with UV Map) 8.5 Yes 65535 Lon Lat S T
Draped Polygon (curved, with UV Map) 8.5 Yes 65535 Lon Lat Ctrl Lon Ctrl Lat S T Ctrl S Ctrl T
Autogen Block 10.0 No Block Code + 256 * (Height / 4) Lon Lat
Autogen String 10.0 Yes Number of Active Sides + 256 * (Height /4) Lon Lat

For forests, the density is a scaling factor–255 makes the maximum number of trees, 0 makes none. This control is multiplied by the rendering settings to set a final number of trees. Tree density will not exceed the maximum possible density from the .for file.

X-Plane 10 : in X-Plan 10, a packing code is added to forest density. 0 gives the default behavior of filling the polygon with trees. 256 gives the behavior of plotting trees along every line of the polygon, treating each contour as a poly-line. 512 gives the behavior of plotting a tree on each point in every contour. Note that:

  • Poly-lines are not auto-closed with line filling (to allow for U shapes) so you must duplicate the final point to make a ring.
  • In point-fill mode, all points are equal, so there is no advantage to using contour rings.

For beaches, the parameter can specify a ring, which connects the end point to the beginning. This will create a correct texture transition from the end to the beginning. The dx and dz coordinates for the beaches are a normal vector, similar to a DSF’s normal vector, and are used for draping the beach. The subtype parameter is an integral subtype which describes which beach from within the .bch file is used.

X-Plane 10 : in X-Plane 10, the normal vectors and elevation of beaches can optionally be omitted, as X-Plane derives this information on the fly.

For draped lines (.lin), object strings (.str) and draped polygons (.pol) if bezier coordinates are present, then bezier curves are generated.

For object strings, the spacing of objects is controlled by the polygon parameter. For draped lines, the polygon may be treated as a ring or chain. Like beaches, best results come from using the ring feature rather than duplicating the first point. For a draped polygon, texture coordinates (ST from 0 to 1) may also be included–the parameter value 65535 indicates this.

X-Plane 12: in X-Plane 12 for draped polygons whose parameter is not 65535 (e.g. texture projected by heading, not UV mapped) if the heading exceeds 359, then the integral heading divided by 360 is used as 128th of a degree and added to the heading modulo 360, to provide sub-degree resolution. In other words:

real heading = (dsf heading % 360) + floor(dsf heading / 360) / 128.0

For both autogen blocks (.agb) and autogen points (.ags) the height of variable height elements is encoded in the upper 8 bits of the parameter (e.g. * 256) and represents the metric height divided by four. (In other words, some precision in height is lost to allow for a wider range of building height.

For autogen blocks, the lower 8 bits of the polygon represent a spelling set code – this is used to look up which “spelling set” in the autogen block to use. A typical use is to use different tile arrangements based on different block codes. X-Plane’s global scenery, for example, uses codes 0-7 to indicate whether the “back 3” walls are road adjacent or not.

Autogen strings represent the strangest polygon feature of all. Unlike other polygons, the contours in AGS are interpreted as poly-lines ( not closed polygon rigns!); the AGS is required to be a closed polygon with holes when all contours are considered.

The first N contours (where N is the lower 8 bits of the polygon parameter) will spawn autogen buildings; the rest of the contours are used only to create a closed polygon-with-holes area.

A few examples may help clarify autogen strings:

  • In the case of a single rectangle city block with houses on all sides, there would be one contour with 5 points (the start point must be duplicated) and the polygon parameter N=1.
  • In the case of a single rectangle city block where the north side has no houses, there would be two contours: the first contour would contain the NE, SE, SW, NW points and the second woul contain the NW, NE points. N=1 because only the first contour has houses.
  • In the case where only the east and west sides of the block have houses, there would be four contours: NE,SE then SW, NW, then NW, NE, then SE,SW. N=2. Note that the first two and last two contours can swap with each other.
  • In the case where a city block has houses on all sides but a lake in the middle, the first contour is the block (with a dupe point to close), the second is the lake (with a dupe point to close) and N=1.

X-PLANE 12: in X-Plane 12, a forest in point mode (and only point mode) can optionally have a third and fourth data coordinate plane; these planes are used to control tree height on a per tree basis and vertical registration if desired. There is no mode to get randomized heights with fixed MSL locations.

Road Types and Coordinate Organization

Only one road.net definition may be used per DSF. Subtypes within the road file are used to create variety.

Road network files use 4 coordinates.

  1. Longitude
  2. Latitude
  3. Elevation
  4. Junction ID

Road segments are connected via junction IDs with the following rules:

  • The DSF file’s junction IDs must start at 1 and contain no gaps. 0 is reserved as the “no junction” flag.
  • A road chain must start and end with a junction.
  • A junction must be used any time an intersection is desired.
  • A junction must be used any time a road chain changes subtype.
  • All nodes that share the same junction code must share the same coordinates.
  • A junction should not be used for nodes that are designed only to change the path of a road (“shape” points), because the processing overhead is higher for junctions.

X-Plane 10 : if the road.net specifies a draped road type then the elevation should be a stacking layer number (0 for the ground, then 1, 2, 3, etc.) for all junctions to specify overpasses. Within the chains, the shape point should be 0 for a vertex and 1 for a bezier curve control point. There must be no more than two consecutive control points in a road. (That is, quadratic and cubic bezier curves are allowed but no higher degere polynomials.) All bridge-crossing roads should use a junction so that the sim can ensure separation.

DSF Feature Extensions Via Comments

Airport-ID Based Exclusion/Filtering

Starting in X-Plane 10.45, sections of DSF overlays can be filtered by airport ID. The mechanism works as follows:

  1. The properties table contains sim/filter/aptid properties that establish an indexing scheme to particular X-Plane airport IDs.
  2. X-Plane determines whether a given airport ID is “owned” by the scenery pack that contains the DSF. If the airport is in the apt.dat of this pack (and not in a higher-priority pack) then the airport ID is owned.
  3. When a filter directive sets the filter to a given index, all following network segment, polygon, and point features are excluded unless the airport is part of this pack. Filtering is done at the interpretation level; DSF command state is not skipped.

Filter commands are encoded via a DSF comment with the following format six-byte format:

uint16 comment type - must be 1
sint32 airport index - can be -1 to clear the filter or [0...properties)

Like all DSF command table data, these ints are little endian. Filter state is considered to be “off” by default.

The intent of this feature is to allow a DSF to place objects that are “part” of an airport and will be removed if a higher priority pack replaces the airport, even if the higher priority pack does not correctly provide exclusion zones.

AGL-Offset OBJ Placement

Starting in X-Plane 11.50, explicit-height OBJs could have their datum changed from MSL to AGL. The format of the comment is:

uint16 comment type - must be 2
sint32 AGL mode - 0 for MSL, 1 for AGL

The flag affects all point placements for OBJs until the mode is further changed; the default mode is MSL.

Overlay DSF Restrictions

DSF overlays have restrictions on the types of files they may use:

  • [X-Plane 8:] Road networks are not allowed in overlays.
  • Mesh patches are not allowed in overlays.

X-Plane 9 relaxes the road network rule–in X-Plane 9 a DSF overlay may contain a road network, but the one-.net-per-DSF rule still holds. When a DSF overlay has a road network and the base mesh does too, the junction IDs between the two do not connect.

Guidelines for DSF Extension

  • Consider all properties starting with “sim/” as reserved.
  • Do not add extra coordinates to vertices beyond what is in this spec.

Data Validation

These rules place limits on the kinds of data that can be specified for various art assets.

Base Mesh

  • Every point within the lat-lon rectangular boundaries of the DSF must be covered by exactly one triangle that is ‘hard’ (meaning the hard flag in its parent patch is set).
  • It is illegal for a triangle’s vertex to be located on the edge of another triangle; triangles must only meet vertex-to-vertex, not vertex-to-edge. (In other words, there can be no “T” junctions in the mesh.)  Triangles meet at vertices if the coordinates of their vertices have the exact same lat, lon and elevation bit-values.

Objects/AGPs

  • Objects must be within the DSF lat/lon boundaries.
  • Object heading should be between [0 and 360).

Polygons

Area rules (these apply to facades with roofs, draped polygons, filled forests, AGS and AGB).

  • All polygons must have counter-clockwise winding for exteriors and clockwise winding for holes.
  • Polygons must not be self-intersecting.

Line rules (these apply to all polygons except for forests in “points” mode).

  • Polygons must not have zero length sides.

Roads

  • All roads chains must be made of at least one segment.
  • All road segments must have positive length.
  • It is illegal for a road segment to reverse direction (E.g. have a 180 degree turn).
  • A junction must not have two roads entering the junction at the same heading and the same level.
  • No more than two shape points within a chain can be bezier control points. (In other words, a cubic bezier is the highest degree bezier supported in curved roads.)
  • While a bezier control point may be outside the DSF boundaries (typically the point pools contain some margin to allow this) the actual path of the road segment must remain within the DSF boundaries.

While it is not necessary, it is recommended that crossing roads share a junction at the crossing point with the roads on different levels; X-Plane can use this information to try to ensure that the roads are not reordered vertically due to the road draping and smoothing process.

Comments Off on DSF Usage In X-Plane

DSF File Format Specification

Revision History:
     2/12/12   Updated for X-Plane 10
     6/ 2/10   Updated for Wiki
    11/12/06   Fixed incorrect size of counts for triangle primitives
     5/08/05   Update for object prioritization
     1/19/04   Initial Draft

DSF Overview

The Distribution Scenery Format (DSF) is the file format for scenery in X-Plane 8 and 9. A DSF file describes the appearance and some physical properties of a 1×1 degree section of the earth (or another planet).

This section describes the high level concepts of DSF. The DSF Specification section describes the file format precisely on a byte-by-byte basis.

This specification mentions cases where X-Plane deviates from the abstract DSF specification, or imposes further limitations.

DSF as Part of the Scenery System

Like the X-Plane 7 scenery system, X-Plane 8 and 9 scenery comes in packages consisting of a series of DSF files covering 1×1 degree surfaces, as well as a number of bitmap files and other helper text files such as objects.

Collectively the bitmap and text files that are referenced by DSF files are known as graphic resources.

DSF (Distribution Scenery Format) files contain compressed scenery data optimized for X-Plane.

Projection and Coordinates

DSF files represent locations on the Earth via degrees of latitude and longitude horizontally and meters relative to mean sea level vertically.

The Earth is approximated as the WGS84 ellipsoid.

All DSF coordinates are stored as sets of fixed point integers that are scaled by 32-bit floating point numbers. This math is done in 64-bit floating point precision. Points are translated to a local Cartesian coordinate system before geometry is constructed. This means that a straight line between two points in a DSF file will be straight in 3-d space, not in the geographic coordinate space of the DSF file (which is curved).

Properties

The metadata section of a DSF file contains a number of properties, consisting of a string name and a string value. Property names are hierarchical, with the ‘/’ character reserved for hierarchy specification.

Compression and File Hashing

DSF files are not internally compressed. Client applications may choose to support reading and writing of compressed DSF files, and can distinguish between a compressed vs. uncompressed DSF file by the cookie at the beginning of the file – XPLANE vs. PK or 7Z for example.

X-PLANE NOTE: X-Plane 9 does not support reading compressed DSF files.  X-Plane 10 supports uncompressed and 7Z-compressed DSF files, with the global scenery distributed in 7Z-compressed format.

DSF files contain a 128-bit MD5 hash at the end of the file describing the previous contents of the file. This allows X-Plane or other programs to quickly detect whether a DSF file has been modified and rebuild caches as necessary.

Compatibility Goals

DSF files are meant to be backward compatible but not forward compatible. New features are added via new atoms, new commands, and extensions to the definition file formats. New programs can identify different versions of DSF, and generally a program that can read the current DSF version will be able to read all older DSF versions without modification. Older programs will not be able to read newer versions of DSF.

Note: Conceptually forward compatibility doesn’t make sense for scenery files. Consider a new scenery file that uses a new feature to represent a section of the world. If the old reader skips the new data then that part of the world will simply be missing or partially rendered. There is a data consistency problem with forward compatibility.

Definition Files and Building Blocks

A DSF file is essentially a 3-d model of a section of the earth, consisting of textured triangles and other polygons, with associated physical properties. However, specifying the entire Earth as triangles would make DSF files prohibitively large. Instead, DSF provides four types of building blocks from which models are built:

  1. Mesh Patches. The surface of the earth is created via a series of 3-d triangles. The appearance of these triangles is defined by a terrain type
  2. Objects. A 3-d model can be placed on the surface of the earth (as specified by the mesh) and rotated.
  3. Polygons. A polygon can be extruded to form a building or filled to form a forest.
  4. Vectors. A vector network can be extruded to form a transportation network, etc.
  5. Raster Data. Starting with X-Plane 10, individual raster layers (2-d arrays of numeric values) can be saved directly into a DSF

For each type of building block, a definition file specifies how that building block will be rendered. Definition files are placed in the scenery package with the DSF files.

Mesh Patches

The DSF format does not dictate a particular configuration for the terrain mesh. Instead the mesh is a loose set of triangles that X-Plane indexes in memory. The mesh is divided into patches, or clusters of nearby triangles with the same terrain type. Each patch in turn may have multiple levels of detail (LOD), or versions of the terrain appropriate for different distances.

Mesh patches use a terrain type file to define their texture. The terrain type defines the texture(s) to be used for the texture, and may also optionally provide resolution information for projecting the texture onto the triangles or other texture processing information.

Mesh triangles may be overlay triangles (implying that they are drawn over existing mesh, with appropriate measures taken to prevent Z-buffer thrash), and they may be physical triangles, meaning they are used to calculate collisions and landings. The physical surface properties of the hard triangle come from the terrain type file.

Mesh primitives replace the 200×150 grid from .env files. Terrain types replace custom custom textures and land uses.

Objects

Objects can be placed on the surface of the scenery (as defined by the mesh) and rotated around a vertical axis. Object files (OBJ) are used to define the appearance of the object.

DSF Objects are the same as custom objects in an .ENV file. Default objects are no longer supported; however, X-Plane comes with a library of custom objects that may be used by any DSF file.

Polygons

Polygons are optionally nested, optionally closed vector paths along the surface of the earth (as defined by the mesh). Polygons are instantiated by polygon definition files. Each polygon has one parameter value. Currently two types of polygon definition files are supported:

  • Facade definition files extrude 3-d buildings along the polygonal path. The definition file describes the way the building is textured and the parameter defines the height of the building in meters.
  • Forest definition files fill the area within the polygon with 3-d objects (e.g. trees). The definition file describes the type and fill pattern of tree placement, and the parameter controls density.

Polygons provide additional ways to create buildings with specific varying heights and also provide an option for creating 3-d vegetation.

Vectors

Vector primitives create pathways along and above the surface of the earth along vectors. Vector data consist of a series of junctions and a series of segments connecting the junctions. Each vector segment may be a straight line or bezier curve.

The vector definition files describe the appearance of vectors, both on their own and when they connect at junctions. Network primitives replace the various pre-defined vectors found in X-Plane 7’s .env files.

In a DSF file, each junction is numbered, starting at the index 1 and increasing consecutively within the DSF file. (The index zero is reserved.) These junction numbers allow X-Plane or another reader to rapidly reconstruct the network topology of the vector structures, and clearly define when two vector chains intersect.

Raster Layers

X-Plane 10 allows for raster layers to be directly encoded into a DSF. Each raster layer has a name in the definition atoms, and meta data defining its pixel format and dimensions. How the raster data is interpreted is defined by X-Plane.

Building Block Definition Extensibility

Building Block Definition files are text files. The individual definition files can be extended to allow for more powerful representation of the various building block types.

The parameter for polygons can be interpretted as necessary by the polygon definition files.

The terrain mesh can be extended to have additional per-vertex information, which can then be used by terrain type definition files. For example, in the default DSF scenery, some vertices have a ratio of plant coverage on each vertex, and this is used to blend textures.

Chunky File Format

The outer level of DSF files is chunky (also sometimes called atomic), meaning each section of the file has a uniform header describing the ID of the file section and the length. This allows programs to find the data they require without parsing unknown or unimportant parts of the file. It also allows programs to store extra data in a DSF that X-Plane will ignore.

Where possible, standard encodings are used for the various atoms in a DSF file, reducing the amount of code needed to parse or write the file.

Point Pools

The 2-d, 3-d, and other coordinates in the file are stored in point pools. A point pool is a collection of N-dimensional points that are scaled and offset in a uniform matter. Point pools are always stored as fixed point fractions that are interpreted over a range that is specified once for each data plane in the point pool.

In most cases there are special versions of the primitive commands that allow a primitive to be built along consecutive points in a pool. Point pools should be constructed to keep primitive vertices in order when vertices are used only for one primitive.

Definition Tables

The definitions for primitives are stored in tables; their order defines index numbers used to reference them. The tables store the file name for the text file defining the primitive.

Atom Extensibility

New atoms may be added to DSF in future versions via new atom IDs. Atom IDs consisting entirely of capital letters and numbers are reserved for the DSF specification. Other atom IDs can be used for private data.

Command-Based File Format and State

While atoms define the sections of a DSF file, commands accomplish most of the work of defining the file’s contents. The command section consists of a series of command opcodes, each of which instructs X-Plane to add a primitive to the current scenery, or change internal state during the DSF file parsing. The various state maintained while parsing a DSF file is reset at the beginning of the DSF file and maintained continuously through all commands; this state serves primarily as a technique to compress similar data. State must be specified before utilized in a DSF file.

Current Definition and Current Road Subtype

Each building block in a DSF file is instantiated using a definition; the current definition is maintained state that indicates what definition the next command will used. The set definition commands change this state. One current definition index number is maintained for all primitives. (This means that if an object index 0 follows a mesh of terrain type 0, no set definition is needed.)

Selected Pool

Before a coordinate from a pool can be used, the pool must be selected. Selecting the pool decides which of multiple geometry pools will be used. Only one pool can be selected at a time.

Junction Offset

Unlike other primitives, vector networks use a 32-bit point pool. A 32-bit point pool is precise enough to allow all data to be encoded in one pool. Since this pool might contain more than 65535 points, a junction offset is maintained and added to indices for most junction commands.

Note: this feature exists primarily for historical reasons. However it is used by the default scenery renderer’s DSF writing library because it simplfies the process of organizing vector data to not have to worry about point pools.

Terrain Patch LOD and Flags

Each terrain patch has some properties associated with it; these properties are considered state. When a new patch is created, if these properties are not changed, the new patch has the same properties as the old one.

Command Extensibility

The addition of new DSF commands will break compatibility; this represents a change to the DSF spec.

Building-Block Related Implementation Issues

Point pools may have any number of data planes; the interpretation of those planes depends on the building block. All pools start with longitude and latitude and have at least two planes. Extra planes are ignored (and allowed for future expansion). Having too few planes is an error.

Point Primitive Rotation Plane

Point primitives require at least three planes: a longitude, a latitude, and a rotation. The rotation is performed around the gravity vector, a vector pointing straight down toward the center of the earth. The object sits on the surface defined by the mesh. If the terrain is sloped, the object may end up partially under ground; negative object Y coordinates allow for underground geometry.

Rotations are stored in degrees.

Polygon Parameters and Direction

A polygon primitive defines a polygonal path or set of paths. When a polygon primitive actually contains nested polygons (to form holes), each polygon is known as a winding. A few restrictions on polygons and windings:

  • Polygons may be concave or complex, but no edges can ever cross (except for ends touching) across any windings.
  • If a winding is an outer boundary of a polygon (meaning the interior of the winding is part of the polygon, it must be counterclockwise. If a winding is an inner boundary (meaning inside the winding is outside the polygon, e.g. a hole), it must be clockwise.
  • Each winding must be after every winding that contains it in the ordering of the winding list.

Every point in the polygon sits on the surface of the mesh.

Cross-Pool Vector Linkage

The vector structures for DSF are more complex than those of ENV because they provide network topology. The building blocks of the network are junctions and chains.

  • A vector segment is a single straight line or bezier curve between two points consisting all of the same type of vector.
  • No segments can touch each other except at their ends. (However, if segments cross above and below each other in 3-d space, this is legal.)
  • A chain is a series of connected vector segments such that the entire chain is of the same type, and each segment connects to exactly one other segment except at the ends of the chain.
  • The ends of the segments within the chain are shape points. They define the shape of a chain but do not represent a junction between segments.
  • The two ends of the chain are junctions.

In a DSF file, each junction is assigned a unique 32-bit ID, starting at 1. Two chains form a junction if their end nodes have the same unique 32-bit ID. Only junction ID is used as a test to see if two chains meet at a junction.

In the point pool for vectors, the 4th data plane (after longitude, latitude and elevation) is used for junction IDs. Zero is used to indicate that the point is a shape point and not a junction.

There may be a complete chain whose geometry indices are not within 65536 of each other; in this case a special segment command is provided that allows for arbitrary 32-bit indices to be specified.

Vector Type Indices

Unlike other definition files, a single vector definition file contains multiple subtypes (also referenced by index). This allows a single definition file to provide specialized images for the crossing of vector subtypes that are both from the same definition file.

Mesh State

The scenery mesh is divided into patches. A patch is simply a collection of nearby triangles that have all of their attributes in common. Those attributes are:

  • A level of detail range in meters indicating the range the patch can be seen at.
  • The definition number defining the patches terrain type.
  • Whether the patch needs to be treated in the physics model for X-Plane.
  • Whether the patch is an overlay onto another patch (and must be treated for z-buffer thrash).

A patch can either be textured by providing per-vertex texture coordinates or by using a projection equation. The projection equation is used for the texture but not necessarily the mask.

The precise requirements and interpretation of planar geo data for a mesh patch are a function of both the mesh state for that patch and the terrain definition file itself. A precise description of X-Plane’s mesh behavior is documented in the .TER terrain type file format specification.

Requiring Objects and Facades to Be Drawn

Starting with X-Plane 8.10, if X-Plane sees the properties sim/require_object or sim/require_facade in a DSF file, it will use the value of this property to force certain objects to be drawn even at lower settings.

The value associated with these properties is a string containing two numbers separated by a slash. The first number is the X-Plane rendering level (0-6) at which to require the object, and the second the index number of the first object or facade definition to be affected. The property may be included multiple times. For example:

Property Value
sim/require_object 4/70
sim/require_object 2/74

In this example, all objects whose definition index is 70 or higher must be drawn when the object detail setting is 4 or higher. All objects with an index of 74 or higher must be drawn if the object detail setting is 2 or higher. (Note that the union of all rules is taken: so even though object definition index 75 is covered by both rules, the lower setting of 2 applies—these objects will be visible at rendering settings of 2 or lower.)

To take advantage of this, a DSF may need to be organized so that “high priority” objects have higher (later) indexes in the file.

DSF Specification

Data Encoding

Endian

DFS files are binary little-endian files. Floating point numbers are stored in IEEE 32-bit or 64-bit format.

DSF File Structure

A DFS file is atomic, which is also sometimes called chunky. Each ‘atom’ of data has a size and ID at the beginning.

Image:dsfspec_filelayout.gif

The container format for DSF files is made up of the following sequential sections.

Header

The header contains an 8-byte unique ASCII cookie identifying this as an x-plane DSF file. The cookie will be the ASCII characters ‘XPLNEDSF’. This 8-byte unique cookie is followed by a 32-bit integer master file format version. The current version number is 1.

Atoms

Following the 12-byte header is a variable number of atoms. Each atom consists of a 32-bit atom ID followed by a 32-bit unsigned byte count for the size of the atom, including this 8-byte header. The contents of the atom depend on the atom’s ID. Atom IDs may be repeated, so the order of the atoms within the file may be significant. The DSF file may also place requirements on the order of the atoms within the files.

Endian Note: since atom IDs are 32-bit integers (and not arrays of 4 characters), they are subject to endian-swapping. For example, viewing a DSF file in a windows hex editor the GEOD atom would read DOEG since ‘GEOD’ is really a 32-bit character constant that must be swapped.

The atom section is variably sized. The atom section ends 16-bytes before the end of the file and can be thought to be the entire file with the header and footer removed.

The format of the contents of an atom depend on the ID of the atom; different atoms may have different formats. Atoms may contain subatoms; usually the entire contents of the atom will be atoms in this case, but this is dependent on the details of the specific atoms in question.

Footer

The footer of a DSF file is a 128-bit MD5 signature of the previous contents (not including this signature). This forms a unique ID for this file that allows clients to detect revisions in content.

Common Atom Formats

Where possible, the same format is used for atoms that contain similar data; this is to reduce the amount of code necessary to read or write DSF files. This section describes some of the typical encodings of atoms.

 

Atom of Atoms

This format encodes a number of atoms within a single atom, forming a hierarchy. The entire content space of the super-atom contains sub-atoms end-to-end. The number of sub-atoms may be found by traversing the atom until the total number of bytes in the super-atom have been processed.

String Table Atom

A string table atom contains a series of null-terminated C-strings packed with one null byte between each one. No padding/byte alignment bytes are necessary. The number of strings is determined by traversing the entire atom. A null character on the final string is necessary for the final string.

Note: this is necessary to allow an empty string as the last string. It also allows the strings to be used in-place in a memory mapped file.

The orders of the strings in a string table is significant; the string table atom forms a natural numbering starting at 0 for each string. Empty strings may be encoded via a single null character.

Planar Numeric Atom

A planar numeric atom contains one or more arrays of numbers in planar format. For example, a table of 100 latitude/longitude pairs would contain all of the latitudes first and then all of the longitudes. The numbers may be either fixed point, integer or floating point. The format of the numbers and number of planes are determined by the specific atom type (e.g. these are flexible within a planar numeric atom). This metadata is not written into the file itself; the reader must understand what kind of planar data to expect based on the atom ID.

Note: the motivation for a planar structure is to keep similar-typed data together. In a lat/lon array, the latitude will be similar in range, as will the longitude. Metadata is not written to the file itself because the client must be able to interpret the data it reads, and therefore knows enough about a given planar numeric atom to provide the metadata as a key to reading it. It is unlikely that the numeric needs of low level atoms will change without the file format itself changing massively.

Both the number of data tuples and the number of planes are written into the planar numeric atom.

A planar numeric atom’s data plane may be compressed in two ways (which are not mutually exclusive) for four possible encoding forms:

  1. Raw data. Each number follows sequentially.
  2. Differenced. Each number is subtracted from the previous and then written to the file. Wrapping rules apply to integer number types.
  3. Run-length-encoded. A byte count and flag indicate the number of similar numbers, followed by the number, or the number of individual numbers, followed by the numbers.
  4. The array may be differenced first and then run-length encoded.

Note: the goal of differencing is to decrease the range of values that appear when data is always closely spaced. The goal of run-length-encoding is to get a big savings for constant data.

The number of items in each plane of the array must be the same, and each item must have the same number of planes. The format of the atom is:

  • A 32-bit item count for the number of items in the array.
  • An 8-bit plane count for the number of planes in the atom.
  • For each plane, a 1-byte enumeration for the encoding type. These are: raw = 0, differenced = 1, RLE = 2, RLE differenced = 3, followed by:
  • Variable length encoded data depending on the compression type and numeric format.

The run-length byte for run-length encoding is an unsigned 8-bit character. The high-bit indicates a repeat of up to 127 of the following number. The high bit cleared indicates up to 127 non-repeating elements.

DSF is little endian, but differencing is done in the machine’s endian format (e.g. differencing is done logically on the data, not on the file). RLE is a bit-wise operation and is not endian-sensitive.

DSF Atoms

The various file sections of a DSF file are each contained within separate atoms, with their own IDs. The header ID is listed on the header of each section of this specification.

Header Atom (‘HEAD’)

This is an atom of atoms containing information about the DSF file. The HEAD atom is an atom-of-atoms in the top level of the file and currently contains one subatom the PROP atom.

Properties Atom (‘PROP’)

The properties atom is a string table atom with an even number of strings; each consecutive pair of strings represents a property name and a property value. This allows for arbitrary metadata to be placed inside a DSF file.

Properties starting with sim/ are reserved for public X-Plane use. Properties starting with laminar/ are reserved for X-Plane private use. All other prefixes may be used for private data. When storing private data in the DSF properties metadata section, prefix the property with your company or organization name to prevent conflicts.

The following properties are currently defined:

Property Default If Missing Definition
sim/west (Required) The western edge of the DSF file in degrees longitude.
sim/east (Required) The eastern edge of the DSF file in degrees longitude.
sim/south (Required) The northern edge of the DSF file in degrees latitude.
sim/north (Required) The southern edge of the DSF file in degrees latitude.
sim/planet earth The planet this DSF belongs to, one of ‘earth’ or ‘mars’.
sim/creation_agent (Blank) The name of the program that created the DSF file if known.
sim/author (Blank) The name of the author of the DSF file if known.
sim/require_object N/A Requirements for displaying objects (see below).
sim/require_facade N/A Requirements for displaying facades (see below).

The sim/require_object and sim/require_facade properties specify that objects and facade whose definition index is greater than or equal to a certain number must be drawn by the sim. Normally the sim may draw only a fraction of the objects or facades in a DSF, based on the user’s rendering settings. By including these properties, you can force X-Plane to always draw objects.

Definitions Atom (‘DEFN’)

The definitions atom contains a series of subatoms that define the various ‘definitions’ used within the DSF file. DSF files first reference a few common definitions and then use them in a larger number of instances. Each definition comes from an external file, allowing definitions to be shared among DSF files or even between scenery packages. (This allows custom scenery packages to use a variety of x-plane-default definitions.) The various definition formats are described in other specifications.

The definition atom is an atom-of-atoms syntactically. All definition sub atoms define a series of partial file paths by being string table atoms. The forward slash (‘/’) should be used as the directory separator. All definitions are referred to by zero-based index in the rest of the file. A maximum of 65536 entries are allowed in any one table. The extension for the file path is always included.

The following four atoms sit inside the definitions atom: the TERT, OBJT, POLY and NETW atoms.

Terrain Types Atom (‘TERT’)

The terrain types atom lists a number of external .ter terrain-definition files that define the various terrains used in the DSF file. Terrain-definition files describe the set of textures to be used for the terrain (dependent on season) as well as other metadata (for example, is this terrain hard, bumpy, etc.).

You may also use .png or .bmp files directly to specify terrain types. See the .ter file specification for info on both the .ter file format and on using PNG and BMP files here.

Objects Atom (‘OBJT’)

The objects atom lists a number of external .obj object files that may be ‘placed’ repeatedly in the DSF file. With DSF files there are no default object types; radio stacks, sky scrapers, etc. are all created using either Object or Prototype (see below) files.

The Polygons Atom (‘POLY’)

The prototype atom lists a number of external polygon definition files that may be usde within the DSF file.

Polygon definitions can be either facades or forests; X-Plane determines the type of polygon definition from the filename extension.

Vector Network Atom (‘NETW’)

The network atom lists a number of external .net network definition files that may be used within the DSF file. While individual objects are placed separately in a file, roads and other ‘networks’ intersect each other. A network definition file describes the appearance and geometry not only of multiple different types of roads (or other segments), but how to build blended intersections of those segments.

X-PLANE NOTE: X-Plane 8 and 9 can only accept one network definition per DSF file; use vector subtypes to define multiple road types, etc.

Raster Definition Atom (‘DEMN’)

New to X-Plane 10: The raster definition atom defines the names for each raster layer contained in the DSF. The order of raster data in the subsequent atoms matches the order of names in the raster definition atom.

Geodata Atom (‘GEOD’)

The geodata atom defines all of the coordinates for all geometry in the DSF file. Coordinates are separated from instantiations of definitions to encourage recycling and reduce file size.

The Geodata atom is an atom-of-atoms at the root of the DSF file. The GEOD atom contains zero or more POOL, SCAL, PO32 and SC32 atoms.

16-bit Coordinate Pool atom (‘POOL’)

This atom is a planar numeric atom with a variable number of planes and 16-bit unsigned int data, establishing a coordinate pool. Multiple pool atoms sit inside the Geodata atom, so the index number of this coordinate pool is based on its order within the geodata atom, starting at 0. Points are stored in sixteen bit unsigned short format, representing values from [[0-65536)]].

16-bit Scaling Range Atoms (‘SCAL’)

For each pool atom there is also a scaling range atom in the GeoData atom, telling how to process the point pools. Each scaling atom contains an array of 32-bit floating point numbers. There are two floats for each plane in the corresponding point pool, the first being a scaling multiplier and the second being an offset to be added to the points. These values are applied in double-precision.

POOL and SCAL atoms are applied based on their order within the file, e.g. the 5th POOL atom within the GEOD atom is scaled by the 5th SCAL atom in the GEOD atom. There must be an equal number of POOL and SCAL atoms. The data planes in the pool atom correspond to the values in the scal atom, so if there are n planes in a POOL atom, its corresponding SCAL atom must have 2n 32-bit floats.

32-bit Coordinate Pool Atom (‘PO32’)

The 32-bit point pool atom is the same as the 16-bit point pool atom except that each data element is a 32-bit rather than 16-bit unsigned int. 32-bit point pool atoms are used for vectors; all other building blocks use 16-bit point pools.

32-bit Scaling Range Atom (‘SC32’)

The 32-bit scaling range atom is the same as the 16-bit scaling range atom except that it is appleid to 32-bit point pool atoms. In other words, the 3rd SC32 atom scales the 3rd PO32 atom. The atom is still formed of 32-bit floats, but like the 16-bit scaling atom, the conversion is done in double-precision floating point.

Raster Data Atom (‘DEMS’)

New to X-Plane 10: The raster data atom is an atom of atoms containing the meta data and raw data for each raster layer in the DSF.

The raster data atom contains one raster layer information (‘DEMI’) and one raster layer data atom (‘DEMD’) for each raster layer. The order of information and data atoms must match with the raster definition atoms. This is how names, meta data, and raw data are matched in the DSF.

Raster Layer Information Atom (‘DEMI’)

The raster layer information atom contains the structure information for one raster layer. The atom is a record of DEM information, encoded as follows:

Field Encoding Description
Version uint8 Version of DEM record; set to 1
Bytes Per Pixel uint8 The number of bytes for each pixel. Should be 1,2, or 4 depending on encoding
Flags uint16 Encoding Flags – see below
Width uint32 Width of the DEM east-west in pixels
Height uint32 Height of the DEM north-south in pixels
Scale float32 Scaling factor to apply to DEM pixels post-load
Offset float32 Offset factor to apply to DEM pixels post-load

Each final DEM pixel is multiplied by scale and then offset is added.

The flags field defines a number of other DEM properties:

  • The low 2 bits tell the number type for the DEM data:
    • 0 = floating point (bytes per pixel must be 4)
    • 1 = signed integer (bytes per pixel must be 1, 2 or 4)
    • 2 = unsigned integer (bytes per pixel must be 1, 2 or 4)
  • A flag value of 4 (bit 3) defines the data as post-centric, as opposed to area-centric.
    • In post-centric data, the pixel values at the edges of the DEM exactly lie on the geometric boundary of the DSF.
    • In point-centric data, the outer edge of the pixel rectangles lie on the geometric boundary of the DSF.
Raster Layer Data Atom (‘DEMD’)

The raster data atom contains the actual raw raster data, sitting directly in the atom’s payload, one DEMD atom per layer. The information atom above tells how to inerpret this raw data.

Commands Atom (‘CMDS’)

The commands atom contains a list of commands used to actually instantiate the scenery file by applying prototypes, objects, etc. at the coordinates available in the geodata atom.

Commands consist of a command ID and additional information in series. Command order is arbitrary but may be optimized for file size by the file writer. Command order does not affect display order when X-Plane renders scenery; display order is affected by internal factors in the rendering engine.

The number of bytes used by a command is known through its type; unknown commands cannot be skipped. The commands are finished when the last command in the atom is parsed. All command IDs are 8-bit. Command ID 255 is reserved for future expansion. The format of the data following the command is based on the command ID.

All commands that include a range of indices list the first index, and one more than the last index. All commands reference 16-bit point pools except for vector commands, which reference 32-bit point pools.

DSF Commands

Each command is listed in order of ID; any data that must follow the command is listed below. Data items listed are:

uint8 Unsigned 8-bit integer.
sint8 Signed 8-bit integer.
uint16 Unsigned 16-bit integer.
sint16 Signed 16-bit integer.
uint32 Unsigned 32-bit integer.
sint32 Signed 32-bit integer.
f32 32-bit IEEE floating point.
f64 64-bit IEEE floating point.
State Selection Commands

These commands change the internal state of the DSF reader, affecting the results of subsequent commands.

COORDINATE POOL SELECT (ID=1)

The coordinate pool select command changes the current coordinate pool and establishes the longitude and latitude bounds that the first two fields are interpreted within.

uint16 zero based pool index
JUNCTION OFFSET SELECT (ID=2)

The junction offset select command specifies a 32-bit number that is added to all indices when referencing coordinates for vectors. This allows the use of a 16-bit vector command for vectors whose indices are greater than 65535.

uint32  zero based index offset
SET DEFINITION 8 (ID=3)
 uint8  zero based definition index
SET DEFINITION 16 (ID=4)

This is the same as above, but with a 16-bit index.

 uint16  zero based definition index
SET DEFINITION 32 (ID=5)

This is the same as above, but with a 32-bit index.

 uint32  zero based definition index
SET ROAD SUBTYPE 8 (ID=6)

This command sets the road subtype for the next vector-segment.

uint8  zero based road subtype
Object Placement Commands

These commands place an object on the surface of the mesh. A point pool must be selected and must have at least 3 planes, which are treated as a longitude, latitude, and rotation in degrees.

OBJECT COMMAND (ID=7)

This command places a single object based on the current definition.

uint16  coordinate index
OBJECT RANGE COMMAND (ID=8)

This command places several objects based on the current definition, using all vertices within a range.

uint16  index of first objectuint16  index of last object+1
Network Commands

The network commands instantiate complete chains and junctions for a network. Networks are formed by instantiating complete chains. The coordinate pool for a network segment must have either four planes (longitude, latitude, elevation, junction ID) or seven planes (adding on longitude, latitude, and a shape point for shaping).

Junction IDs are one-based consecutive unique integers. Junction IDs simply indicate what junctions will link to each other; if two junctions have the same ID but different spatial locations (based on the first three planes after transform), this is an error.

The junction ID zero indicates a shape point, meaning a coordinate that changes the shape of a vector but is not a junction.

All network commands except for the network-chain-32 command add the junction offset to all indices.

NETWORK CHAINS (ID=9)

This command creates one or more complete chains, using all of the vertices that are specifically enumerated. Complete chains are started or ended based on the presence of a non-zero junction ID.

uint8  number of coordinates

N x uint16  coordinate indices
NETWORK CHAINS RANGE (ID=10)

This command creates one or more complete chains, using all of the vertices within the range specified. Complete chains are started or ended based on the presence of a non-zero junction ID.

uint16  first coordinate inde

uint16  index of last coordinate+1
NETWORK CHAIN 32 (ID=11)

This command creates one or more complete chains, but rather than using 16-bit indices and the junction offset, they use explicit 32-bit indices and no offset. Use this command to create a vector when the indices span a range of more than 65536.

uint8  number of coordinates

N xuint32  coordinate indices
Polygon Commands

The polygon commands instantiate polygon primitives on the surface of the mesh. The selected plane must have at least two planes, which are interpretted as longitude and latitude. A per-polygon 16-bit parameter is interpretted based on the polygon definition.

POLYGON (ID=12)

This command instantiates a single polygon.

uint16  parameter valueuint8  number of indices

N x uint16  coordinate indices
POLYGON RANGE (ID=13)

This command instantiates a polygon through a contiguous range of vertices.

uint16  parameter valueuint16  first index

uint16  last index+1
NESTED POLYGON (ID=14)

This command instantiates a series of polygons, each with a distinct winding.

uint16  parameter

uint8  number of polygon windings

(for each of N windings)

   uint8 number of indices

   M x uint16 coordinate indicies
NESTED POLYGON RANGE (ID=15)

This command instantiates a series of polygons with distinct windings using a list of contiguous ranges. Each index starts a winding except for the last, which is one past the end of the polygon’s last point.

uint16  param value

uint8  number of indices (this polygon has N-1 windings).

N x uint16  indices
Mesh Commands

The mesh commands instantiate the terrain mesh as triangles. The mesh commands take planar data with at least 5 parameters, corresponding to to longitude, latitude, elevation, and a normal. Additional parameters are used to texture the patch based on the .ter terrain type definition file.

Mesh normals are defined as a pair of coordinates from -1.0 to 1.0 that represent the X and Z components of a normalized normal vector, where the positive X axis points east and the positive Z axis points south. The Y component is derived from the X and Z components by X-Plane.

There are three ways to specify triangles in a patch: triangles, strips and fans. Strips and fans are adjacent triangles that share common vertices. This lets you specify more triangles with less vertices, saving file size by up to a factor of 3.

For each type of triangle primitive (fan, strip, or individual triangles), there are three commands. One places triangles by a series of indices (up to 255 per command). Another uses a range of consecutive indices, saving file size. A third takes points from multiple point pools by specifying the point pool individually.

Note: why is there a cross-pool triangle command? Mesh vertices must have the exact same coordinates or else the mesh will have cracking – visible OpenGL artifacts. There may be rounding error associated with reducing the coordinate to a 16-bit integer via the scaling factors. Therefore if a coordinate V is included in two different point pools (for use in two different triangles), the two triangles may not actually line up at coordinate V. To guarantee alignment, both triangles must reference coordinate V in the same point pool, which means that triangles may have to span point pools to form the entire mesh.

TERRAIN PATCH (ID=16)

This command indicates that a new terrain patch is being created. The patch will have the same LOD range and flags that the last created patch had.

no data follows this command.
TERRAIN PATCH FLAGS (ID=17)

This command indicates that a new terrain patch is being created. The patch will have the same LOD range as the last patch, but new flags. The flags are:

Bit Value Indication
1 Physical – if set, this patch is used for collision detectoin. If cleared, the patch is drawn but not collision-checked.
2 Overlay – if set, this patch is drawn over another patch. Z buffering precautions are taken. The precise interpretation of this flag may depend on the terrain type.
uint8  new flag values
TERRAIN PATCH FLAGS AND LOD (ID=18)

This command indicates that a new terrain patch is being created. Besides specifying flags, a new LOD range in meters is also provided. Flags are the same as above.

uint8  flagsf

32  near LOD

f32  far LOD
PATCH TRIANGLE (ID=23)

This command creates one or more specific triangle for a terrain patch. Triangles must have clockwise rotation as seen from above for all triangle primitives.

uint8  coord count

N x uint16    coordinate indices
TRIANGLE PATCH CROSS-POOL (ID=24)

This command creates one triangle from multiple terrain pools. This is the same as the command above, except that a pool index is provided per vertex.

uint8  coord count

2N x uint16  pool ID/coord index pairs
PATCH TRIANGLE RANGE (ID=25)

This command creates a number of triangles based on the inclusive range of coordinate indices. The range must be a multiple of 3. Each set of 3 adjacent vertices is treated as a triangle.

uint16  first index

uint16  last index+1
PATCH TRIANGLE STRIP (ID=26)

This command creates a triangle strip. A triangle strip is a series of adjacent triangles that share two common vertices; for a series of points 1,2,3,4,5 as a triangle strip is equivalent to the triangles 123,243,345…

uint8  coordinate count

N x uin16  coordinate indices
PATCH TRIANGLE STRIP CROSS-POOL (ID=27)

This command creates a triangle strip, except the point pool is specified per vertex rather than referencing the current coordinate pool.

uint8  coordinate count

2N x uint16  poolID/coord index pairs.
PATCH TRIANGLE STRIP RANGE (ID=28)

This command creates a triangle strip for a series of consecutive coordinates.

uint16  index of first coordinate

uint16  index of last coordinate+1
PATCH TRIANGLE FAN (ID=29)

This command creates a triangle fan. A triangle fan is a series of adjacent triangles that share two common vertices; for a series of points 1,2,3,4,5 as a triangle fan is equivalent to the triangles 123,134, 145…

uint8  coordinate count

N x uin16  coordinate indices
PATCH TRIANGLE FAN CROSS-POOL (ID=30)

This command creates a triangle fan, except the point pool is specified per vertex rather than referencing the current coordinate pool.

uint8  coordinate count

2N x uint16  poolID/coord index pairs.
PATCH TRIANGLE FAN RANGE (ID=31)

This command creates a triangle fan for a series of consecutive coordinates.

uint16  index of first coordinate

uint16  index of last coordiante+1
Comment Commands

These commands allow arbitrary data to be embedded in a DSF file. The commands are defined by the size of the length field, allowing for larger or smaller comment blocks. The length field tells the length of the following comment data not including the length field itself.

COMMENT 8 (ID=32)
uint8  length

N x uint8  comment data
COMMENT 16 (ID=33)

This defines a comment of up to 65535 bytes.

N x uint8  comment data
COMMENT 32 (ID=34)

This defines a comment of up to 4294967295 bytes.

uint32 length

N x uint8  comment data
Comments Off on DSF File Format Specification