topic: Modeling

Building Custom 3-D Trees

Basics

New 3D trees in X-Plane consist of two main parts.

  • The first part of a tree definition is a 2-d billboard side view of the tree. These operate almost identically to X-Plane 11 trees. In X-Plane 12, the side billboard always faces the camera and there is only one per tree.
  • The second part is one or more 3-d models of the tree that are used for close up rendering. X-Plane dynamically animates the 3-d model based on wind parameters.

X-Plane automatically uses the 3-d model of the tree for close rendering and transitions to the 2-d billboard for far views for performance.

The two parts of the tree use separate texture and materials – the 2-d textures and material is shared by all 2-d billboards in the .for file; the 3-d textures and material is shared by all 3-d models in the .for file.

This guide requires some basic Blender knowledge like adding vertex groups and weight painting.

Textures

Both parts use separate textures – one for billboards and another for 3D parts. This is also the main prerequisite – all billboards and all 3D parts for all trees (all species) within a single *.for must be in a single texture sheet. A typical pair of textures may look like this:

01

X-Plane 12 offers a new type of shader called translucent. It was designed specifically for 3D vegetation. Unlike a typical PBR shader, it has a different usage of the normal map blue channel. Instead of metallic property, it determines translucency. White color means fully translucent (leaves) and black means no translucent (solid parts – trunk). Here is what a typical normal map may look like:

02

Creating Trees in Blender

In Blender, all parts are organized in a hierarchy and in collections by strict rules. A single tree consists of three (or more) parts. The top-level object is an empty wrapper (Its name is used for the tree name on export). This parent wrapper must have two child objects – a billboard (single vertical quad) and a 3D tree (mesh object).

03b

Each tree can have up to three 3D meshes. The reason is more per-tree LODs that can be additive. The typical use is: the first LOD mesh (0 to 500 m) has all triangles that are facing upward. The second LOD for a shorter distance (0 to 100 m) has all triangles that are facing towards the ground and thus don’t need to be visible for a bigger distance (bottom of branches). This is highly recommended for better performance, in particular when using high polycount on 3D meshes.

04

Trees are organized into forests using collections and each forest needs two levels. The top-level collection (right under the Scene root collection) is the forest itself. It consists of nothing but other collections. Those collections represent forest layers and all names must start with a numeric value (01, 02, 01-conifers, etc). This value is used as a tree layer index on the export. Obviously, all trees (with all their parts) must belong to some “layer” collection.

05

Parameters

All important parameters in Blender can be found in the properties editor but they’re spread across various tabs. All parts of a tree must be organized in the proper hierarchy and collection in order to get the options tab visible.

Global forest options can be found on the scene tab. Besides the main “Export” button the most important parameters here are the file name used on export, tree spacing, and global LOD distance. A separate tab for each existing root collection is shown. A collection is treated as a separate *.for on export once it has some filename entered.

06

The tree root object (empty wrapper) has all options on the objects tab. The “Weighted Importance” value is a relative occurrence of the tree within a forest layer. “Max tree height” is the size limit of the tree. The minimum height is determined from the real size of the tree billboard (in other words, trees are prepared in Blender in their minimum size).

3D tree mesh-specific options are on the object data tab. 3D tree mesh LOD values are set to 0 and 500 by default. This is also the recommended value for all trees that are intended to cast shadows because 500 meters is currently the default max shadow distance in X-Plane. Shorter distances might cause popping shadow artifacts, but for some types of meshes it is not important, such as bottom facing geometry.

In addition, both billboards and 3D meshes have material options on the material tab. It is recommended to use blend hash and normal translucency mode for both materials.

07

Adding Wind Effects

3D trees can sway in X-Plane’s dynamic wind. In order to do so the mesh needs additional vertex data. In Blender we have three vertex weight data channels: w_stiffness, w_edge_stiffness, and w_phase. These names are mandatory and case sensitive!

The stiffness channel (w_stiffness) is used to displace mesh vertices horizontally in the wind direction. The maximum distance of displacement (in meters) is defined by the stiffness parameter on the mesh data tab. It is a multiplier of the vertex data value.

08

Edge stiffness (w_edge_stiffness) is used to displace mesh vertices vertically (vertical oscillation or swaying).

Phase data (w_phase) is used to shift various branches’ movement in time. This can avoid uniformity in the look of the whole tree’s movement.

Stiffness and edge stiffness data might look very similar in most cases. Maximum weight value is on the tip of the branch and zero near the trunk. Phase data is different however. The whole branch usually has the same weight (any value in range 0 – 1).

09

On top of that the whole tree is bent by wind. This bend is calculated automatically from the ground to the top of the tree. The stronger the wind, the greater the bend at the top of the tree. There is a calibration value on the mesh data tab that can tweak the total amount according to tree height.

10

The default value of 1.0 is calibrated for a 10 meters tall tree. This value might change on the tree shape and the artist’s desires however. Here are a few examples:

10 m tree        1.0

20 m tree        0.5

30 m tree        0.3

5 m tree        1.6

Rock                0.0 (no bend)

Seasons

At this time the exporter has no automatic support for creation of seasons. It has to be done manually. To do so, make a copy of final *.for and change the texture to a different season variant. More info about seasons in different document (link?).

Tips & Tricks

  • The exporter is still in a very raw stage. Code isn’t error proof so you have to follow strict rules to avoid errors on export.
  • All parameters in the Blender UI have a tooltip with descriptions.
  • It is recommended to use one forest per one Blender scene.
  • Everything except proper forest collections must be turned off (excluded from View Layer) on export time.
  • Try to avoid extremely high polycounts. A typical big tree mesh can have 1000 – 2000 triangles, or 3000 – 4000 for very big, old trees.
1 Comment

lights.txt File Format

The lights.txt file is a file of light names and directions for X-Plane’s rendering engine. It is absolutely not meant for editing by the user and we take no responsibility for crashes or the file being overwritten during updates.

It is an ASCII .txt file with a header and body.

All text including and after a ‘#’ is a comment. There are no leading or trailing whitespace allowed.

lights.txt Header

Similar to other Laminar Research file formats, the lights.txt header is as follows

NEWLINE (A)

VERSION (850)

LIGHT_SPECS

TEXTURE <filepath to texture file>

A header may have multiple TEXTURE files, currently one for close range and one for distant distances.

lights.txt Body

  • Each line of the body consists of a RECORD TYPE, a light name that may be shared with other records, and the contents of that RECORD TYPE.
  • Light names match “[A-Za-z0-9_]+” and represent only 1 light – no “my_test_light” representing a red spill and a blue strobe.
  • Each element of the line is separated by (usually 1) tab for readability. Spaces (please use 4) may be used but are strongly discouraged.
  • All light’s “front” face is to the south (0, 0, 1) – if you are standing south of a light, looking north you’ll see it. Parameters for DX, DY, and DZ can change this.

RECORD TYPEs

There are two record types: OVERLOAD or LIGHT_PARAM_DEF. A light_name must have at least 1 OVERLOAD and may have 1 LIGHT_PARAM_DEF. Records should be grouped by light_name, bounded by an empty line. A LIGHT_PARAM_DEF must precede all OVERLOADs.

OVERLOADs

OVERLOADS are in the form of <OVERLOAD TYPE> <light_name> <matching number of arguments for prototype>

Arguments may be

