Javier posted a video of his CRJ on the dev list today. I have not tried the plane, but there is no question from the video that it looks really good. What makes the video look so nice is the careful management of light. Part of this comes from careful modeling in 3-d, and part of it comes from maxing out all of X-Plane’s options for light.
But…what are the options for light on an airplane? I don’t know what Javier has done in this case, but I can give you a laundry list of ways to get lighting effects into X-Plane.
Model In 3-D
To really have convincing light, the first thing you have to do is model in 3-d. There is no substitute – for lighting to look convincing, X-Plane needs to know the true shape of the exterior and interior of the plane, so that all light sources are directionally correct. X-Plane has a very large capacity for OBJ triangles, so when working in a tight space like the cockpit, use them wisely and the cockpit will look good under a range of conditions.
You can augment this with normal maps in 940. Normal maps may or may not be useful for bumpiness, but they also allow you to control the shininess on a per-pixel basis. By carefully controlling the shininess of various surfaces in synchronization with the base texture, you can get specular hilights where they are expected.
The 2-D Panel
First, if you want good lighting, you need to use panel regions. When you use a panel texture in a 3-d cockpit with ATTR_cockpit, X-Plane simply provides a texture that exactly matches the 2-d cockpit. Since the lighting on the 2-d cockpit is not directional, this is going to look wrong.
When you use ATTR_cockpit_region, X-Plane uses new next-gen lighting calculations, and builds a daytime panel texture and a separate emissive panel texture. These are combined taking into account all 3-d lighting (the sun and cockpit interior lights – see below). The result will be correct lighting in all cases.
Even if you don’t need more than one region and havea simple 1024×1024 or 2048×1024 3-d panel, use ATTR_cockpit_region – you’ll need it for high quality lighting.
The 2-d panel provides a shadow map and gray-scale illumination masks. Don’t use them for 3-d work! The 2-d “global lighting” masks are designed for the 2-d case only. They are optimized to run on minimal hardware. They don’t provide the fidelity for high quality 3-d lighting – they can have artifacts with overlays, there is latency in applying them, and they eat VRAM like you wouldn’t believe. I strongly recommend against using them as a source of lighting for a 3-d cockpit.
To put this another way, you really want to have all global illumination effects be applied “in 3-d”, so that the relative position of 3-d surfaces is taken into account. You can’t do this with the 2d masks.
The 2-d panel lets you specify a lighting model for every overlay of every instrument – either:
- “Mechanical” or “Swapped” – this basically means the instrument provides no light of its own – it just reflects light from external sources.
- “Back-Lit” or “Additive” – this means the instrument has two textures. The non-lit texture reflects external light, and the lit texture glows on its own.
- “Glass” – the instrument is strictly emissive.
You can use 2-d overlays not only for instruments but also to create the lighting effect within instruments, e.g. the back-lighting on a steam gauge’s markings, or the back-lighting on traced labels for an overhead panel.
2-d overlays take their lighting levels from one of sixteen “instrument brightness” rheostats. You can carefully allocate these 16 rheostats to provide independent lighting for various parts of the panel.
The 3-d Cockpit
The 3-d cockpit allows you to specify 3 omni or directional lights. These can be placed anywhere in the plane, affect all interior objects, and can be tinted and controlled by any dataref. Use them carefully – what they give you is a real sense of “depth”. In particular, the 3-d lights are applied after animation. If a part of the cockpit moves from outside the light to into the light, the moving mesh will correctly change illumination. This is something you cannot do with pre-baked lighting (e.g. a _LIT texture).
Finally, ATTR_light_level is the secret weapon of lighting. ATTR_light_level lets you manually control the brightness of _LIT texture for a given submesh within an OBJ. There are a lot of tricks you can do with this:
- If you know how to pre-render lighting, you can pre-render the glow from a light onto your object into your _LIT texture, and then tie the brightness of the _LIT texture to a dataref. The result will be the appearance of a glow on your 3-d mesh as the light brightens. Because the lighting effect is pre-calculated, you can render an effect that is very high quality.
- You can create back-lit instruments in 3-d and link the _LIT texture to an instrument brightness knob.
- You can create illumination effects on the aircraft fuselage and tie them to the brightness of a beacon or strobe.
There are two limitations of ATTR_light_level to be aware of:
- Any given triangle in your mesh can only be part of a single ATTR_light_level group. So you can’t have multiple lighting effects on the same part of a mesh. Plan your mesh carefully to avoid conflicts. (Example: you can’t have a glow on the tail that is white for strobes and red for beacons – you can only bake one glow into your _LIT texture.)
- ATTR_light_level is not available on the panel texture. For the panel texture, use instrument brightness to control the brightness of the various instruments.
I have a sample plane that demonstrate a few of these tricks; I will try to post it on the wiki over the next few days.
In Plane-Maker you will see that there are two “glass” lighting modes for instruments – one called “glass” and the other called “glass (translucent)”.
What’s the difference? The difference is how they respond to their lighting rheostat being turned down.
- Glass becomes dim by mixing the RGB colors of the overlays toward black.
- Glass (tranlsucent) becomes dim by mixing the alpha channel of the overlays toward transparent.
Which one do you want? It depends on what you are doing. The rules I suggest are:
- Use “glass” if you are using the layer as a “mask” to block elements behind it.
- Use “glass (translucent) if you are using the layer as an “overlay” to draw on top of other elements.
X-Plane’s panel system does not have true “masking” based on a bitmap. You can clip an instrument to its rectangular region, but most masks are made by overlaying another layer or instrument on top of the moving parts. Examples include the circular mask for the moving map and the outside of the artificial horizon dial.
If you are using ATTR_cockpit then what you see in the OBJ is just like what you see in the 2-d panel, and the masking problem is simple: pick a mask that matches your background. In particular, if the back of the panel is black, your mask must be black; if the back of your panel has a gradient, the mask must contain a copy of a slice of the gradient.
But there are two cases where this rule does not work the way you might expect.
Masks for 2-d Spotlights
The 2-d spotlight textures (panel-2, panel-3, etc.) have a strange property: they light the background of the panel (the “burned in layer”) per-pixel but the overlays are lit per vertex. This is a cheat to keep the frame-rate high.
Normally this is not a problem – the moving parts are small and look different enough from the background that the lighting mismatch is not visible. But if you have a mask in the 2-d panel and spot lights, it will not match!
Unfortunately there is not much you can do about this. The only thing you can do is to keep the spotlight color uniform over the entire mask region.
Masks for Cockpit Regions
When you use ATTR_cockpit_region, the lighting model for your 3-d cockpit changes: instead of drawing the panel (as you saw it in 2-d), X-Plane calculates the albedo (day-time) and emissive (“_LIT”) components of the panel separately and then combines them with real 3-d lighting.
The good news is that the spot light problem is no longer a problem. Since the spot lights are 3-d and are applied to these final “panel textures”, a mask that matches the background will blend perfectly.
But in order to mask, you need to know which part of the panel texture you are masking (albedo or emissive!). If you are masking the albedo texture (e.g. a mechanical artificial horizon), create a mask that looks just like the panel background.
But for a glass instrument, the moving parts go into the emissive layer. Your mask must be pure black! Where did I get that from? The emissive layer adds light to the object. Black is an absence of adding light. So pure black ‘erases’ any light-only elements (which include all glass EFIS instruments, etc.).
One nice thing about this strategy: you can build a custom glass instrument (with a black mask) and put it over any background. This means you can reuse your art assets no matter how they are positioned on the panel.
With X-Plane 930 beta 8, we finally integrated the latest version of Max’s Cessna 172 SP. Grab the new beta and try it – he’s added a number of new features that demonstrate some of the newer X-Plane 9 airplane features.
- Real 3-d lighting in the 3-d cockpit. Note how the map light tends to illuminate only some of the cockpit as it fades out.
- 2-d back-lighting on all of the major steam gauges.
- A bunch of parts can now be dragged in 3-d, including the door handles. This is done via manipulators.
- Walls! In 3-d cockpit viewer mode you won’t be able to leave the airplane until you actually open the doors. The cockpit viewpoint is constrained.
- The model has the glass parts separated out for correct shadowing, and the glass works correctly from all viewpoints.
- Panel uses cockpit regions for accurate lighting.
The cirrus jet has been similarly updated. I plan to use the Cessna for a series of tutorials showing how to use these recent X-Plane features.
What is the difference between a dataref and a command? They serve different purposes in X-Plane, but it’s easy to get them confused, especially because the names can look so similar. If you only take one thing away from this comparison, it should be:
- Datarefs are information.
- Commands are actions.
A dataref is a single bit of published information. For example, the user’s indicated airspeed, as seen by the pilot, is a dataref, stored in:
Datarefs have names that do not change. Datarefs made available by X-Plane start with sim/ while datarefs made available by plugins start with another prefix. Datarefs have been in X-Plane since the release of the plugin system in version 6.70.
You can always read a dataref, but sometimes you can change it. Trying to change a dataref usually has one of three actions:
- If the dataref is not writable at all, nothing happens.
- If the dataref is writable, it will change.
- Sometimes a dataref may be writable, but only after changing some other sim configuration. For example, you can only “write” to the control surface deflection datarefs after setting the control surface override dataref to 1. (If you don’t set this override, X-Plane will constantly write its own ideas of the control surface positions to the control surface datarefs and your changes will be lost.)
You can read and write datarefs:
A command is an action that the sim can take on your behalf. For example, the command
arms the autopilot for altitude hold.
Like datarefs, commands have permanent names, starting with sim/ for X-Plane or other prefixes for plugins. Commands have been available in X-Plane since version 9.0.
You can always actuate a command, but there is no guarantee that it will do anything. For example, the engine starter command won’t start the engine if the plane has electrical starters and the battery is dead.
You can use commands by:
Plugins can add both new datarefs and new commands to the sim. Plugins can also change the behavior of all built-in sim commands, and can change the information in some datarefs.
Where Do I Find Datarefs And Commands
X-Plane’s default commands and datarefs are listed in the text files Commands.txt and Datarefs.txt in the Resources/plugins folder. (Note: providing the command list is new to X-Plane 930.) The dataref list is also available on the X-Plane SDK Wiki.
Up next: when should I use a command and when should I use a dataref?
I have been trying to put documentation on the X-Plane Wiki, and use this blog for announcements and “the inside story”, rather than letting the blog turn into a poor-man’s users manual. An aircraft developer asked me via email whether there was a blog entry on some of the pitfalls of the v9 panel lighting system. There is not, and the lighting system is under-documented. I will be working on improving the documents over the next few weeks, but the point of this blog entry is: “how did we get here?”
I am a huge fan of incremental software improvement. That’s the subject of another blog post (perhaps on another blog), but for now I’ll say this: all changes to the rendering engine since version 8.0 have been incremental ones, and yet if you were to look at the code, you wouldn’t see a series of band-aids taped on top of each other. Each incremental change leaves the rendering code “fully updated”, as if it had been written yesterday. I start each new scenery feature by first reshaping the existing code into the most useful form for what we want to have in the future, and then coding the new feature is relatively simple.
But this strategy has an Achilles heal; if the code being refactored has a public interface (whether it is a file format or programming API), then all of the intermediate steps in the journey become requirements for future products in order to maintain backward compatibility.
This is not a problem as long as the programmer knows where he is going. The danger comes when one of the intermediate steps is actually a step in the wrong direction, and becomes dead weight around a future design.
A Reasonable Progression: OBJ
The OBJ 800 file format has had a reasonable progression* since its birth in version 8. It has gained a number of new features, but each one has generalized and made more powerful previous ideas, such that “legacy behaviors” are not so painful. Some examples:
- Hard surfaces may now be decks (e.g. you can fly under them) or not, and you can specify what kind of hard surface you have. The original hard surface command was simply “it’s hard” or “it’s not”. But viewed under the lense of the new scenery system, that old hard surface command implicitly implied “the surface is smooth” and “the hard surface is not a deck”. So the new hard surface command is a more general version of the old one, which continues to work under the new system.
- Animations in version 9 can be key framed; in version 8 you simply specify start and end values. But start and end values are just like having two key frames. So viewed under the lense of the new scenery system, all animations are key framed; older objects always just have two key frames. The new key framed commands are a more powerful, more general version of the old ones.
I can’t say that the relatively pain-free evolution of OBJ files over the last 4 years comes from good design or genius on my part – in truth it’s probably just good luck. But I think one thing has helped me keep the new OBJ extensions relatively sane: most of them are conceived several months before they make it into X-Plane.
I have a scenery system to-do list that will last me at least another four years; most of it is filled with things that Sergio has asked for. This to-do list acts as sort of a road map for future scenery system extensions; for any possible OBJ change, I can look at it relative to the other todo items and ask: “is this extension going to play nicely with things to come?”
(As a side note, this is one of the reasons why there are not light maps in any of the X-Plane modeling formats. Light maps don’t play well with a number of other scenery system extensions. I want to resolve the conflict between these future additions before they go into the sim.)
Wandering In the Desert
By comparison, the evolution of the panel system in version 9 has been more like wandering in the desert than a straight line toward a goal. Repeatedly, I put features into the panel system without a clear roadmap of where we would end up or how they would work together. The result is what you see now when looking over the panel documents: complexity and chaos.
Basically there are several major changes to the panel system that affect each other in strange ways:
- A more complex lighting model on the 2-d panel in version 920. (That is, the 3 2-d spot lights, and generic instruments with back-lit, mechanical, or glass lighting.)
- A more complex lighting model in the 3-d cockpit in version 930. (That is, 3-d spot lights, ATTR_cocpkit_region and generic instruments with back-lit, mechanical, or glass lighting.)
- A separate panel used only to provide texture to the 3-d cockpit. (That is, the 3-d panel.)
The problem is the order that they were invented: first ATTR_cockpit_region, then the 3-d cockpit, then back-lit generic instruments, then 2-d spot lights, and then 3-d spot lights.
The result is two sources of confusion:
- Some combinations of features simply don’t work together. Since all of the features appear to be independent, I sometimes get bug reports on these. For example, you can’t use the 2-d spot lights on the 3-d panel. This is not a bug, it is by design! I will explain why some of these limits exist in future blog posts.
- Among the remaining combinations that do work together, there are a lot of choices about how to structure a plane – too many choices!
This second point is a tricky one: X-Plane has to continue to support whatever set of features was available for any given release (864, 900, 920, 930) so that older planes continue to work. But some of those combinations (e.g. the ones that exist in version 900) don’t make a lot of sense for new planes made in 930.
I am open to ideas on how to solve this. I intend to document a “correct formula” for a modern plane, perhaps with tutorials, on the Wiki. I am also considering programming Plane-Maker to flag unusual combinations of features as a warning when saving 930 planes.
Either way, I fear I’ve learned my lesson from the panel system: incremental improvement of code is only a good idea if the programmer knows where he is going! Next time I will use Google Maps. 🙂
* I suppose that whether you think the OBJ 800’s evolution has been reasonable depends on your standards for file formats. OBJ 800 absolutely does show growing pains. I would only say: consider the number of revisions and the change in the hardware platform OBJ 800 feeds when you consider its stretch marks.
I have found the cause of a rather serious bug in Plane-Maker: sometimes instruments disappear from the hierarchy (but are still visible in the main window).
The problem is that the cut-paste facility, when used with multiple-instrument selections, was corrupting the hierarchy information. Because of the way instrument hierarchies are managed, this corruption persists – even if it isn’t visible. So if you manage to ungroup everything, it looks okay until you work more, then the instruments disappear again!
This is a really bad bug of mine, particularly since a panel is such a time investment. Here is what we’ll be able to do in 930 to get around this:
- A new “flatten panel” command simply ungroups everything and completely cleans the hierarchy. All corruption of hierarchy is fixed with this command, finally exposing every instrument. From that point on, you can then re-group and things should be okay.
- I am fixing the cut-paste commands to not trash the hierarchy, and I am looking for any more hierarchy-corruption problems.
- 930 has export/import of instrument groups to text files. So another way around instrument corruption problems would be to export the panel to a text file, fix the grouping problems (which is a matter of moving the GROUP/END_GROUP lines) and then re-importing. If you do not have a selection, the entire panel is exported, including any hidden items in the hierarchy.
I believe that text-based panel import/export will also be useful for sharing individual instruments (or clusters of grouped generic instruments), archiving work, and making large-scale changes using search-and-replace.
These two issues have been discussed a lot in the forums, so I thought I’d mention them:
First, I finally found and nuked that star-burst pattern in the rain. It turns out that for some textures, compression was destroying the lower res mip-maps
, causing the geometry that the rain drops are drawn on to show up as that starburst pattern. It should be fixed for 930 beta 1.
Second, it turns out that the code that converts the 900-format generic instruments to 920-format generic instruments* was being run on the user’s airplane whenever a multiplayer airplane older than version 920 was being run. That could cause generic instruments to disappear, appear incorrectly, or just crash the sim, because the aircraft data in the user’s plane (once the user is flying) is already in 920 format…if you interpret it as 900 format again, you get non-sense.
I am fixing this for 930 beta 1; there may be other bugs relating to multiplayer and generics, so we’ll see if this fixes most of the problems, or others crop up. The panel system is essentially “global” (that is, there is one panel for the user in all of x-plane) but the instrument data is per-plane…so there is always a risk of code mistakes where the multiplayer planes affect the user’s panel.
When will 930 beta 1 be out? I don’t know. Hopefully pretty soon – when bug fixes make it into the blog, we’re usually in the push to get to beta. But I’m working on features on a few fronts, so it’s hard to say which ones will be done first.
* X-Plane 920 revised the ACF format from version 900. The file format for generic instruments was pretty much completely changed to accommodate new features like key frames. 920 has code that converts the 900 generic instruments into 920. For example, simple key frame tables are built out of the older offset-scale parameters per instrument.
The X-Plane export plugin for AC3D doesn’t handle panel textures very well. The current plugin tries to identify cases where you have used your panel background as a texture – this queues it to generate ATTR_cockpit. This scheme has a number of problems:
- The search paths for the panel background are not up-to-date. The plugin doesn’t know about the new naming conventions or the cockpit_3d folder.
- The scheme doesn’t address panel regions at all – there is some support for them but it doesn’t work well.
- Most important: panel editing is not WYSIWYG. Since you are using the panel background as your texture, you can’t actually see where all the moving parts are! Doh!
That last point is perhaps the most important one, and it is why, for the next version of the plugin, I am introducing panel previews.
Basically a panel preview is a screenshot of your panel with the instruments on it, sitting in your cockpit_3d/-PANELS- folder. AC3D will recognize and use the panel preview when possible. This will solve problems (1) and (3) – there will be only one naming convention for previews, and they will be screenshots of the panel in action, so you can texture with a preview of the instruments.
Plane-Maker 930 will contain a facility to generate panel previews; if you are using X-Plane 920, you can generate the preview manually by taking a screenshot in X-Plane.
For panel regions, we will have one preview file for each region (e.g. Panel_preview0.png, panel_preview1.png). This addresses issue 2 – usage of the region previews will invoke ATTR_cockpit_region.
Finally, I am moving the panel sub-region information from the preferences to the .ac file (hopefully) so that it will be saved with your plane.
Hopefully this will make a work-flow which is much simpler. To make a 3-d cockpit you will simply pick “generate previews” in Plane-Maker, and then start using the previews as textures.
I have blogged about this before, but I will try to create one simple explanation of what’s going on with sim/cockpit2 and sim/flightmodel2 datarefs.
Sandy and I (with the help of others who helped compile the list) created “new” datarefs (first released with X-Plane 9) , aimed at airplane modelers. These new sections are:
- sim/cockpit2/ which provides a new set of datarefs for cockpit modeling via OBJ animation and generic instruments.
- sim/flightmodel2/ which provides a new set of datarefs for airplane exterior modeling via OBJ animation.
These datarefs sometimes include new data that was not available in version 8, and sometimes they simply provide a second dataref with the same information. Why duplicate datarefs? The new datarefs have some special properties, so I wanted to have a complete set of datarefs for modelers with these new properties.
Skip to the end for the rules of thumb on how to use them.
The new datarefs are designed to have longer, less confusing names; the old datarefs contained a lot of abbreviations – potentially acceptable for programmers (who are used to seeing things like fstat and chgrp on a regular basis) but not good for modelers who do not speek English as a first language. The new datarefs have long names and are more consistent in their conventions. They also contain complete documentation.
You will see the array dimension of some of the new datarefs as symbolic constants, e.g. [engine] instead of . This is because the dataref generation system we use knows that these new datarefs sometimes track the maximum number of parts in the aircraft structure. This tagging means that it is much simpler for Sandy and I to adjust the datarefs when Austin increases part maximums.
With the old datarefs, if Austin allows for 10 engines, Sandy and I must search for every  dataref and decide if it must be  – some will be per-engine and need to change, some will be per-battery and will not! With the new system, we simply redefine the “engine” constant to 10 and the datarefs adjust.
(Note that if your plugin really needs to run dynamically with any number of engines, the best thing to do is to read the array size using XPLMGetDatavX.)
There are two ways to view a dataref: before system failures (such that the dataref reflects simulated physical reality) and after system failures (such that the dataref reflects pilot indications). For example, when the pitot tube ices up, the pre-failure airspeed reflects how fast you are flying; the post-failure airspeed reflects how much crud is in your pitot tube.
Pre-failure datarefs are appropriate for animating the exterior of the airplane. For example, if the gear indicator light fails but the gear is working, you want to animate your landing gear based on the real (pre-failure) gear position, so that the gear really does look like it’s down from an outside view.
Post-failure datarefs are appropriate for animating the cockpit. For example, you want to use that post-failure indicated airspeed for your air speed indicator, so that pitot ice will affect your generic instruments and animations, as well as the built-in instruments.
The new datarefs are designed to clearly provide two different views:
- sim/cockpit2/ are all post-failure whenever possible, and are thus appropriate for cockpit modeling.
- sim/flightmodel2/ are all pre-failure, and thus are appropriate for external airplane modeling.
Be careful not to swap them! You should always be using sim/flightmodel2/ for your aircraft and sim/cockpit2/ for your cockpit. If the dataref you need is in one and not the other, email me and I will add it to the right place.
Correct Multiplayer Behavior
The older datarefs all return data about the user’s airplane. However if you build an object, attached to an ACF, and that ACF is loaded for a multiplayer plane, you will get incorrect results — the user will see his own plane’s actions visualized on the multiplayer plane.
The new sim/cockpit2/ and sim/flightmodel2/ datarefs handle this case correctly: they return data about whichever airplane is being drawn. Thus if your object is attached to airplane number 5 in a multiplayer session, that’s the airplane that will animate your control surfaces.
(Plugin developers – outside airplane drawing, these datarefs return information about the user’s flight.)
For this reason, you should always use sim/cockpit2/ and sim/flightmodel2/ – not the older sim/cockpit and sim/flightmodel/ datarefs. If the dataref you want is only in the old sections but not the new ones, email me!
What Dataref Do I Use?
Here’s the rule of thumb:
- If you are targeting X-Plane 6/7/8, you must use sim/cockpit and sim/flightmodel, otherwise
- If you are targeting X-Plane 9, use sim/cockpit2 for your generic instruments and 3-d cockpit. Use sim/flightmodel2 for your attached objects.
That’s all there is to it!