FMOD version
X-Plane 12 runs the FMOD 2.02 engine, but since FMOD provides backwards compatibility, older 1.08 banks will load with no change. Nevertheless, you will NOT be able to use the “live update” feature of FMOD Studio 1.08 with X-Plane 12, because the newer version of the audio engine cannot connect to older Studio versions.
If you’re starting a new project for X-Plane 12…
The “Starter Project” download page now delivers a full FMOD 2.02 version. As you did with X-Plane 11, you must download a fresh “Starter Project” for every new X-Plane 12 project you intend to create.
Download the FMOD Project Template (v2.02 – for XP12)
If you’re upgrading an X-Plane 11 project…
We recommend you open your old 1.08 Studio project using FMOD Studio 2.02 and saving it as a 2.02 project. This will automatically upgrade your sound bank. Then you’ll need to address the following issues for it to work properly on X-Plane 12.
You should set your output format as “Surround 5.1 on Desktop” because the master bank that lives in X-Plane now outputs this format by default. Your bank’s output will be automatically downmixed/upmixed for users with a different speaker system. Be sure to properly set your buses to this format both on the input and output of each bus to avoid inadvertently downmixing your sounds. The starter project is already set up for Surround 5.1.
Parameter names
As of FMOD Studio 1.9, some characters are no longer allowed in parameter names. So when you use datarefs as parameter names (on events or snapshots), you should replace
- “/” with “.”
- “[*]” with “[#]”
Thus, “sim/flightmodel2/engines/engine_rotation_speed_rad_sec[*]” will need to be expressed as “sim.flightmodel2.engines.engine_rotation_speed_rad_sec[#]”. Note that dataref names on the .SND files do not need to be changed, you only need to make this change when they’re used as parameter names inside FMOD Studio.
If you migrated an old 1.08 project to 2.02, you can use this tool to help you bulk convert all the parameter names in your project to the new format so you don’t have to do it manually. Open your 1.08 bank using Studio 2.02, save it, exit Studio and then run the tool.
Live Update
To be able to use “Live Update” you need to use FMOD Studio 2.02. You must enable the “Live Update” connection only after X-Plane has fully loaded your aircraft, or the changes you make to the bank won’t be reflected in the simulator. If you reload your aircraft, be sure to turn off and on “Live Update” again so it picks your external changes.
Limitations
- FMOD 2.02 “global parameters” are supported but untested at this time.
- The “Highpass”, “Highpass simple”, “Lowpass”, “Lowpass simple” and “Parametric EQ” are considered deprecated on FMOD 2.02. All those are now superseded by the new “Multiband EQ” which has better CPU performance and functionality. We recommend you upgrade those effects if you’re using them.
New polyphonic events
When triggering sound events, X-Plane reuses the event instances to save resources, so if you have an event whose start conditions are satisfied several times in succession, the same instance will be stopped and retriggered each time. This might be undesirable under certain circumstances, such as triggering “clicks” for rotary knobs.
X-Plane 12 introduces the “EVENT_POLYPHONIC” directive for events. This forces X-Plane to disable instance reusing for that event and makes it trigger a new, separate instance of the same. Be sure to limit the “max instances” that can be triggered on the event (suggested 2-5) and the “cooldown time” to maintain low CPU usage and to prevent FMOD from triggering too many sounds at the same time, which could mute other sounds playing at that moment.
Environmental sounds
X-Plane now includes ambient sounds that depend on where the camera is placed in the world and its surroundings, as well as new rain, wind, hail and thunder effects. Ground equipment now produces sound too. All these are routed through the “Exterior Processed / Environment” bus, so it should “just work” with your existing banks.
As with X-Plane 11, it’s the responsibility of the aircraft developer to signal process these sounds when the user is located on the interior of the airplane, according to its sound insulation characteristics, and to do so only on the airplane interior, leaving the bus completely unprocessed when the user is outside (i.e. no mixer snapshot active). Be sure to preserve the 5.1 input/output format on that bus too.
The new environmental sounds that replace the old .WAV files in “Resources/sound/weather” don’t include rain or hail hitting the airframe, because it’s impossible for us to determine what material your aircraft is made of. So the developer should add their own sounds for the exterior and interior rain/hail impact on the airframe. You can use the following datarefs to that effect:
- sim/weather/precipitation_on_aircraft_ratio
- sim/weather/view/hail_ratio
- sim/weather/view/snow_ratio
New copilot NAV radio morse datarefs
In addition to the existing datarefs for triggering the morse code / marker sound events tied to the pilot radio, X-Plane 12 now provides datarefs for the copilot side too. They’re named exactly like their pilot counterparts, but suffixed with “_copilot”:
sim/cockpit2/radios/indicators/morse_id_tone_nav1_copilot
sim/cockpit2/radios/indicators/morse_id_tone_nav2_copilot
sim/cockpit2/radios/indicators/morse_id_tone_adf1_copilot
sim/cockpit2/radios/indicators/morse_id_tone_adf2_copilot
sim/cockpit2/radios/indicators/morse_id_tone_dme_copilot
sim/cockpit2/radios/indicators/morse_id_tone_dme1_copilot
sim/cockpit2/radios/indicators/morse_id_tone_dme2_copilot
sim/cockpit2/radios/indicators/morse_id_tone_nav3_copilot
sim/cockpit2/radios/indicators/morse_id_tone_nav4_copilot
And you can modulate their volume based on:
sim/cockpit2/radios/actuators/audio_volume_nav1_copilot
sim/cockpit2/radios/actuators/audio_volume_nav2_copilot
sim/cockpit2/radios/actuators/audio_volume_adf1_copilot
sim/cockpit2/radios/actuators/audio_volume_adf2_copilot
sim/cockpit2/radios/actuators/audio_volume_dme_copilot
sim/cockpit2/radios/actuators/audio_volume_dme1_copilot
sim/cockpit2/radios/actuators/audio_volume_dme2_copilot
sim/cockpit2/radios/actuators/audio_volume_mark_copilot
sim/cockpit2/radios/actuators/audio_volume_nav3_copilot
sim/cockpit2/radios/actuators/audio_volume_nav4_copilot
Remember that sound events related to morse and marker should be routed to the Radios bus. You can look into the Airbus A330 implementation for reference.
Plane Customization
Navigation Display Scaling
Starting with X-Plane 12 it is possible to independently scale symbols and text of the navdisplay, and also change the relative locations of symbols and labels. Customization of the map display is possible by editing the map_s_HM-1.png, map_s_HM-2.png, map_s_HM-2.png and map_s_HM-4.png graphics and supplying the graphics specific for your aircraft through the library system (the path is cockpit/EFIS/EFIS_maps). These png files can supply alternate symbols, colors or fonts to generate the style of the nav display. Learn more: Navigation Display Scaling
New HUD
X-plane 12 contains a new 3-d HUD system. This system is unrelated to existing tech for a HUD in 2-d panels or in the “forward with HUD” view.
The new HUD works by projecting a region of the 3-d panel in front of the aircraft in the distance, but only drawing it where it intersects a 3-d modeled HUD glass. This simulates the real-world HUD experience of the HUD being focused at infinity (and aligning with the horizon), while only being visible when the pilot’s head is within a specific 3-d box in the aircraft.
To use the new HUD you will need to do three things:
- Specify the geometry of the HUD in the Plane-Maker viewpoint screen, cockpit tab, 3-d HUD section. You specify both:
- The panel texture area to be used as the HUD (in pixels) and
- The angle of the HUD from the pilot’s view (as field of view ratios).
- Build the HUD image in your 3-d panel in the appropriate area.
- In one of your objects marked interior glass, use the new ATTR_hud_glass to mark the glass that the HUD “appears on” and make sure that that OBJ is in the “glass reflective” light group in X-Plane.
To calculate the FOV ratios, use the trigonometric tangent function for the angle from center for each side. So for example, a HUD with 20 degrees below the horizon and 10 degrees above would have an FOV ratio of tan(-20) and tan(10) or -0.364 for the bottom and 0.176 for the top.
For an example of the 3-d HUD, see the F14.
OPEN ISSUE: as of this writing, the HUD light levels are not correctly set. Future guidance will come when this issue is resolved.
Plane Maker Updates
Airframe and Tail Anti-Ice and De-Icing boots
X-Plane 12 treats the tail surfaces different from the wing surfaces when it comes to ice accumulation and anti- or de-ice measures. Learn more: Airframe and Tail Anti-Ice and De-Icing boots
Autopilot
Navigation Source
This article summarizes X-Plane’s capabilities when it comes to modern integrated approach navigation and sheds light on the new datarefs: Autopilot Navigation Source
Autopilot VNAV modes
X-Plane knows two different types of VNAV, which can be described as “GA” and “Airliner”-type VNAV. The main difference is the availability of auto-throttle. “GA” without auto throttle can only do geometric descents – the vertical path is controlled by the autopilot, while the pilot controls the speed by the throttle (or speedbrakes). “Airliner” with auto-throttle uses the auto-throttle to set climb power in climb, hold the selected cruise speed in cruise, and comply with speed restrictions (if physically achievable) in descend.
For a detailed explanation and examples see the article Autopilot VNAV modes and PlaneMaker settings.
Auto-coordination
If your aircraft requires rudder pedal input to operate realistically (especially single engine propeller aircraft and light twins) consider configuring the constants for the new auto-coordination to improve the experience for users with no rudder hardware.
Directional Gyro
X-Plane 12 changes the way directional gyro drift is calculated and the behavior of the directional gyro drift data refs. If your aircraft or plugin adjusts or watches these datarefs, you will want to check whether your code still works with the new drift. Learn more: Directional gyro drift and adjustment datarefs
FADEC Controlled Engines
X-Plane can limit the power output of altitude engines (or flat-rated engines) in order to not overtemp or overtorque them. In addition to thrust or torque limiting, X-Plane 12 can also limit to N1 or EPR values. Learn more: FADEC controlled engines
Flight Control Trim
If your aircraft is configured to have a trimmable horizontal stabilizer, there is no change in behavior from X-Plane 11. X-Plane 12 allows for three distinct ways of trimming the flight controls, and allows assigning different types of trim to different axes, so it is possible to have a trim tab on the elevator, but a pre-loaded centering spring on the rudder, as is common with many general aviation aircraft like the Cessna 182. Learn more: Types of flight control trim
Flight Control Splits
In case of a flight control malfunction where a jam occurs in one system, it is usually possible to split the controls, in some aircraft by pulling a flight control disconnect handle, in others the torque tube shears when a certain (high) load is applied to it. X-Plane simulates both the type of failure and the flight control split to deal with it. Learn more: Flight Control Splits
Helicopter Governors
X-Plane 12 revises the interaction of collective and throttle control in helicopters. Existing helicopters retain the default behavior of X-Plane 11 until modified in Plane Maker 12 to opt into one of the new governor systems. The joystick control assignments for collective and throttle don’t change, but there’s a new joystick curve available for Robinson-style throttle control. Learn more: Helicopter governor and correlator configuration
Hydraulic systems
X-Plane has three hydraulic systems per aircraft that can power a variety of actuators. Most notably, each flight control surface can be powered by any combination of hydraulic actuators. Learn more: Hydraulic systems and flight controls
Gear systems
If you have a three-position gear switch (Up-Off-Down) that you are using custom scripting/animation for, consider checking the new default option: Hydraulic gear systems
Moment of Inertia/Radii of Gyration
If you have customised the radii of gyration to achieve a “more heavy/stable” feel for your aircraft, consider switching to actual payload stations instead to achieve dynamic moment of inertia calculation based on actual load-out: Weight & Balance and Load Stations
Idle speeds
Setting up idle speed is a three-step process:
1. Getting the internal friction right
2. Setting the right amount of throttle to overcome the internal friction
3. Setting the fuel flow for that idle throttle
Learn more: Tuning Idle Speeds.
Pilot and Copilot Flight Control Inputs
X-Plane 12 differentiates between pilot & copilot sides for cockpit animations, joystick hardware, and plugins. Learn more: Pilot and Copilot Flight Control Inputs
Propeller overrides
X-Plane features datarefs that let you override parts of the flightmodel. While these datarefs are often named for the dataref whose value you control when the override is enabled, they really act by removing logic blocks from X-Plane’s flight model and systems simulation. Learn more: override_prop_pitch and override_prop_mode
Single Spool Engines
Aircraft that were using single spool engine types and relying on X-Plane to convert these to double spool engines should correct the engine type to “jet 2 spool” in Engines Specs > Engines 2 tab, then double check performance.
Stabilizer Trim and Servo
X-Plane provides two ways to trim the elevator or stabilizer of a plane: Mechanical or with an electric servo. The presence of an electric servo has consequences to the type of commands you can use to move the trim, and the commands you want to set up for hardware. This article explains the interaction of the commands and X-Plane systems code: Stabilizer Trim and Servo
Windshield ice and rain protection
X-Plane 12 simulates more than one glass surface for looking out. This affects how new 3D rain, icing, defrost, and wipers behave. Learn more: Windshield ice and rain protection datarefs
Radios and Navigation
Changes have been made to standalone DME, TACAN stations, and WAAS reception. Learn more: Changes to Radio Navigation
Weapons
Master Arm
In X-Plane 11 and earlier, the “master arm” command and panel switch had no effect on the sim. In X-Plane 12, master arm now functions: when the master arm switch is off, the only weapons that will fire are flare and chaff. When the master arm is on, weapons will fire based on their prior selection rules, e.g. if they are either selected in the weapon console or by the various individual arm/disarm datarefs by weapon type.
A new writable dataref sim/cockpit2/weapons/master_arm provides writable access to the switch position.
For compatibility, aircraft are loaded with the master arm switch on, so existing aircraft without a master arm switch will have functioning weapons. If you have this switch you can initialize it to off in a flight-initialized plugin callback.
Sound
FMOD 2.02
X-Plane 12 now runs FMOD 2.02, and while your older, already compiled sound banks will still work on X-Plane 12 with no changes, the workflow for new projects has a few caveats. Learn more: FMOD 2.0 upgrade notes.
X-Plane features datarefs that let you override parts of the flightmodel. While these datarefs are often named for the dataref whose value you control when the override is enabled, they really act by removing logic blocks from X-Plane’s flight model and systems simulation. This article explains the exact effects of overriding the prop_pitch and prop_mode overrides.
Prop Modes In X-Plane for Constant RPM Props.
X-Plane’s prop model features four prop modes for constant-RPM props in sim/flightmodel2/engine/actuators/prop_mode:
- Feathered (prop_mode = 0): the prop goes to its feathered pitch as set in the .acf file.
- Alpha range (prop_mode = 1): this is normal operation – a target RPM is set with the blue prop levers. This is visible via sim/cockpit2/engine/actuators/prop_rotation_speed_rad_sec. The governor tries to adjust pitch within the range of the min and max pitch as set in Plane-Maker to maintain commanded RPM if possible.
- Beta range (prop_mode = 2): prop pitch is commanded directly with the throttle as it moves through the beta range – the engine is at idle and the prop angle changes. On some planes the prop may even go into a reverse range while in beta mode – this is set in Plane-Maker.
- Reverse range (prop_mode = 3): prop pitch is commanded directly with the throttle and goes from the beta pitch to reverse pitch, and throttle commands the actual throttle. This can be used to simulate reverse-by-throttle or a range of reverse angles or both.
X-Plane will set the prop target speed with the prop joystick axis if assigned, and the throttle with the throttle axis if assigned. The prop mode is set between reverse/beta/alpha by commands, and feathering happens via a series of on-board systems, e.g. feather when mixture is pulled, auto-feather, or feather when the prop lever is pulled past a detent.
Overriding prop_mode
When sim/operation/override/override_prop_mode is set to 1, X-Plane will not move the prop mode between alpha, beta and reverse when (1) the panel 2-d throttles are dragged or (2) a joystick axis moves into a new range on an aircraft with beta and reverse ranges built into the throttle. (This is a .acf setting.)
X-Plane will change modes if you write to the dataref or when commands like sim/engines/thrust_reverse_toggle and sim/engines/beta_toggle are run; to ensure complete control of the dataref, override commands that affect beta or reverse.
When prop_mode is overridden and prop_pitch is not overridden, X-Plane will control feathering automatically, and writes of 0 to the prop_mode will be rejected. Automatic feathering in the sim will still work.
Overriding prop_pitch
When setting sim/operation/override/override_prop_pitch to 1, X-Plane will not change the prop pitch. A bunch of code is bypassed:
- The joystick prop axis will not set the prop pitch (for variable pitch props) and will not set the target RPM (for constant RPM props). You must read the axis yourself using sim/joystick/joy_mapped_axis_avail and sim/joystick/joy_mapped_axis_value – array index 8 for a single global prop lever or 24-27 for individual prop levers.
- Constant mach and thrust-vectored props will not auto-adjust the target RPM.
- Feathering is disabled; you must set the prop mode to feather, and you must set the actual prop angle. Setting a prop mode of 0 and not setting the angle will not result in feathering!
- Constant RPM props will not set their pitch.
You can set the prop angle directly via sim/cockpit2/engine/actuators/prop_angle_degrees.
Setting up idle speed is a four-step process:
- Setting the minimum “smooth” running speed.
- Getting the internal friction right.
- Setting the right amount of throttle to overcome the internal friction.
- Setting the fuel flow for that idle throttle
The “minimum engine running speed” setting in Plane Maker does NOT set the idle speed itself, but the minimum engine RPM that results in a smooth operation. This speed is lower than what we want the engine to actually idle at. If the RPM falls below the minimum running speed we will experience “stumbling” that manifests in RPM and torque fluctuations. If RPM drops far enough below that minimum speed, combustion itself will be affected and unable to sustain engine operation at all. The engine will come to a halt. The strength of the stumbling effect at lower-than-minimum RPM is determined by the number of cylinders that is set in Plane Maker. A four cylinder engine will exhibit more stumbling than a 6 cylinder engine or a radial engine with even more cylinders.
For a typical flat-four engine, the target idle will be around 600-700 RPM, while the minimum running RPM should be set closer to 500. This provides a good margin to keep the engine running under load from the alternator and at higher altitudes and hotter days where the engine makes less power. If the RPM drops below that setting of 500, expect erratic engine behavior.
The idle throttle setting serves one purpose, and that is overcoming the engine’s internal friction. The idle speed of the engine is determined by the equilibrium of the torque produced by the engine at idle throttle setting and the torque consumed by the engine at idle. That torque that needs to be overcome is the engine’s own internal friction, plus the small torque consumed by the propeller rotating at slow speed, plus any additional loads from the generator the engine needs to turn.
The engine’s internal friction is controlled in Plane Maker with the “engine friction” ratio. X-Plane’s guess at 1.0 works for a big-bore high compression direct-drive engine such as the IO-550 found on a Cirrus or Columbia. Other engines with different compression ratios or gearing will likely require different values here.
A good way to find the right internal friction, if the propeller is set up correctly, is to turn the engine off in flight (by cutting the mixture) and slowing the aircraft down to just above stall speed. The engine should almost stop turning as the airplane approaches stall speed, but rotate practically unaffected at greater air speeds (note that once fully stopped, a disproportionately high airspeed is needed to get the prop turning again).
The suggested process is to tune the sim/aircraft2/engine/engine_friction_ratio dataref in the simulator, take note of the value that produces the desired result, and then set it to the acf permanently in Plane Maker.
Once the internal friction is set, the airplane should be placed at a sea-level airport in standard atmosphere (15C OAT, 1013hPA QNH) and the electrical system loaded up with all electrical loads that are reasonably expected to be on on the ground ready for take-off, that is avionics bus powered, navigation and landing lights on, etc.
Then the idle throttle adjustment (sim/aircraft2/engine/high_idle_ratio) should be made so that the engine runs at a minimum smooth idle RPM with the throttle all the way out.
This will likely be too low to run the generator or alternator enough to charge the battery. That is not a bug, but corresponds to behavior found on many real piston aircraft. Basically all real piston engines require a positive throttle input to run at a high enough RPM to sustain generator load to charge the battery along with other electrical loads.
It is important to let the engine run for a minute or longer, as it might take some time to find the equilibrium between drive torque (generated by the engine) and drag torque (consumed by the engine itself, the propeller, and the generator).
The idle should be tweaked in the simulator with the sim/aircraft2/engine/high_idle_ratio dataref, and the desired value then set permanently in Plane Maker.
Once the engine runs stable at a low RPM in this config, it is up to the user (i.e. pilot, not aircraft developer) to run the throttle up enough to sustain battery charging.
Finally, the desired fuel flow at this setting can be adjusted with the dataref sim/aircraft/overflow/ff_rat_idle_PRP in the simulator and permanently saved to the acf in Plane Maker on the SFC (specific fuel consumption) tab.
Note that setting the engine up like this corresponds to a sea-level setup as would be performed on most aircraft.
Taking this aircraft to a high elevation airport such as Leadville, CO, will result in the engine stumbling or maybe even stopping at idle in a very short period of time. That is not a bug, but corresponds to how a real aircraft would behave at high density altitudes. It is absolutely necessary to lean the mixture and increase the throttle to sustain a good idle at high density altitudes, both in the real world and in X-Plane. In practice, the pilot will add throttle to keep the engine running, then slowly pull out the mixture control and watch the tachometer, to lean the engine to peak RPM, then reduce the throttle again to the desired RPM as dictated by electrical needs.
This document outlines how to test X-Plane via CLI commands and telnet.
Laminar Research develops tests via telnet, then passes them to X-Plane via script.
Using telnet
Launch X-Plane with the CLI flag
--testing
Then connect to the sim using the CLI command
telnet localhost 49000
List of Commands
acf <string>
Loads the aircraft at the specified path (be sure to use quotes). Ex: acf “Aircraft/Laminar Research/Cessna 172SP/Cessna_172SP_G1000.acf”
move lle <latitude> <longitude> <elevation in meters>
Reposition your plane at an exact lat/lon/elevation. Note: aircraft will be initialized with 0 airspeed, so this is best used on the ground if possible.
move <ICAO> <optional ramp start>
Reposition the aircraft at the specified airport. Defaults to runway 0, unless a ramp start is specified.
command <command> <optional time in seconds>
Execute the specified command for the specified duration, in seconds. See Commands.txt for the full list of commands. Note that the test runner is incredibly fast, so it’s recommended to add a
wait
(see below) after each command.
Datarefs
dref set <dataref> <value>
Set a dataref & value. See DataRefs.txt for the full list of datarefs.
expect <dataref> <conditional> <value>
Checks that the specified dataref meets an expected value. Ex. expect sim/flightmodel/engine/ENGN_running[0] == 1
wait <time in seconds, can be a decimal>
Waits the specified time before executing the next line. Important to use after commands to ensure it fully completes before moving on. Waiting longer times, such as multiple minutes, after a move or aircraft load can be useful to ensure all aspects of a flight stabilize.
camera dump
Outputs current camera location to telnet.
camera <additional params>
Sets specific camera location. (Recommended to get the exact command from camera dump.)
quit
Quit the sim. Also useful to reset parameters between tests.
Writing & Running tests
Test files must include the following header:
A
1000
CLI_SCRIPT
Save your test script as a .txt or .test file.
Use the command line argument
--script=[file name]
To launch X-Plane and run your test script. Note that X-Plane will use the existing preferences at launch. If there are syntax errors in your script, X-Plane will print the error in the terminal (Mac only) and log.txt for investigation. The results of the test run will be output in the same places as well. Finally, tests that fail any “expect <dataref>” lines will automatically save a screenshot at the fail point in the main X-Plane directory.
Example Script
Download a sample script here.
This document provides guidelines for using OpenGL to draw from X-Plane plugins running inside X-Plane’s process.
While X-Plane can use OpenGL, Vulkan, or Metal drivers to render to a graphics card, plugin-drawing is supported only via OpenGL. OpenGL is not the fastest or most modern API, but it does provide a robust way to draw in 3-d without exposing complicated and error prone implementation details like memory management, resource barriers, or concurrency, making it an appropriate choice for custom user interface and custom aircraft glass displays.
General principles
In our work with third party add-ons, we see three kinds of add-on behavior that cause almost all of the compatibility problems, bugs, performance loss, and crashes. Here are three guiding principles for interacting with X-Plane.
Do Not Lie to X-Plane
If your add-on uses plugin APIs for purposes other than their intended uses, you may have performance or compatibility problems later. Avoid things like using drawing callbacks for non-drawing purposes, using 3-d drawing callbacks for 2-d drawing, or non-window callbacks for UI.
If your add-on lies to X-Plane about your intentions, X-Plane no longer has optimal situational awareness and can no longer run plugins in an optimal way. Achieving the best possible performance is only possible if everyone plays fair and by the rules.
Minimize XPLM and OpenGL Use
X-Plane users care deeply about performance; minimize your use of OpenGL and the XPLM to minimize your add-on’s negative impact on framerate. Only perform operations that are necessary, and cache values retrieved through XPLM API, except for OpenGL resources, to be reused later if possible. When drawing, avoid repeated OpenGL state changes and adopt modern OpenGL techniques where feasible. Using shaders and vertex buffer objects for static geometry is much faster than using pre OpenGL 2.0 immediate mode rendering.
Do Not Use Undocumented Behavior
Do not use the SDK in ways that are not covered by the documentation; undocumented use of the SDK can appear to work but destabilize the sim or interfere with other add-ons, or can break in a future X-Plane update. If you are not sure from the documentation whether something is legal, ask us!
Drawing Callbacks
Plugins receive an opportunity to draw inside X-Plane via drawing callbacks; the following section provides guidelines for when and how to use drawing callbacks correctly.
Register only the drawing callbacks that you need at the time you need them to do actual drawing! Dispatching any drawing callback requires a not-insignificant CPU time overhead and requires heavy synchronization in the case of Vulkan and Metal, both of which are completely wasted if no drawing actually happens.
Use Drawing Callbacks Only for Drawing
Use drawing callbacks only for drawing, not for updating simulation state, bookkeeping, network IO, etc. Drawing callbacks can be called multiple or zero times per frame based on the user’s monitor configuration, so add-ons that use drawing callbacks for other purposes both hurt performance and may not work correctly in some situations.
Use Real Windows for UI
Using real windows and the XPLM 3.x window API (XPLMCreateWindowEx, etc.) is highly recommended over using legacy draw callbacks. This provides the sim with the most situational awareness to improve dispatching and compositing of plugin windows. The real window API also provides correct UI interaction for floating windows and focus.
Use Drawing Callbacks for Panels
The panel and gauge drawing callbacks let you draw under or on top of the 2-d and 3-d panel. Be sure to check the draw-type datarefs for the callbacks – see Datarefs for Panel Drawing below. Your panel draw callback can be called for both the albedo layer and the emissive layer of the panel separately; make sure your code draws the appropriate content for each.
Use a Flight Loop Callback for Off-Screen FBOs
Use a flight loop callback to draw into your offscreen framebuffer. When you do this, X-Plane will not have set an FBO up for you to draw into, so you will bypass the overhead of synchronizing with our drawing on the GPU.
Use XPLMInstance and Particles for 3-d Drawing Where Possible
Avoid using the 3D drawing callbacks unless absolutely necessary. Dispatching 3D drawing callbacks comes with potentially negative performance impacts and isn’t necessary most of the time.
The best interface for drawing “stuff” in the 3-d world is the XPLM instancing API to draw objects into the world or tie particle effects to your custom datarefs in order to create custom effects. The instancing API is straightforward to use, available since X-Plane 11.0, and replaces XPLMDrawObject and XPLMDrawAircraft.
See also the Plugin Compatibility Guide for X-Plane 11.50.
Use a 2-d Callback for “Coach Marks”
When drawing overlays or other kinds of scene annotations, a 2D drawing callback is much better suited than a 3D drawing callback. You can use the projection matrices provided by X-Plane to efficiently transform 3D coordinates to 2D screen coordinates.
A sample of this can be found here: https://developer.x-plane.com/code-sample/coachmarks/
See also the Plugin Compatibility Guide for X-Plane 11.50.
Use a Panel Texture to Draw “on” the Aircraft
If you need to draw onto the aircraft, e.g. to simulate damage to the fuselage, rain on a wind-screen, or a livery change, you can map a panel texture to that section of the aircraft and then use a panel drawing callback for drawing. This can be used for dynamic decals or other effects, for example, that would otherwise require complicated use of the 3D drawing callbacks.
Panel texturing is available for all parts of the aircraft, not just the cockpit object, but is more expensive than using disk-based textures – use it only where the dynamic effect is absolutely necessary.
If your add-on needs more panel texture space, you can use panel regions to get access to four separate dynamic textures.
Use the New 3-d Callback on Windows Only When Necessary
Using the new 3D drawing callback under Vulkan is not recommended unless absolutely necessary! It comes with a lot of gotchas and caveats and is intended only for add ons that truly need to do custom scenery drawing in 3D, like weather add ons. Before using the 3D drawing callback, evaluate all alternatives to see if there isn’t a better solution for what you are trying to achieve.
The new 3-d drawing callback works with OpenGL and Vulkan but not Metal; when running under Vulkan, a number of aspects of the drawing environment will be different:
- The depth buffer will be in reverse-float-Z, not standard integer format; the clip control will be DirectX style and the depth compare function will be inverted.
- The origin of the frame buffer may be inverted.
See the appendix for datarefs that let a plugin dynamically detect these conditions.
See also: Plugin Compatibility Guide for X-Plane 11.50.
OpenGL State Management
Your plugin shares an OpenGL context with other plugins and sometimes with X-Plane itself; this section provides guidance on how to change OpenGL state correctly.
Don’t Call glGetXXXX
Do not use glGet to retrieve OpenGL state. This usually results in some kind of stall for the driver and has detrimental effects on performance. For custom state management it is usually much better to potentially set OpenGL state again and then cache that known value for future state changes.
X-Plane provides access to the transform stack (upon entrance to your call stack) and viewports via datarefs, as well as the currently bound FBO (although ideally this should not be changed).
If you need a state that isn’t covered here, please contact us – there may be a different way to approach your rendering code.
Call glGetError in Debug Builds Only
Please call glGetError in debug builds and don’t ship code that breaks the OpenGL state machine. Your plugin should never execute code that leaves an OpenGL error in place.
When shipping your plugin, do notcall glGetError as it can hurt performance. A simple macro that wraps glGetError() calls and makes it easy to toggle usually works best and makes it easy to ship the version of code you want.
If your add-on creates framebuffers, please do check for framebuffer completeness once when you create the FBO; your add-on should not create and destroy FBOs on a regular basis.
Use the XPLM APIs to Manage State Where Possible
The XPLM APIs provide a number of calls to manage state; where these functions exist, please use them; they will avoid setting state multiple times.
- XPLMSetGraphicsState controls blend enable, fixed function alpha test enable, depth mask and depth test enable, fixed function fog and lighting, and fixed function texture enabling.
- XPLMBindTexture2d controls the 2-d texture binding point.
- XPLMGenerateTextureIDs wraps texture object generation.
Restore all Other State Except Attributes When Done
Any OpenGL state other than vertex attributes that is not covered by the APIs above must be restored to its initial state when your callback completes. This includes:
- Unbinding any bound shaders, VAOs, VBOs and non-2d textures to 0.
- Restoring the drawing array state (only the fixed function vertex array should be enabled).
You do not need to reset the client array pointerstate, nor should you assume upon entrance to a callback that it contains anything sane.
Restore the Current FBO By Dataref
If you must render to an offscreen FBO in a draw callback for some reason, you must restore the currently active FBO before returning from it. Don’t call glGet() to retrieve it, instead use the sim/graphics/view/current_gl_fbo dataref to figure out what FBO to restore.
XPLMDrawString and Friends May Change State
XPLMDrawString and the other API drawing calls can change all of the states mentioned above; while you do not need to clean up after them, do not assume your own state setup is correct after they have been called.
Illegal OpenGL Usage
The following techniques are not allowed from plugins running inside X-Plane.
Do Not Draw from Non-Drawing Callbacks
Non-drawing callbacks aren’t necessarily dispatched in a way that supports drawing. Drawing in a non drawing callback will lead to undefined behavior with regards to your own rendering and the effects on the rest of the sim.
Do Not Mutate X-Plane’s OpenGL Resources
Resources obtained through the XPLM API should be seen as immutable, with the exception of the contentsof the active FBO during draw callbacks. Attempting to change any internal X-Plane resources can lead to heavily decreased performance or have other unexpected side effects, like crashing.
Do Not Locate and Use Private X-Plane OpenGL Resources
Resources not exposed through the XPLM API are not fair game for use. These resources aren’t guaranteed to remain stable between or even within X-Plane runs or future versions. X-Plane is assumed to be the only consumer of these resources and will not attempt synchronizing with plugins when modifying them.
Do Not Hold on to X-Plane OpenGL Resources
While it might be tempting to hold on to OpenGL resources obtained in previous draw callbacks and then reuse them in other callbacks, doing so can have disastrous consequences. This is especially true under Vulkan and Metal, where resources require special synchronization. If missing, this can lead to driver or system crashes and desktop freezes.
Do Not Change State to Affect X-Plane
Attempting to change OpenGL state to trick X-Plane into rendering differently is heavily discouraged. This can lead to X-Plane doing improper bookkeeping of its own state, which can lead to heavily impacted performance. This is also not guaranteed to work between versions or even between runs and can break at any time.
Performance
This section contains performance guidelines for OpenGL plugins.
Pre-Initialize Your Add-on
Perform heavy initialization at aircraft load or flight start time. At runtime, a plugin should be able to just work without lazily initializing any state or computing expensive look up tables. The goal should be to never add unpredictable latency to the frame time.
Do Less
Avoid unnecessary work; preload resources and precompute expensive results.
Follow standard OpenGL performance practices:
- Move computing work from fragment to vertex shaders.
- Reduce API calls that change state.
- Reduce the number of draw calls by merging them where possible.
Do More but Consistently
Attempting to improve framerate by adopting a flip-flop mechanism where one frame doesn’t do heavy work and the other does is highly discouraged. Schemes like this help nothing with the perceived performance of the sim, on the contrary, the very uneven frame times will have a noticeable impact on the user experience. It is much better to instead do the work every frame and provide a slightly lower but much more consistent framerate. Consistently drawing frames on the screen makes the sim appear much smoother to the user.
Consider Using Multicore
If your add-on needs to compute values per frame that are expensive (e.g. take several milliseconds to compute) and you cannot optimize the computation, consider doing the work on a separate thread.
Moving work to a separate thread in a plugin is quite complex because:
- The SDK provides no built-in facilities to help with this.
- No SDK APIs may be called from worker threads you create.
- You do not have access to the SDK-provided OpenGL context from a worker thread.
- You cannot block waiting for data completion from an SDK callback.
Typically to make this work you will need to launch a worker thread once and have it block on a semaphore to pick up tasks that can be computed independently without XPLM calls and then returned to the main thread via some kind of thread-safe queue.
Appendix A – DataRefs
This section covers datarefs that can be used to get more information about the rendering environment or interact with X-Plane during drawing callbacks. All callbacks should be resolved via XPLMFindDataref at plugin startup but should be read from inside the drawing callback to get information contextual to a particular draw callback. Read results may be undefined outside of or in the wrong draw callback.
Datarefs for Panel Drawing
These drawing callbacks are appropriate from panel drawing callbacks (before/after panel and gauges).
sim/graphics/view/panel_render_type (int, read-only)
This dataref indicates the type of panel rendering being done:
- 0 render the entire panel (day time and lit elements with full lighting for 2-d panels)
- 1 albedo only (render solid elements without lighting)
- 2 emissive only (render lit elements only)
sim/graphics/view/panel_render_new_blending (int, read-only)
This dataref indicates whether the blending mode for the 3-d panel for the current aircraft is the deprecated, legacy “max” alpha blending mode or the modern preferred alpha blending with correct alpha treatment.
- 0 blending mode is legacy max mode
- 1 blending mode is modern
The blending equation for legacy max mode is:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
The blending equation for modern blending mode is:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
Modern blending mode will correctly composite multiple translucent elements over a translucent or clear panel; legacy max mode gives incorrect but often acceptable results.
Warning: legacy max mode is deprecated and will be dropped from X-Plane in the future. At that point all aircraft will render using blend mode regardless of the content of their art assets.
Datarefs for Panel Clicking
When the mouse is being used over a 3-d panel (via a region mapped with ATTR_cockpit), the following datarefs provide information about the click location.
sim/graphics/view/click_3d_x (float, read-only)
sim/graphics/view/click_3d_y (float, read-only)
This is the location of the mouse in the UV map coordinates of the underlying object.
sim/graphics/view/click_3d_x_pixels (float, read-only
sim/graphics/view/click_3d_y_pixels (float, read-only)
This is the location of the mouse in panel pixel coordinates, or -1 if the mouse is not over the panel.
For all of these datarefs, they are only valid during draw callbacks for the monitor that the mouse is over. Therefore if your plugin is multi-monitor aware, you need to read these from the draw callback for the window that you are using to capture clicks.
(We do not recommend using these datarefs to implement mouse interactions; to capture clicks on a 2-d screen, use a generic instrument on the panel, or consider a real 3-d manipulator on the object itself.)
Datarefs for Panel Location and Scrolling
The location of the panel is provided via two sets of rectangles during panel and gauge drawing callbacks:
sim/graphics/view/panel_total_pnl_l (float, read-only)
sim/graphics/view/panel_total_pnl_b (float, read-only)
sim/graphics/view/panel_total_pnl_r (float, read-only)
sim/graphics/view/panel_total_pnl_t (float, read-only)
These four datarefs form the total bounds of the panel in the modelview coordinate system of the panel drawing callback. You can use these datarefs from inside a panel drawing callback to “calibrate” the location of your drawing. Due to scrolling of panels, the origin of the panel bitmap is not guaranteed to be in any one location on the panel.
sim/graphics/view/panel_visible_pnl_l (float, read-only)
sim/graphics/view/panel_visible_pnl_b (float, read-only)
sim/graphics/view/panel_visible_pnl_r (float, read-only)
sim/graphics/view/panel_visible_pnl_t (float, read-only)
These four datarefs provide the rectangle within the panel that is visible within the current OpenGL viewport. If the panel does not completely fill the viewport, some values could be outside the total bounds of the panel.
These datarefs can be used to identify which panel region is being rendered, for aircraft that use cockpit panel regions. They can also be used to cull gauge drawing that is not going to be visible.
Note that these datarefs are not the same as the current viewport – they are specified in modelview coordinates – that is, the current transform in effect for OpenGL drawing.
sim/graphics/view/panel_total_win_l (float, read-only)
sim/graphics/view/panel_total_win_b (float, read-only)
sim/graphics/view/panel_total_win_r (float, read-only)
sim/graphics/view/panel_total_win_t (float, read-only)
For 2-d panels that are visible on-screen, these datarefs provide the location of the total panel in modelview coordinates during UI drawing callbacks (e.g. post-window draw callbacks and XPLMDisplay window draw callbacks). These datarefs can be used to calibrate the panel location to user interface elements.
sim/graphics/view/panel_visible_win_l (float, read-only)
sim/graphics/view/panel_visible_win_b (float, read-only)
sim/graphics/view/panel_visible_win_r (float, read-only)
sim/graphics/view/panel_visible_win_t (float, read-only)
These datarefs provide the visible extent of the panel in current modelview coordinates during UI callbacks; they can be used for culling gauges that are drawn in UI layers but must match the panel’s location.
Datarefs for 3-d Drawing Callbacks
These datarefs can be read during 3-d drawing callbacks to find details about 3-d drawing.
sim/graphics/view/world_render_type (int, read-only)
This dataref indicates the type of rendering that X-Plane is trying to accomplish with its 3-d callback. The following render passes are visible to plugins:
- 0 Regular 3-d rendering pass
- 1 Prep source imagery for water reflections
- 3 Render depth for shadow maps
- 6 Prep source imagery for environment cube maps
3-d draw callbacks may be called more than once, so opting out of drawing based on this enumeration can have performance benefits.
Note: by default only regular 3-d render passes are dispatched to plugins; you must enable the capability “XPLM_WANTS_REFLECTIONS“ to receive other types of 3-d drawing callbacks.
Note: the modern 3-d callback does not dispatch shadows; use XPLM object instances for shadow-casting solid geometry.
sim/graphics/view/plane_render_type (int, read-only)
Before X-Plane 11.40, the aircraft drawing phases were the only ones that correctly separated solid and blended drawing; during an aircraft-phase drawing callback this dataref contains:
- 1 Solid geometry is being drawn for the aircraft. If HDR is enabled and the drawing pass is normal, drawing is going into the G-Buffer.
- 2 Blended geometry is being drawn for the aircraft. If HDR is enabled, this will be after the G-Buffer is resolved.
For plugins using the modern 3-d drawing callback, the one callback that a plugin receives is equivalent to a post-aircraft drawing callback for blending. Solid drawing is not available – use instancing to add models to the X-Plane world.
sim/graphics/view/draw_call_type (int, read-only)
For 3-d drawing callbacks, this dataref indicates the type of drawing being done for VR multi-eye rendering:
- 1 Mono (regular) drawing is in progress
- 3 Stereo drawing is in effect and this call is to render the left eye
- 4 Stereo drawing is in effect and this call is to render the right eye.
When the left and right eye are dispatched, the transform stack will have been modified to take into account per-eye offsets.
sim/graphics/settings/HDR_on (int, read-only)
This boolean dataref tells whether the HDR deferred renderer is enabled.
- 0 HDR is not enabled
- 1 HDR is enabled
sim/graphics/settings/scattering_on (int, read-only)
This boolean dataref tells whether atmospheric scattering is enabled; since atmospheric scattering is always on in X-Plane 11, it will always have a value of 1.
Datarefs for OpenGL State and Modes
All drawing callbacks provide datarefs that provide access to the transform stack at the time your drawing callback is called.
sim/graphics/view/projection_matrix (float[16], read-only)
sim/graphics/view/modelview_matrix (float[16], read-only)
sim/graphics/view/viewport (int[4], read-only)
These three datarefs provide complete access to the modelview, projection and viewport transformations, allowing you to map between modelview and OS window coordinates.
sim/graphics/view/world_matrix (float[16], read-only)
sim/graphics/view/acf_matrix (float[16], read-only)
sim/graphics/view/projection_matrix_3d (float[16], read-only)
These three datarefs can be read during a 2-d drawing callback or window drawing callback to gain access to the transform stack that was used to render the 3-d world, if there was a 3-d render. The world matrix provides the model-view matrix for standard OpenGL world coordinates (e.g. for XPLMWorldToLocal).
The acf matrix provides a modelveiw matrix whose origin is the aircraft’s nominal CG and whose axes are aligned with the aircraft. This is equivalent to starting with the world matrix, translating to the aircraft location and rotating by the aircraft Eulers, but may provide better precision.
sim/graphics/view/is_reverse_float_z (int, read-only)
This dataref indicates whether the depth buffer for the current drawing callback is using regular linear depth encoding or reverse-float-Z conventions.
ValueDepth FormatDepth FunctionDepth Range
0GL_DEPTH_COMPONENT_24GL_LEQUAL-1..1
1GL_DEPTH_COMPONENT_32FGL_GEQUAL0..1
The depth buffer will have an attached 8 bit stencil buffer.
sim/graphics/view/is_reverse_y (int, read-only)
This dataref indicates whether the current rendering pass uses OpenGL conventions for the framebuffer (origin in lower left, Y axis points up) or DirectX/Metal Conventions (origin in upper right, Y axis points down). Even when X-Plane is running in reverse Y mode, the transform stack will be set up such that the model view matrix has the same input coordinate system, e.g. Y is up in 3-d, and Z is south.
Legacy Datarefs for Object Animation
When datarefs are read from a plugin to compute an object’s animation pose or to calculate the setup of its lights, the following datarefs are available to read to learn which object is being rendered.
sim/graphics/animation/draw_object_x (float, read-only)
sim/graphics/animation/draw_object_y (float, read-only)
sim/graphics/animation/draw_object_z (float, read-only)
sim/graphics/animation/draw_object_psi (float, read-only)
This technique for determining which object is being animated is deprecated and is made obsolete by XPLMInstancing.
Starting with X-Plane 11.50, users have the ability to change the graphics API that is used by X-Plane. They now have the option to choose between OpenGL (all platforms), Vulkan (Windows and Linux) and Metal (macOS). This has potential implications for third party code that interacts with X-Plane’s rendering. The main goal with Vulkan and Metal is to deliver a more consistent and higher framerate, while also maintaining compatibility with the existing add on ecosystem as much as possible.
Compatibility with existing plugins
As a general note, existing plugins running under the OpenGL renderer in X-Plane 11.50 should behave exactly the same as in X-Plane 11.41. Assuming the plugins behaved nicely and played by the rules of the SDK, compatibility between 11.50 OpenGL and 11.41 is provided.
Whether a user selects OpenGL, Vulkan or Metal, the following kinds of operations don’t require any changes to existing add-ons:
- Scenery add ons. All renderers support the existing scenery features and texture formats and will look the same on all platforms.
- Plugins that don’t interact with the rendering system and instead provide additional functionality without the need to draw in the world.
- Window drawing using the XPLM 3 SDK windows. This includes UI elements drawn using the XPWidgets library as well as custom OpenGL drawing.
- 2D drawing callbacks. This includes UI elements drawn using the XPWidgets library as well as custom OpenGL drawing.
- Panel drawing callbacks. This includes 2D panels as well as 3D panels drawn inside the aircraft.
- 3D drawing using the XPLM instancing API.
Breaking changes have been made to the 3D drawing callbacks. All 3D drawing phases have been deprecated as of X-Plane 11.50 and will no longer be called under either the Vulkan or Metal renderer. Additionally, the XPLMDrawObjects() and XPLMDrawAircraft() APIs have been deprecated and also no longer works with either Vulkan or Metal. 3D drawing callbacks, XPLMDrawObjects(), and XPLMDrawAircraft() will continue to work under OpenGL in 11.50 like they did in 11.41.
X-Plane has offered an alternative to the XPLMDrawObjects() and XPLMDrawAircraft() APIs since X-Plane 11.10 in the form of the instancing API, which we highly encourage developers to adopt. While not a direct, drop in replacement, it offers much more flexibility for plugin authors and X-Plane than the previous system did. You can read the documentation for the instancing API here and check out our example code here.
OpenGL compatibility notes
When a user runs X-Plane with either Vulkan or Metal, X-Plane itself will exclusively run with the selected backend and no rendering is done using OpenGL. To provide compatibility with plugins X-Plane will create a OpenGL context that is exclusively for use by plugins. X-Plane will create minimal resources in this OpenGL context to enable support for APIs like XPLMGetTexture() and to facilitate sharing of framebuffers across Vulkan/Metal and OpenGL. Plugins should not assume the existence of any resources in an OpenGL context and should instead use public APIs to retrieve resources. No guarantee is made with regards to availability of resources in the OpenGL context across versions or even runs of X-Plane. Plugins that try to sniff resources from the OpenGL context, whether running under Vulkan, Metal or OpenGL, are considered misbehaved and no compatibility guarantees are made.
Plugins that use Vulkan/Metal compatible drawing operations don’t need to do any special processing or precautions. X-Plane provides all synchronization and resource sharing across the rendering APIs as part of its internal plugin bridge system. We expect this OpenGL plugin bridge to exist for the foreseeable future as something that plugins can be authored against. OpenGL provides an easy to use API for plugin needs without any of the complications that come with Vulkan or Metal.
Alternatives to 3D drawing
As mentioned above, the X-Plane 11.41 3D drawing phases have been deprecated in X-Plane 11.50 and are no longer called on Vulkan and Metal. This should not be a problem for most plugins, although a few might require changing to the XPLM instancing API. However, we have found that a lot of third party plugins rely on the 3D drawing phases to read datarefs or do internal bookkeeping, without actually doing any real drawing. This will no longer work under either Vulkan or Metal with 11.50 due to these drawing phases no longer being dispatched, although it is still possible under OpenGL.
We strongly recommend authors avoid doing this in general, even on OpenGL. 3D drawing phases are meant exclusively for 3D drawing, and dispatching them isn’t free in terms of CPU overhead on X-Plane’s end. Plugins that don’t require 3D drawing capability should instead use the flight loop callbacks to do all of their bookkeeping.
We also discovered that a lot of 3D drawing is actually in the form of overlays or other kinds of markers or labels on 3D objects. These can be done from a 2D drawing callback instead of a 3D drawing callback by transforming the 3D world coordinates onto the 2D screen and then using those coordinates to draw. This will work regardless of whether a user runs OpenGL, Vulkan or Metal. Example code that deals with the 3D world to 2D screen coordinate transform can be found here. Note though that this will always draw over world objects since there is no depth information available.
We expect most plugins to be able to entirely phase out their usage of the 3D drawing phases with minimal code changes necessary, either by adopting the instancing API, moving bookkeeping to the flight loop, or using a 2D drawing callback to draw overlays. We highly recommend exploring these alternatives to the previous 3D drawing approaches as they allow X-Plane to run much more efficiently.
3D drawing using the modern drawing phase
Plugins that require completely custom drawing in the X-Plane world with the ability to be occluded by other objects won’t work with the above work arounds. We don’t expect very many plugins to be in this category, with custom weather rendering plugins being the notable exception. For plugins like this, X-Plane 11.50 offers a new 3D drawing phase as part of the XPLM 302 SDK: xplm_Phase_Modern3D. For technical reasons this drawing phase is not available on Metal and only runs on Vulkan and OpenGL!
This new drawing phase has many caveats and gotchas and comes with the big fat warning that it isn’t very cheap in terms of CPU overhead. We highly discourage the use of it unless it’s absolutely necessary to perform real, custom 3D drawing! As mentioned before, the biggest caveat is that this drawing phase will not be called under Metal. Additionally there is only a single drawing phase now which conceptually sits right where the old before xplm_Phase_Airplanes draw phase used to be. The before and after phase of the modern 3D drawing phase are called directly in succession and no X-Plane rendering happens in between.
There are two additional things to watch out for when doing 3D rendering in general:
First, X-Plane can run with reverse-z semantincs. Meaning that the depth range is [0, 1] as opposed to the traditional [-1, 1] and the depth comparison is GEQUAL instead of LEQUAL. As a side effect, this means that the depth buffer is cleared to 0 instead of 1. When in reverse-z mode, the depth buffer will be in floating point format (DEPTH_32F) instead of the traditional 24bit integer format. X-Plane will set up the OpenGL state and projection matrices for you to reflect these changes when dispatching plugins, but it’s something you might want to be aware of if you do any depth buffer readbacks, set the depth state yourself, or calculate your own projection matrices. Whether X-Plan is in reverse-z mode can be observed through the sim/graphics/view/is_reverse_float_z dataref. When running under Vulkan, X-Plane will always run in reverse-z mode, when running under OpenGL it’ll only be in reverse-z mode for VR rendering.
Second, X-Plane can run with reverse-y semantics. In reverse-y mode, the colour and depth buffer are flipped along the y-axis (the origin is top left and grows downward). When running in reverse-y mode, it’s the responsibility of the plugin author to flip the front face winding to avoid polygons from getting incorrectly backface culled. The projection matrix provided by X-Plane takes care of the changed projection parameters, but if you do your own projection matrix set-up you’ll have to do this change yourself. Whether X-Plane is in reverse-y mode can be observed through the sim/graphics/view/is_reverse_y dataref. When running under Vulkan, only 3D drawing with the HDR renderer is in reverse-y mode. 2D rendering phases and OpenGL rendering are never in reverse-y mode.
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:
- 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
- The manipulator type that tells X-Plane what type of interaction spot to make and what happens when you interact with it.
- 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
- 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:
- 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.
- 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.
The spoken phrases and names of the ATC system come from a cloud-base Text-To-Speech (TTS) engine. Several spreadsheets of vocabulary are fed to the cloud engine to be spoken and saved as individual sound files. These are then processed and saved as part of the X-Plane resources which are distributed as part of the application. While the TTS engine is very good at getting reasonable pronunciations for most things, it is by no means perfect. Regionalization and other types of specialization are often necessary to improve the accuracy of the speech.
We have made our spreadsheets public so that the community can edit them to correct mistakes that they may find. We will periodically grab the latest spreadsheets with community corrections and rebuild our internal speech resources to include the new corrected pronunciations, then make them available as part of standard X-Plane updates.
You can find the spreadsheet here.
The spreadsheet currently contains 5 tabs along the bottom for the categories: Airlines, Airports, Aircraft Makers, Aircraft Models and VORs, as well as an instructions tab. Each category tab has two common editable fields. One is what the ATC engine will display as text on screen. The other is what will be spoken as audio output.
It’s important to note that some users will disable ATC speech and just want to see textual ATC commands. Others may disable the text and only want to hear spoken commands. Because of this, the ATC engine needs data for text and speech. For example, you may want to display “B737-800” as an aircraft type in text, but you may want to say “737 800” in speech; without the ‘B’ and without pronouncing the ‘dash’. That’s why the two columns exist independently.
Speech and pronunciation can also be adjusted by using the SSML standard. Note that you do NOT need to add <speak></speak> tags. It’s implied. There are many resources available on the web to help learn SSML syntax as well as pronunciation characters. They all should work fine, independent of the TTS engine used. It is suggested that you create a free Amazon Web Services account and use the Amazon Polly Text-To-Speech synthesizer online to listen to your syntax before editing the spreadsheet. However, you can also use Google’s online synthesizer or various others.
Please do not attempt to use pronunciation to create regional accents in the spoken words as this will make things more difficult. For example, the word Boston should be “Baw-stun” even if regionally they’d say “Bah-stin”. This type of feature IS actually possible someday but it is NOT done on the pronunciation level in the spreadsheet.
Gyro systems
X-Plane can drive the attitude indicator, also known as the artificial horizon, from any of three systems. This yields a total of six gyros you can use for your attitude instruments (pilot and copilot side). The three systems are:
- vacuum gyro – this one is driven by air being sucked through it, and the vacuum necessary to pull the air into it is generated by an engine-driven vacuum pump. This is the system most often found in simpler general aviation aircraft like a C172. X-Plane simulates a vacuum pump driven off the accessory section of the engine, thus the gyro will spin up when the engine spins up.
Check out the article on the vacuum system itself for more information.
- electric gyro – this gyro replaces the failure-prone vacuum pump, hose, and filter system with a simple electric motor inside the instrument, which spins up the gyro. You find those in non-glass Cirruses, Diamonds, and other more modern general aviation aircraft. X-Plane drives this motor off a DC electric bus, or, if checked in Plane Maker, off the AC inverter.
- AHARS – the fully electronic attitude and heading reference system replaces the gyros with sagnac laser-gyros or cheaper MEMS gyroscopic sensors (comparable to the ones in your smartphone) to generate attitude and heading information without any moving parts. This system is obviously electrically powered.
Limitations of the mechanical attitude gyro instrument
The attitude instrument uses a gimbal mechanism which allows the instrument case (and by extension, the whole airplane) to revolve around the gyro, which keeps pointing upward. The movements of the gimbal are translated by a pickup mechanism into movements of the part of the instrument the pilot is looking at. So while the plane rotates around the gimbal, the deflection of the gimbal is what causes the blue/brown part of the attitude indicator to move. It is important to keep in mind that this pickup mechanism is quite delicate, and also limited in its freedom of movement. It can indicate up to 110 degrees in bank and 70 degrees in pitch. Beyond that, the mechanism locks up and the attitude reading on the instrument becomes inaccurate. Moreover, a violent excursion of the bank or pitch limitations of the instrument can even cause permanent damage to the pickup mechanism, but that doesn’t happen in X-Plane.
After an exceeding of the instrument limitations, the indicated pitch or bank will be off, depending on how far the gyro was forced off from its natural position. The gyro rights itself at three degrees per minute in normal flight conditions, so you will see the attitude indicator correcting itself at this slow rate. To force the gyro back into the upright position quicker, you can pull the caging or fast erect knob.
Caging to the rescue
Aerobatic planes that are expected to exceed 70 degrees of pitch and 110 degrees of bank, if equipped with an attitude indicator at all, will have an instrument that allows caging. A caged gyro is locked to the instrument case, and rather than the delicate pickup mechanism taking the beating, the whole instrument absorbs the gyroscopic forces. While it is caged, the attitude indicator indicates straight and level, while the aerobatic plane can go to extreme bank and pitch angles without damaging the gyro. Back in normal flight, the gyro can be uncaged and resume normal operation.
What is “fast erect”?
On some attitude indicators, the caging knob is instead labeled “(pull to) fast erect”. The mechanism however is the same: When pulled, the gyro is forced into the upright straight and level position and locked to the instrument case, however the fast erect knob snaps back to the uncaged position when let go, while a caging knob can be locked in the caged position. Since they perform the same operation, the knob is the same dataref
sim/cockpit/gyros/gyr_cage_ratio[N]
For a fast erect knob, the dataref can be ramped up with the command
sim/instruments/ah_fast_erect(_copilot)
this simulates pulling out the knob, which instantly springs back when let go.
For the cage knob the command
sim/instruments/ah_cage(_copilot)
instead simulates toggling the knob to the pulled position.