– a number (in decimal notation), convertible to a float
– a dataref or NOOP to replace DREF, no surrounding quotes
– a parameterization-argument: One of the parameters from the light’s LIGHT_PARAM_DEF. Can be in any order in the arguments list and be used multiple times in the arguments list as long as the light has a LIGHT_PARAM_DEF.

Overload Type | Order of arguments and likely parameters used (spacing for readability, not to indicate an altered start index)
---------------|--------------------------------------------------------------------------------------------------------------------
BILLBOARD_HW   | <R> <G> <B> <A> <SIZE> <CELL_SIZE> <X_CELL> <Y_CELL> <DX> <DY> <DZ> <WIDTH> <FREQ> <PHASE> <AMP> <DAY>
BILLBOARD_SW   | <R> <G> <B> <A> <SIZE> <CELL_SIZE> <X_CELL> <Y_CELL> <DX> <DY> <DZ> <WIDTH>                            <DREF>
SPILL_HW_DIR   | <R> <G> <B> <A> <SIZE>                               <DX> <DY> <DZ> <WIDTH>                      <DAY>
SPILL_HW_FLA   | <R> <G> <B> <A> <SIZE>                                                      <FREQ> <PHASE> <AMP> <DAY>
SPILL_SW       | <R> <G> <B> <A> <SIZE>                               <DX> <DY> <DZ> <WIDTH>                            <DREF>
SPILL_GND      |                 <SIZE> <CELL_SIZE> <X_CELL> <Y_CELL>
SPILL_GND_REV  |                 <SIZE> <CELL_SIZE> <X_CELL> <Y_CELL>

light_name has been omitted. (Although LIGHT_PARAM_DEF and an OVERLOADs params and arguments lists look like a function declarations and partially applied functions, the names are just for humans. The order used is what truly matters. To keep consistent, the format specifies our conventions.)

OVERLOAD Types

  • BILLBOARD_HW – A hardware accelerated billboard.
  • BILLBOARD_SW – A dataref driven billboard, NOOP may be used.
  • SPILL_GND, SPILL_GND_REV – old v8-style quads-on-the-ground light spill for runway lights.
  • SPILL_HW_DIR, SPILL_HW_FLA – hardware spill, directional’ or flashing. We can’t have both due to a lack of light params.
  • SPILL_SW – dataref driven spill, NOOP may be used

OVERLOAD Parametrization Restrictions

The following are tables of what columns of an OVERLOAD’s prototype are allowed to be parameterized. The column names are conventions only based on common uses of these columns. This is unrelated to the content and order of LIGHT_PARAM_DEFs or the overload’s argument.For example

A light has SIZE in the LIGHT_PARAM_DEF and a BILLBOARD_HW overload with “SIZE” 1st column (commonly known as the R column) and 1.24 in the 5th column (commonly known as the SIZE column). The common labels for the columns and their contents are meaningless.

OVERLOAD type R G B A SIZE CELL_SIZE CELL_ROW CELL_COL DX DY DZ WIDTH
BILLBOARD_HW * * * x * x x x * * * *
OVERLOAD type FREQ PHASE AMP DAY DREF
BILLBOARD_HW (continued) * * x x x
OVERLOAD type R G B A SIZE CELL_SIZE CELL_ROW CELL_COL DX DY DZ WIDTH DREF
BILLBOARD_SW * * * * * x x x * * * * x
OVERLOAD type SIZE CELL_SIZE CELL_ROW CELL_COL
SPILL_GND * x x x
SPILL_GND_REV * x x x
OVERLOAD type R G B A SIZE DX DY DZ WIDTH DAY
SPILL_HW_DIR * * * * * * * * * x
OVERLOAD type R G B A SIZE FREQ PHASE AMP DAY
SPILL_HW_FLA * * * * * * * x x
OVERLOAD type R G B A SIZE DX DY DZ WIDTH DREF
SPILL_SW * * * * * * * * * x

LIGHT_PARAM_DEFs

LIGHT_PARAM_DEFs are in the form of LIGHT_PARAM_DEF <light_name> <count greater than 0> <parameters list of count length>. Every parameter must be unique. A LIGHT_PARAM_DEF’s params list can be in any order but is strongly suggested to follow the order in each OVERLOAD type.

Regular Parameters

These are: R, G, B, A, SIZE, DX, DY, DZ, WIDTH, FREQ, PHASE, INDEX, and DIR_MAGINDEX represents the index in the light’s dataref’s array. It is only used in airplane_ lights. DIR_MAG is only used in airplane_nav_left/right/tail_size to indicate it is using the “directional magnitude” method of calculating the WIDTH column, instead of the usual method.

Special “Hint” Parameters

Some parameters give clues to tools and X-Plane on what their values should be, despite being parameters. They can be used multiple times (by appending a '_' for each duplicate).

  • UNUSED: Replacement placeholder for deprecated parameters, commonly replaced with 0.
  • NEG_ONE, ZERO, ONE: Some light’s parameter’s only ever make sense to use a hard coded value like -1, 0, or 1. A prime example is airplane/generic/landing/taxi lights’ RGB parameters which are actually used for aiming the light, but the light should only ever be aimed at (0, 0, -1). Tools and X-Plane can use this metadata to avoid making artists know this obscure fact.

An example: old_light’s parameters list was once LIGHT_PARAM_DEF old_light 9 R G B A SIZE DX DY DZ WIDTH, but now is expressed as LIGHT_PARAM_DEF example_light 9 ZERO ZERO_ NEG_ONE UNUSED UNUSED_ DX DY DZ UNUSED__. This way tools and X-Plane knows only DX DY DZ matters anymore, and “each parameter is unique” is satisfied in an easy to read and parse way. Software can help the artist and user accordingly.

ARGUMENTS explained

  • R, G, B, A – The color tint applied to the light spill or billboard. Since light is additive, A is really just a master dimmer.
  • SIZE – The total size in meters for spill, or a ‘size constant’ for billboards you’ll have to play around with to get right.
  • CELL_SIZE, CELL_ROW, CELL_COL – A triplet of ints (size, row, column where 0,0 is the lower left) for billboards. Size is a power-of-two multiplier for cell size. Thus a double-size cell in the top right corner is 2 7 3 (because the 1024 x 512 texture can be divided into a 8 x 4 grid of 128×128 pixel cells).
  • DX, DY, DZ: Direction vector for directional billboards and spill lights – should be normalized
  • WIDTH: For billboards, a constant term between 0 and 1 that makes a billboard more omni directional the closer it gets to 1. For spill lights: cos(1/2 * view_angle).
  • FREQ, PHASE, AMP, DAY: Frequency, phase offset, amplitude, and day/night flag for flashing lights
  • DREF: For software lights, the dataref that “processes” the light.

NOTE: if a hardware or software billboard has negative size, then it is axial. In this case: the direction is the axis of rotation (the billboard hangs off in that
direction. The axis should be normalized. The ‘width’ parameter is used as a scaler, e.g. larger numbers are more focused.

More notes on frequency:

  1.  “frequency” of flashing in Hz ( number of flashes per second, 0.2 mean a flash every 5 seconds)
  2. “Phase offset” in seconds (so you can make two flashing lights that don’t flash at the same time, this value controls how late the flashing pattern starts from light OFF
  3. “amplitude” of the flash, flash is a triangle wave, but with amplitude 1.0 the lights pulse (going from 0 to 1 and back to 0)
    but if you pick a huge amplitude like 10.0 x-plane will automatically subtract 9 (to keep the light from going crazy) the result is….a strobe!
    if you set the amplitude to 0.5 then x-plane will add a bit so even at its DARKEST the light will still be 50% ON, so you can make some tricks with the amplitudeALEX SAYS: Flash amplitudes GREATER THAN 1000 now invoke a square-wave flash behaviour. The pulse width ratio is calculated as (amp – 1000)/1000 %.
    In other words, every integer over 1000 represents one millicycle. E.g. amp = 1500 gives a pulse width of 50%, amp = 1020 gives a pulse width of 2% etc.
    Amplitudes less than 1000 still invoke the existing “strobe” scheme.
  4. parameter: “daytime vs night-time” ratio. if it is 1 the light will be ON during the day and night, if it is 0 light will be ON only at night.
3 Comments

Designing Manipulators for Virtual Reality

A manipulation is an action the user can take by clicking on your object. Manipulations can only be used in cockpit objects.

Traditionally, manipulators have been focused on the interaction between the mouse and cockpit. VR implementation has added a few new possibilities and made older processes obsolete. This guide explains manipulators in terms of how real objects move instead of in terms of mouse clicks.

The Pieces Of A Cockpit Control

There are 6 components of a cockpit control.

Required components:

  1. An interaction spot, such as a single place to click or interact in VR, or the two spots that are automatically created using something like Command Switch Up Down
  2. The manipulator type that tells X-Plane what type of interaction spot to make and what happens when you interact with it.
  3. The manipulator’s dataref or command, from X-Plane or a plugin, that changes or triggers when the interaction spot is interacted with. Also, certain other case by case parameters like cursor type, tooltip, etc
  4. The manipulator mesh, which determines where the interaction spot will be in X-Plane. It is usually blocky in shape for an easier time interacting with it

Optional components:

  1. A visual mesh for what the user sees. The manipulator mesh is made invisible (but is still interactable), while the user sees a high-detail visual mesh. This is standard for yokes, but may be more work than needed for simple buttons.
  2. Finally, the animations that keep the manipulator mesh and visual mesh (if you have any), moving in sync so it doesn’t break realism. This does not have to be the same as the manipulator dataref (if any), but very well could be.

A simple example: Making an extremely simple Push button (manipulator type) to fire commands.

  • Make a panel where the button is supposed to be (interaction spot), and give the panel the relevant manipulator information, such as the command you want to use and the cursor to see.
  • Finally, include the button in the cockpit texture so the user has something to look at.

A more complex example: Creating a slide for some trim flaps.

  • You want a linear dragging motion, and pick Drag Axis for their manipulator type.
  • Model the control, a small tapered cylindrical knob.
  • Users say this is hard to click and easy to miss (interaction spot), so you make two meshes: One a slightly oversized cylinder that the user will actually click (manipulator mesh) and a high detail tapered cylinder the user will see moving (visual mesh).
  • The manipulator changes the dataref sim/cockpit2/….trim (manipulator’s dataref).
  • Since the user drags the manipulator mesh but sees small tapered visual mesh, they must be animated the same way. For convenience, the manipulator’s dataref is used.

And so, the user drags the trim flap slider up, the trim flaps go up, the animation moves up. Note: Clamping the manipulator’s animation is possibly essential to prevent incorrect or unrealistic motion

Manipulator Types

The following names are based on the OBJ spec and the XPlane2Blender add on. The names are probably similar in whatever OBJ exporter you are using. Otherwise, see the supporting documents of that exporter or e-mail their author for more details.

Levers

MECHANISM You want For firing commands For changing DREFs
Interaction Is Consumed But Nothing happens Noop Noop
linear lever Command Axis* Drag Axis
With Detents Drag Axis With Detents
rotational lever Drag Rotate
With Detents Drag Rotate With Detents
Ball Joint Drag XY**
Yoke Drag XY***

*The command axis manipulator runs a command based on a drag in one direction and the other – this doesn’t fit well with real linear mechanisms, but in rare cases it can provide a nice user experience for a detented linear lever, like a flap handle.

** Ball joints do not work well in VR – the XY manipulator is an approximation

*** Yokes should be done via the XY manipulator – the _vrconfig.txt file has special commands

to make yokes work perfectly. See the VR configuration file format spec for details.

Details on Noop

If you want a click to be consumed before it reaches another manipulator underneath it, use a Noop. This is useful for temporarily disabling a control without the use of a plugin, such as a locked lid over an “EJECT” button. Make the glass a noop, and the button a Command. When the locked lid over and eject button has played its animation to raise, the eject button becomes clickable.

Buttons

MECHANISM CMD DREF
push-button Command Push (radio, delta, toggle, wrap)
knob Command Knob Axis Knob
knob (2-way) Command Knob 2
horizontal switch Command Switch Left Right Axis Switch Left Right
horizontal switch (2-way) Command Switch Left Right 2
vertical switch Command Switch Up Down Axis Switch Up-Down
vertical switch (2-way) Command Switch Up Down 2

Note that the command variant is always preferred in terms of quality of user experience – dataref variants are provided only to help authors with weird situations. The various push button dataref manipulators vary based on what values are written to the dataref.

The Manipulation section of the OBJ8 spec contains more information about how these type names get turned into OBJ directives and the exact details of their parameters.

Leave a comment

All About Clamping Animations

Let’s suppose we are simulating a faulty fuel quantity gauge for a historic plane, the “Arbitria Examplus Mk 2”. The plane had a real fuel capacity of 200kg, but showed empty when there was 5kgs left, and full when there was 190kg in the tank. Plane Maker will provide the sim with the real fuel capacity while this animation will provide the visual realism.

The fuel gauge, at frame 1
The fuel gauge, at frame 2

First, we model a gauge and a needle, initially pointed up at 0 degrees. The texture used here is fuel_round_GA.png, included with Plane Maker.

We are using the dataref sim/flightmodel/weight/m_fuel_total. The first keyframe shows the gauge’s arrow at the empty position (135 degrees), and will be shown when the dataref is 5. The second keyframe shows the gauge’s arrow at the full position (-135 degrees), and will be shown when the dataref is 190. Here is a chart of this data as a table and graph of the arrow’s rotation over changes in m_fuel_total.

The faulty fuel gauge animation, in table and graph form, without clamping

When sim/flightmodel/weight/m_fuel_total is between our explicitly created keyframes (5 and 195) it will animate as intended because X-Plane is interpolating between these known keyframes. But, beyond that X-Plane will guess by using the first two keyframes for when the dataref is less than 5 and the last two keyframes when the dataref is greater than 190. (In this case we only have two keyframes, both are used to “look ahead” and “look behind”). This is called extrapolation. Extrapolation is useful as it allows you to animate just a portion of the range of motion and allow X-Plane to do the rest. It is convenient and allows you to think of animation as incremental motion (10 degrees CCW every change of .1) that builds up dynamically rather than one large static motion that will be broken up into chunks.

There is currently a problem with our animation! We want the needle to stop moving when it reaches 5kg or 190kg, but this keyframe table will allow X-Plane to keep rotating the needle for all of 0 to 200. X-Plane’s extrapolation cannot be turned off; instead we must trick it using “clamping keyframes”. By using another keyframe on each side of the keyframe table with the same angle and a smaller and larger value respectively, we can “clamp” the animation and stop incorrect extrapolation from ruining our fuel gauge!

The faulty fuel gauge animation, in table and graph form, without clamping

You can see in the graph how the extrapolation is now fooled! By giving X-Plane a flat line to follow, rather than a sloped one, past certain values the angle of rotation will stay the same no matter the dataref’s value. The value for the dataref simply has to be less than or greater than each side, but many artists use a convention to quickly identify what is a clamping keyframe. Some use -999999,999999 or adding or subtracting 1 off each end as we’ve done in this example. Both work equally well, so the real value is in being consistent. Though rarely used, it is also possible to clamp only one side of a keyframe table.

Although a rotating gauge was used, this principle applied to translations as well.

1 Comment

X-Plane 11 Particle System

Introduction to the Parts of the Particle System

The X-Plane 11 particle system follows a fairly standard game-industry design:

  • A particle system consists of a collection of emitters and particles.  There can be many particle systems running in X-Plane at the same time, and they do not interact with each other.
  • A particle system’s behavior is controlled by a particle system definition text file. More than one particle system can use the same definition file at a time.

Particle Types

Every particle in a particle system has a type, and the definition file defines the behavior of every particle type.  Typically you will have a small number of types per definition file. For example, a definition file that contains “smoke and fire effects” might contain three types of particles: a flame particle, a white smoke particle, and a black smoke particle.

The particle type definition controls the appearance and behavior of the particle over time, including what textures it uses and how it grows/shrinks and fades over time.

Every particle that is created in a particle system has a finite lifetime (measured in seconds) before it disappears.  The particle definition file defines how the particle type is drawn over that lifetime.  For example, a typical behavior is to make the opacity of the particle fade from 100% to 0% over the lifetime of the particle, so that the particle slowly disappears.

All properties of the particle type that can be key-framed are key-framed over either the lifetime of that particle, or by data-refs. You can use more than one key-frame table; the results of each table are multiplied to get the final result.

Emitter Types

An emitter creates particles; every emitter has a type, and the emitter type definition defines how the emitter creates particles.

The emitter always creates the same type of particles, but it can control the particle’s initial properties, including its initial size, its initial opacity, and how long it lives for.

Emitters are used in the simulator by attaching them to objects or aircraft.  The emitter would be attached at a particular location on an OBJect with a particular direction; if the object is on an airplane, the emitter moves with the airplane.  For example, you might put an emitter of smoke puffs on the exhaust pipe of an aircraft.

For convenience, X-Plane lets you put one or more sub-emitter into each emitter. Each sub-emitter can emit its own type of particles with its own properties. The motivation here is to make it easy to attach a lot of emitters to a single point in an object.

For example, our gun-barrel emitter contains two sub-emitters: one for the muzzle flash (emitting a small number of fire particles) and one for the smoke (emitting a larger number of smoke particles). By wrapping both sub-emitters in a single emitter, it’s simple to attach the one “gun barrel” emitter to the tip of a gun barrel on a fighter.

The various properties of the emitter (number of particles created per second, initial velocity, etc.) are key-framed based on datarefs.  So you can specify that an emitter makes more particles (or faster particles, or bigger particles) as the engine’s N1 spools up.  In this way, an emitter can dynamically change its stream of created particles based on inputs from X-Plane.

Datarefs attached to emitters can use wild-cards for array indices. When you specify [*] for a dataref index (e.g. sim/flightmodel2/engines/N1_percent[*]) the * is replaced with an index number that comes from the OBJ file where the emitter is attached. This lets you use a single ‘generic’ emitter for all engines in your aircraft and specify the engine index number each time you use the emitter. (This mechanism works the same as wild card parameters in FMOD.)

Many parameters of the emitter type definition can be randomized. In this case the parameter ha a lower and upper bound that can be edited separately. Since the parameter is key-framed, the amount of randomization (the distance between the two parameters) can vary based on a dataref.

Effect Types

Emitters are attached to parts of the X-Plane world (scenery objects, airplane objects, etc) and run continuously based on their volume.  This is good for continuous sources of particles like a smoke stack, but it is not good for a finite event, like an explosion.

An effect is a collected sequence of key-framed emitter locations and values.  An effect is something that happens over a time and start location.  For example, an explosion effect might contain instructions to run a fire emitter for 10 seconds.

The properties of an effect are key-framed to the time of the effect; the effect has a finite total duration.  Thus for an effect you can create a smoke emitter that creates a lot of smoke and then have the smoke level slowly die down.

Effects cannot be attached to objects; rather X-Plane uses effects directly at specific times, e.g. when a bomb hits the ground or when the airplane crashes.

Accessing the Particle System in X-Plane

As of X-Plane 11.30d2, the X-Plane B737 has been updated to use the particle system and can be used as a reference.

Pick “Show Particle System Browser” from the developer menu to access the in-sim particle system UI.  You will see a list of all currently loaded particle system definition files (.pss files). You can edit any loaded particle system shown in the browser by double-clicking to open its editor. Note that these windows can be resized or popped out, and the width of the columns in the .pss window can be adjusted.

To create a new particle system, click the “New…” button and pick a particle system file on disk. The location of your particle system on disk matters because only textures in the same folder as the particle system (or in sub-folders) can be used.

To open and edit a particle system not currently in use by X-Plane, click the Open… button and browse to your .pss file.

The particle system editor

Particle editor

The upper left column (named for whichever particle you double clicked to open from the browser) is a hierarchy list of all particles, emitters, effects etc. + preview and texture tab. This may be hidden if the Particle Budget column is expanded. Click an item to view its properties; icons under this section are: create, delete, duplicate, move up, move down. The eyeball icon next to the various emitters lets you disable emitters globally.

The lower left column is the particle budget.  For the PREVIEW only, this shows how many particles of each type are being used, which lets you figure out if you have enough particles of each type budgeted in the system.  Note that particle systems used in the sim and not in the editor preview are NOT shown, so sadly you cannot use this to debug budget problems in the live sim.

When “texture” is selected from the hierarchy, the texture preview appears on the right side.

texture

The middle section is the property editor and is named for whatever is selected in the hierarchy. When an emitter is selected, the sub-emitters form multiple columns.

When a property that can be key-framed is selected in the middle view, the key frame editor appears on the right side.  The add/delete buttons on the right let you add a second key frame table or delete the bottom one.

emitter properties 1

Each key frame table lets you pick a dataref or other key frame source, and then edit the key frame table either graphically by dragging nodes or by clicking.  Option-click on a key-frame curve to add nodes graphically, or use the + (add) and ø (delete) icons on the right.

The key-frame interpolation mode popup changes the algorithm by which the key frame points are attached.

If the key frame property contains more than one value (E.g. two for a randomized value between two bounds or 3 for RGB colors) you can drag each line independently.

Top buttons provide access to: save/revert the .pss file, undo/redo edits, and preview/stop previewing the selected emitter or effect.  (You cannot preview a particle type directly – you must preview an emitter that emits them.)

Particle Properties

These settings affect all particles of a given type.  Some properties can be key-framed either by a dataref or by “particle lifetime”, which makes a property change over the life of each particle. When “particle lifetime” is used, the key frame table runs at different speeds for long-living and short-living particles.

Name: this is the name you see in the hierarchy – X-Plane ignores it.

Max particles: this is the maximum number of particles of this type you can have at once.  The biggest you can set this is 16384.  Set this large enough that the system does not run out of capacity, but smaller is better.

Physics Properties

Gravity: this is how heavily gravity makes the particles fall. Negative numbers make them rise. A value of zero means no gravity.

Drag: this is how fast the particles slow from their initial speed to the speed of the outside air – higher numbers give more drag.  A value of zero means no drag.

Angular Velocity: this is how fast the particle billboard spins over the life of the particle.

Turbulence: this is how much each particle is randomly bounced around by turbulent air.

Collision Mode: this defines what happens when the particle hits the ground.

  • None: the particle is not checked against the ground.  This is the fastest for CPU – use this if you do not need to collision test.
  • Bounce: the particle bounces off the ground.  Set Elasticity to make the particle bounce more or less.
  • Die: the particle disappears when it hits the ground.

Rendering  Properties

Billboard Mode: this controls how the particle is drawn in 3-d.

  • Billboard – the particle is a square and always faces the camera – good for smoke.
  • Axial Billboard – the particle is a long rectangle, spinning around the direction it moves – possibly good for gun fire.
  • Ribbon – the particle is a long connected chain of quads with the texture repeating – good for contrails that must be very long.

Blending Mode: this controls how the alpha of the particle is combined with the scene.

  • Normal – the particle blends over the background, like a photoshop layer – good for smoke.
  • Additive – the particle adds light – good for lights and explosions.  Similar to how the OBJ lights work.
  • Pre-multiplied – the particle is applied using “pre-multiplied” alpha – areas with opaque alpha act like ‘normal’ and areas with clear alpha act like ‘additive’.  Your particle’s RGB must be drawn over a black background.

X/Y Grid Divisions: this defines the grid of texture cells for this particle.  Each particle can use its own grid so that some particles can be big and some small.

Start Cell/Cell Count: this defines the list of cells that animate to draw the particle. The upper left cell is 0, and then they increase from left to right, then down, like a book.

Repeat: how many times the cell sequence repeats over the life of the particle.

Randomize: if checked, each particle gets a random texture cell and does not animate.

Animation Rate: this lets you customize the speed of the cell animation over the life of the particle.

Scale: this controls the size of the particle – it can grow or shrink over time.

Alpha: this controls how opaque the particle is – you can fade it out over time.

Length: for axial billboards only, this is how long the particle is (separate from the width).

Ambient, Diffuse: this controls how much the particle is lightened by the lighting conditions of the world.

Emissive: this is how much the particle creates its own light, so it is visible at night.

Tint: this is an RGB control that can ‘tint’ the color of the billboard if needed.

Emitter Properties

Each emitter contains one or more sub-emitters – the idea is to allow several emitters at a single spot (e.g. smoke and fire for a rocket) by attaching only one emitter in an OBJ.

Name: this is the name you see in the hierarchy – this is used to specify the emitter in the OBJ file.

Emitter Mode: this controls how particles are emitted.

  • Stream: particles come out continuously over time. This is the default mode and is useful for smoke.  You must use streaming mode for ribbons.
  • Burst: a large number of particles are all emitted at once.  This is used only for effects, and not for emitters attached to objects.
  • Attach: a single particle is kept attached to the emitter at all times.  This can be used to create a single ‘flame’ billboard on the end of an engine, for example.

Number of sub-emitters: change this to add and remove sub-emitters.

Sub-Emitter Properties

Visible: you can temporarily hide an emitter to remove its particles from the particle system preview.  This is used only for authoring, and is not used in the final particle system.

Particle type: this selects which particle type the emitter emits.

Rate: this controls how many particles are emitted per second.

Initial speed: this is how fast the particles are moving when emitted.  This speed is relative to the speed of the OBJ they are attached to (e.g. the airplane).

Angular Velocity Multiplier: this scales the rotation from the particle definition itself.

Initial Pitch/Initial Heading: this controls the direction the particle flies relative to the attached object. An emitter on an OBJ that is not animated (in the OBJ) and has 0 pitch and heading points in the negative Z direction (E.g. toward the nose of the aircraft).

Size: this scales the size of the particle itself.

Alpha: this scales the alpha of the particle itself.

Lifetime: this controls how long the emitted particle will live, in seconds.

Offset Properties

These properties offset where the particle is created relative to the emitter on the object.

Dx, dy, dz: these offset the emitter along the X, Y and Z axis of the object, in meters.

Longitudinal Offset: This offsets the particle along its emit direction (as defined by initial pitch and heading).

Lateral Offset: this offsets the particle in a random direction that is orthogonal to the longitudinal offset.

Initial Rotation: this defines the initial rotation of the particle billboard when it is born

20 Comments

Optimizing Object Peformance

This article describes how to optimize the performance of scenery and airplanes that use OBJs. OBJs are often the most expensive part of an airplane or scenery pack, so careful construction of OBJs can help.

Identifying Performance Limitations

There are three typical scenarios for object performance tuning:

  1. You have a small number of objects with a lot of detail in each one. Typically you will be constrained on “detail” – that is, the total VRAM used by all objects, total number of vertices, and sometimes attributes. A typical scenario might be an airplane, where there are only 20 objects, but each one uses a huge texture, a huge normal map, and has a ton of vertices.
  2. You have a moderate number of objects, each with a moderate amount of geometry. But do to the repetition, the total vertex count is very high. This is a case where the “leverage” of repeating an object causes problems. A typical case might be a jetway that has a lot of detail and is placed into an airport scenery package 200 times.
  3. You have a huge number of objects; pure object count is the limiting factor, even though the objects themselves are quite trivial. This can happen when objects are used to build cities, e.g. you have 10,000 building objects in a small area.

Before you can optimize your airplane or scenery, you must identify which scenario you are in. The best way to do this is to reduce the ‘cost’ of your scenery/airplane and watch performance change.

  • Reduce the size of textures in photoshop.
  • Temporarily remove parts of a model to reduce vertex count.
  • Remove some objects from the scenery pack.

When you find a crude technique that improves framerate, you know where your costs are.

Optimizing Detail

If you have a few objects and are still having performance problems, there are a few things to look out for:

First, be aware of overall vertex count. X-Plane can handle fairly large models, but at some point you will run out of vertex budget. Use LOD to simplify meshes when viewed from far away. Two notes on LOD use for vertex count:

  • Don’t use LOD to save a small number of vertices. For example, LOD to reduce from 100 to 50 vertices is not a win for detail-bound models. But if your airplane is 500,000 vertices when viewed up close, LOD might be a real win.
  • You get maximum performance when an object is not drawn at all because the maximum LOD distance is set low. Separate details that can be eliminated entirely into their own objects, then set their LOD very low to avoid them. The very act of drawing an OBJ is expensive, even if it contains one OBJ, so you save setup costs in this case.

The total amount of texture used by a model or scenery can start to crowd out VRAM. Here LOD is important too. If an object is not drawn at all because we are farther away than its highest LOD, then its texture won’t have to sit in VRAM. But this only works if the texture is not used by any objects.

  • Organize your textures so that all details are in one texture, then use LOD to try to eliminate details when viewed far away.

Example: if you are building an airport, put all of your trucks, cones, and other small objects into one texture. Keep the terminals separate. The terminals will be visible from 10 miles away, but if all of the details have low LOD, the detail texture may not be used at all when on final approach, cutting down VRAM use.

Be aware that the cockpit object’s texture is never compressed or reduced in size, so use this texture sparingly; use it only for details that must be crisp to make the plane flyable. If the user is running at a low texture setting, there is a reason for it!

Optimizing Leveraged Geometry

When you have a moderate number of high-cost objects, the total geometry can start to add up. For example, 200 jetways with 10,000 vertices each will add two million vertices to the scene. It’s likely that all of the jetways are visible when the user flies over the airport; two million vertices is a lot, particularly when the rest of the world must be drawn too.

When working on an object that will be placed many times and has a lot of detail, use LOD carefully to avoid high vertex count. For example, it’s fine to have a high detail jetway with 10,000 vertices as long as we have another LOD with only 1000 vertices and a reasonable transition distance. At any one time, most jetways won’t be nearby and will take only 1000 vertices (for 200,000 vertices total) with maybe one jetway using 10,000 vertices. That’s almost a 10x savings in vertex count.

But be aware: there is a cost to having lots of LODs, so generally you should only use two or three LODs.

Optimizing Total Object Count

When placing a large number of objects, the object count becomes the most important factor. Most users will have machines that can draw between 3000 and 8000 objects, per frame, depending on rendering settings, hardware, and drivers. When building cities, it’s pretty easy to exceed these numbers.

The most effective way to cut object count is to make the farthest LOD of your objects be not too far away. When an object is beyond its maximum LOD distance, it is not drawn at all, reducing object count. X-Plane is very very fast at eliminating objects that are beyond their LOD distance. For example, X-Plane can easily draw an OBJ for every taxiway light (over 10,000 objects at KORD) because the LOD distance is only 500m on each light . Thus of those 10,000 objects, almost all of them are eliminated rapidly.

When object count gets large, small mistakes in the OBJs themselves start to add up. A single attribute in an OBJ can add one batch and make the OBJ twice as slow on the CPU to draw. For an airplane cockpit this is no problem, but if the OBJ is repeated 5000 times then we’ve added 5000 batches. When building an object that will be placed many times:

  • Do not use attributes if you can possibly avoid it.
  • Keep LOD low when possible.
  • If possible, use only triangles; avoid lines and animation.

OBJ File Format Performance

This section contains some notes regarding the creation of fast OBJ files. This is only of interest if you are working on an export script that creates the OBJ file itself – that is, it deals with how to best organize an OBJ file for maximum speed.

Ordering

Let’s start with the ‘cost’ of everything. Basically, the rough list is (most expensive changes come first: these are the things you do NOT want to interleave):

  • Changing primitive type (tris vs lines vs lights vs smoke – always put lights last!).
  • Changing to and from the cockpit texture (try to avoid doing this more than once!!)
  • Changing “shader” (this includes: poly OS, ATTR_light_level — Material changes)
  • Animation
  • “Cheap” attributes (ATTR_hard/ATTR_hard_deck, ATTR_draw_disable). Basically these control which ‘physical’ mesh a tri is part of are the cheapest attributes and lowest priority to optimize.

In other words, you never want to do anything to make your OBJ bigger to optimize out ATTR_hard, because the sim is good at ATTR_hard, but it is very slow at changing to the cockpit texture, so avoid doing that more than once. Within these buckets, there really isn’t much difference – that is, poly_os and blend mode both change shaders, so they have nearly the same cost.

You can avoid ‘small’ batches of two sided by duplicating the geometry and reversing the normal – if an entire OBJ is two sided, ATTR_two_sided _might_ be best, but if a model has only a few two-sided geometry, duplicate the mesh; it can be worth it to create up to 100+ extra triangles to avoid a shader change attribute.

The cost of anim transforms is of course partly in the animation, but part is in the stoppage of drawing. So given a HUGE pile of animation commands, it’s good to have them all in one group. That’s why the XPlane2Blender exporter performs well even though it duplicates the animations (to avoid attribute state) – the result is typically a set of animations, and they’re cheaper in groups.

One other note: if you put the word DEBUG on its own line at the end of your OBJ, X-Plane will output the internal command structure, which is what X-Plane will actually run. It will be different from what you output – some commands are optimized out, and some OBJ commands become multiple X-Plane commands. Generally, shorter output in that log is better, and fewer shader changes are really important. Note that the list contains aesthetic ideas too – e.g. poly_os is before non-poly_os because otherwise the poly_os geometry will look bad!

In the end, the fast path is an OBJ with _no_ internal shader changes; this case is fast no matter what the sort order (since there are no shader changes to sort) but if a user includes shader changes, there is going to be a speed hit.

 

 

Comments Off on Optimizing Object Peformance

Normal Maps

Definitions

A normal map is a texture that defines which way light bounces off a surface, on a per-pixel basis. Normal maps encode the direction of light reflections using RGB colors.

A bump map is a texture that defines the height of bumps on a surface, on a per-pixel basis. Bump maps encode the height as a gray-scale image.

X-Plane does not use bump maps; it only uses normal maps. See the Creating Normal Maps section below for information on creating normal maps from bump maps.

A Specular Level Map (or shininess map) is a texture that defines which parts of a surface are shiny, on a per-pixel basis. (Specular maps are similar to ATTR_shiny_rat in their effect.) . Specular levels are a non-PBR X-Plane 10 concept.

A Gloss Map defines which parts of a texture are smooth, and replace specular level maps in X-Plane 11.

A “UV” map is the mapping of texture coordinates onto your model–that is, it is the shape of how your textures are applied to the mesh. X-Plane supports only one UV map per OBJ – that UV map is used for all textures: the day time (albedo), night LIT (emissive) and normal map textures.

Format

X-Plane 10 uses combined normal and specular level maps in a single texture. The RGB of the texture are used for the normal map, and the alpha channel is used for the specular level.

X-Plane’s normal maps are “tangent space” normal maps. That means that a “flat” (blue) normal map leaves the original surface unperturbed.

Creating Normal Maps

NormalMappr

NormalMappr is a free program for OS X that converts bump-maps to tangent-space normal maps. You open a PNG file, adjust a few parameters, and then save the results. You can apply it to a custom-drawn bump map (drawn in gray-scale using PhotoShop) or simply apply it to your RGB textures.

//shamyl.zakariya.net/apps/NormalMappr.zip

Converting Normal Maps From FS X Aircraft

FSX and X-Plane do not use the same normal map format. There are three key differences:

  • In FS X, the red, green and blue channels have been moved around a bit to reduce texture compression artifacts.
  • In X-Plane, normal maps should be uncompressed, in PNG files, not compressed in DDS files.
  • In X-Plane, the alpha channel can optionally be used as a specular map.

This tutorial explains how FSX normal maps are created. To use the normal map in X-Plane, you need the original light blue normal map from before the changes (“saving in FSX format” are made).

Generally since X-Plane normal maps are uncompressed, you will get higher image quality by going back to the original materials, rather than trying to re-convert the DXT-compressed normal map.

Using Normal Maps

Normal maps may be used in objects. To use a normal map in an object you must include a line

TEXTURE_NORMAL <filename>

Normal maps must be PNGs (not DDS). The normal map does not have to be the same size as the day or lit textures, but it does have to be a power of 2. It should be a 24-bit RGB + 8-bit alpha texture.

In order for the specular level map to work, you must use ATTR_shiny_rat. X-Plane multiplies the shiny_rat and specular level from the normal map, so it is best to use ATTR_shiny_rat 1.0 when using normal maps.

Normal maps can be used in the draped texture of an object or in other art assets as follows:

TEXTURE_NORMAL <ratio> <filename>

Where ratio scales the normal map relative to the UV map of the parent art asset. The intent of this is to allow for high frequency repeating normal maps that add texture at a rate different from a low frequency albedo.

Warnings and Problems

A few special precautions when making normal maps:

Normals Must Be The Correct Length

In a normal map, the RGB colors represent a “vector” – that is, a direction that light bounces off a surface. The vector must be of length 1. In practical terms, this means that the colors must balance in a certain ratio.

If the colors in the RGB channel do not balance to create a “normalized” vector, X-Plane’s lighting will not function correctly. Therefore it is important that you not modify the RGB channel with a paint program; instead use a program designed to create normal maps.

RGB Behind 0% Alpha

When using a normal map, you may have areas with 0% shininess. This is represented by 0% alpha. Some graphic programs (including some versions of GIMP and PhotoShop) will replace the RGB color behind a 0% alpha (transparent) area with white.

From the above comment, the normal vector must be normalized – since white is not a legal normal map value, these white areas will have strange lighting errors.

Be sure to use a program that can apply an alpha channel without destroying the RGB colors, like Graphics Converter.

Normal Maps Must Not Be Flipped

Normal maps have a “front” and a “back”. The front must face the viewer. If your UV map flips the normal map horizontally or vertically (flipping both is fine, since this is like a 180 degree rotation) then the normal map will not work correctly.

Basically, if you could put writing into your main texture and the writing would not look mirrored, then your UV map (the way your texture is applied to your object) is fine for normal mapping. If the text looks mirrored, the normal map will be reversed.

(Note: it can be very hard to detect incorrect lighting with a mirrored normal map; I suggest using a temporary texture with writing to confirm that your UV map is okay.)

Compatibility

  • Normal mapping is available in X-Plane 940 and later.
  • Normal mapping requires a graphics card with programmable pixel shaders – that is, a DX9 or later compatible card.
  • Normal mapping is only visible if the user enables per-pixel lighting.
  • Normal maps may be ignored at the lowest graphics settings for performance.

Technical

X-Plane uses tangent space normal maps with a specular level in the alpha channel:

r = dx, -1,1 mapped 0.255
g = dy, -1,1 mapped 0.255
b = dz,  0,1 mapped 0.255
applied where dz = N, dx = dS, dy = dT

Further Reference

//wiki.blender.org/index.php/Doc:Manual/Textures/Maps/Bump_and_Normal_Maps

Comments Off on Normal Maps

Managing Translucency

About Translucency Problems

A surface on a model is translucent if you can partly see through it – that is, its opacity is somewhere between 0 and 100%. Translucency presents problems for X-Plane models because it produces artifacts.

When Does a Model Have Translucency

A model will have translucency if any part of its texture has an alpha channel value that is not fully opaque or fully transparent.

A model will also have translucency at the soft edges between an opaque and transparent region. If blending is disabled (ATTR_no_blend for objects), there will be no translucent parts of the model.

Artifacts Introduced by Translucency

When there is a translucent section of an object, any scenery, model or airplane drawn after the translucent surface that is behind the translucent surface will disappear. For example, the interior of an airplane will not be visible behind the windows if it is drawn after the windows.

X-Plane’s Drawing Order

X-Plane’s drawing order is important because translucent surfaces must be drawn after the objects they are in front of.

Drawing Order Within Objects

The drawing order within an object is determined by the OBJ file – that is, the drawing order is not changed by X-Plane. This means that within an object, translucency problems can be solved by reordering the object.

Drawing Order Between Objects

The drawing order between scenery objects is not guaranteed, and will depend on runtime factors. Currently X-Plane has no mechanism for managing translucency between objects.

Drawing Order of Objects in an Airplane

Within an airplane, the drawing order is:

  1. The cockpit object, for external views (cockpit_OUT.obj).
  2. Attached objects with “outside” lighting, in order.
  3. Attached objects with “inside” lighting, in order.
  4. The cockpit object, for internal views (cockpit_INN.obj).
  5. Attached objects with “glass” lighting mode, in order.

Use Cases For Dealing With Translucency Problems

In all cases, the correct draw order will be opaque objects, then translucent objects in the order we see them (farthest to closest).

Translucency In Front of Opaque

If a translucent surface is always in front of an opaque surface, the translucent surface simply needs to be drawn after the opaque surface. The simplest way to do this is to make the translucent surface be at the end of the OBJ. This works well for cases where the camera cannot get in between the translucent surface and the opaque surface behind it. Examples:

  • Glass windows in the front of a building, where only the interior of the building is visible behind them, as long as the user cannot fly into the building.
  • An overlay decal like a pavement line on top of pavement. (If the pavement lines are not ATTR_no_blend, then they effectively have translucency around their edges, so this case does have to be considered!)

Multiple Windows for Airplane Cabins

The airplane cabin provides a real challenge: we can see in one window and out the other, or we can look out from the inside. To make this case work right, follow the following steps:

  • Put all windows in an object of type “glass”. This puts them at the end of the airplane’s draw order, after the cockpit object (which might have opaque elements like a pilot).
  • Within the glass, make each window out of two sets of one-sided geometry. This allows you to order the “inside” view of the glass” and “outside” view separately.
  • Within the glass object, put all glass that is visible from the INSIDE before all glass that is visible from the OUTSIDE.
Comments Off on Managing Translucency

Lighting Level of Detail

Almost all lighting billboards come from OBJs, via named lights or custom lights.

They are usually subject to level of detail (LOD). However, there are some exceptions.

Philosophy:

  • Authors know better than X-Plane when an OBJ should disappear – it’s a subjective thing. X-Plane always honors ATTR_LOD for triangles.
  • X-Plane knows better than authors when a light should disappear – since X-Plane knows how those abstract light params are rendered. X-Plane may ignore LOD. Usually this involves light being drawn for a longer distance, in cases where there is no perf hit in the rendering enigne. This is almost always desirable for authors.

Guidelines:

  • Replicate your lights through all LODs with the SAME exact values.
  • You can drop a light in far LOD but don’t add one.

Notes on implementation:

  • X-Plane may draw your light for longer than you want – calc will be based on light’s actual appearance.
  • X-Plane won’t double-draw extended-LOD lights when repeated in two LODs. Not a problem!
  • Don’t add lights in far LOD – X-Plane may not be able to accurately do this effect if it is tampering with LOD!
  • If your last LOD is light only, X-Plane can handle this VERY efficiently. So often there is penalty for huge final LOD for a named light that is geo only.
Comments Off on Lighting Level of Detail

Custom Lights

Rendering of Custom Lights

Custom lights are always rendered as a textured billboard (no matter what the user’s settings and hardware). The texture of the billboard is a subsection of the OBJ texture. The lighting parameters specify RGBA tinting of the texture, as well as the texture coordinates, and apparent size of the billboard.

Custom lights may have a DataRef associated with them; if the light does have a dataref, that dataref modifies the lighting parameters when the light is drawn, for animated effects.

Like named lights, custom lights are affected by animation (both rotation/translation and show-hide) as well as the object’s position. When a dataref indicates that a light is “directional” in a certain direction, remember that this is relative to the object, and can be affected by animation.

Example: if you attach a landing light to an airplane and put it inside an animation for the landing gear, then the light’s directionality will change as the plane flies and as the gear retracts.

Custom Light Architecture

In order to understand how custom lights work, you must understand that datarefs can act as processing functions as well as sources of information. Behind every dataref is some code (in a plugin or X-Plane) that provides the dataref value.

When a custom light is drawn, the following steps occur:

  • First, X-Plane starts with the 9 parameters from the OBJ file.
  • X-Plane passes those 9 parameters to the dataref code (in a plugin or X-Plane) for the custom light (if it has a dataref associated with it).
  • That custom dataref code can then modify or replace the parameters.
  • X-Plane then draws the billboard with the parameters (as modified by the plugin).

This process happens each time the light is drawn – that is, the next time the light is drawn, X-Plane starts over with the original OBJ parameters.

Usage Models for Custom Lights and Datarefs

There are a number of ways to use custom lights (with or without datarefs):

Simple Custom Lights

The simplest way to use a custom light is to not use a dataref at all. Your light will be drawn based on the parameters in the OBJ file.

Example: an object uses a custom light with no dataref to make a simple, omnidirectional, always-on light.

Custom Lights with Plugin-Replaced Parameters

A more complex use involves using a plugin that replaces certain parameters.

Example: The dataref sim/graphics/animation/lights/airplane_strobe_light replaces the red, green, and blue parameters with 1.0, an the alpha parameter with 0.0 if the airplane strobes are not flashing or 1.0 if they are. Thus adding this dataref to a custom light makes it into a white strobe.

In this example, some of the light parameters (size, texture coordinates) work normally. Other parameters (RGBA) are replaced by the plugin, so the values in the OBJ file do not matter. You can put any RGBA into your custom light with sim/graphics/animation/lights/airplane_strobe_light and it will always come out white.

Custom Lights with Plugin-Modified Parameters

The most complex case is the one where lighting parameters are interpreted by a plugin and then replaced. In this case the “meaning” of those lighting parameters depends on the dataref.

Example: the dataref sim/graphics/animation/lights/airplane_landing_light interprets the red, green, and blue parameters as a direction vector for the light. The alpha parameter is interpreted as an index number for the landing light switches. So RGB = 0 0 -1 means that the light points toward the front of the aircraft. (This is a light where X = 0, Y = 0, and Z = -1.) A = 2 would mean the third landing light is used; A = 0 means the first landing light. The dataref replaces the RGB values with 1,1,1 (white) and the alpha value with the brightness based on the current camera angle, or 0.0 if the light is off. The result is a directional landing light.

In this example, the meaning of RGBA is completely changed – instead these four parameters form a vector and light number. In return for this flexibility, the author loses control of the tint of the light (because the dataref always sets the light tint to white).

Most X-Plane provided datarefs for lights reinterpret the RGBA values (and replace them with white and a variable-level alpha); lights can be colored by coloring their texture. Typically the texture coordinates and size are not modified.

Custom Lighting Parameters

Nine numeric parameters define the appearance of a custom light. Those parameters are:

  • Red, Green, Blue, and Alpha Levels. These four numbers define the tinting of the lighting billboard. (The alpha level fades the light out – at alpha=0.0 the light is not drawn.) These numbers are ratios from 0.0 (minimum) to 1.0 (maximum).
  • Size. This number describes how big the billboard looks. Note that this number is not in meters – the size of lighting billboards changes non-linearly with distance. Use experimentation to tune the light appropriately.
  • S1, T1, S2, T2. These four numbers define the rectangular texture coordinates from your OBJ texture for the image to use as a billboard.

X-Plane Datarefs for Custom Lights

X-Plane provides a number of datarefs for custom lights. They are all in the path:

sim/graphics/animation/lights/

For example: sim/graphics/animation/lights/airplane_landing_light.

You should also read part of: xpsdk: PluginsAndObjects. This documentation is intended for plugin developers but may be useful.

Understanding the Documentation for Custom Light Datarefs

Custom light datarefs typically change the meanings of the 9 lighting parameters (RGBA, size, texture coordinates). For example, you might see this:

INPUTS:

RGBA form a 4-part direction vector - see PluginsAndObjects.

X-Plane 921 and newer: RGB form a 3-part direction vector; A is interpreted as an index number for multiple landing light switches.

OUTPUTS:

Alpha is set to brightness or 0 if it's off. RGB is set to white.

SPECIAL BEHAVIOR:

This light will turn off if the landing light is off.

DESCRIPTION:

This provides a directional light that follows the airplane's landing lights.

The most important sections are “inputs” which tells which of the 9 parameters have special meaning to this dataref, and “outputs” which tells which of the 9 parameters are replaced with new values.

You can find links to the complete list of datarefs here. For datarefs for custom lights, view the HTML datarefs, and click on the link for documentation.

Typical Conventions for Light Datarefs Created by X-Plane

Datarefs provided by X-Plane for custom lights typically have a few common properties:

  • Custom configuration is always done with the RGBA color parameters.
  • The color is almost always replaced with white. (The intention is to color your light using the texture.)
  • Alpha is almost always replaced with the light brightness.
  • Size and texture are usually left alone.

Mathematics of Directional Lighting Parameters

There are a number of common conventions used by X-Plane for directional lights.

RGBA directional lights

Many light datarefs treat either RGB or RGBA as a “direction vector” for a directional light. For example, the airplane landing and taxi lights do this.

The red, green, and blue lights represent the direction of the light in the X, Y, and Z axis in object coordinates.

For example (assuming the object or plane has a rotation of 0 degrees, e.g. it is facing north):

  • RGB = 1,0,0 is a light that shines to the east.
  • RGB = 0,0,-1 is a light that shines to the north.
  • RGB = 0,1,0 is a light that shines straight up.
  • RGB = -0.7,0,0.7 is a light that shines to the south-west.

The alpha parameter is a fixed amount of brightness that is always added to the light. So for example, RGBA = (0.5, 0, 0, 0.5) would create a light that shines to the east, but is also always on a little bit. (See “Tricks for directional lights” below.)

RGB directional lights

Some lights only provide RGB for direction. In this case, RGB operates the same as above, but no constant brightness is added. Typically in this case the alpha parameter is used for something else.

RG Rescaling

Some lights indicate “red green rescaling”. In this case, the light always faces north (as if its direction vector was 0,0,-1). However, the magnitude of that direction vector is multiplied by the red value of the light, and the green value is then added. So for example, R=0.5, G=0.5 would create a light that shines to the north with 100% intensity, but in other directions at 50% intensity.

Tricks For Directional Lights

The magnitude of the normal vector can be calculated as:

M = sqrt(x*x+y*y+z*z)

This magnitude affects the overall brightness of the light. Normally you would want M=1 for a light that reaches maximum brightness when the user looks at it. But you can create some interesting effects by using a norma vector such that M is not 1.0.

In particular if M is larger than 1.0 and the constant term of the light (the alpha channel) is negative, the result is a light that is more tightly focused (e.g. it becomes invisible when viewed only a few degrees off axis). Example:

R = 0 G = 0 B = -10 A = -9

In this example, the magnitude of the normal vector M = 10, and the constant term is -9. (Note that B being negative points the light north … B = 10 would point it south. The magnitude is always positive!)

Similarly, if the light is red-green rescaled, you can achieve the same effect with:

R = 10, G = -9

If M is smaller than 1.0, the constant term can be used to widen the light. For example:

R = 0.5, G = 0, B = 0, A = 0.5

In this case, the light won’t fully disappear until directly behind it. For a red-green light, you would use:

R = 0.5, G = 0.5

Plugins and Custom Lights

Plugins can provide custom lights – plugin authors should read xpsdk:PluginsAndObjects for more info. Datarefs provided by plugins for custom lights will not start with sim/graphics… but rather have a plugin-specific prefix. If the plugin is not loaded, the light will show the lighting parameters unmodified.

Comments Off on Custom Lights