In a previous post I noted that we weren’t attempting dynamic ambient occlusion inside the 3-d cockpit, due to problems of quality, availability, and because it wasn’t really better than what authors do now: prepare the AO offline using a high quality render in their 3-d modeler.
I’ve been thinking about this a while: while I like to get up on my soap box and shout that X-Plane is not like a first person shooter any time we get compared to a AAA console title, there is one case where X-Plane kind of is like one: inside the user’s aircraft.
First person shooters often specialize in rendering highly controlled, closed, constrained, claustrophobic environments in ludicrous detail at very high framerate. To achieve this, they take advantage of optimizations specific to those closed, controlled environments: lots of things are pre-computed, pre-baked, and pre-calculated.
X-Plane’s scenery engine mostly focuses on throughput; once you climb through 500 feet you can see everything at an airport, so we just try to draw really fast. But the inside of the aircraft is different. Baking at least part of the interior lighting is pretty much a standard practice. We provide object-kill datarefs to let authors script their own culling algorithms to squeeze framerate out of a confined space.* We define sound spaces within the aircraft that can change how sound effects are filtered.** We let you mark which parts of your aircraft receive interior and exterior light. (This feature is called “light groups” in a regular 3-d game engine and it’s very common, particularly in older forward-rendering engines.)
All of this stuff is a lot more like a game with a 3-d level editor than the rest of X-Plane. Techniques that focus on interior spaces are a good fit inside an airliner.
Better Baking: one of the features planned for our next-generation modeling format is to allow multiple UV maps for a given model***. We can then add an ambient-occlusion texture to an object’s shader and you can bake your aircraft interiors at a much lower resolution than you albedo textures.
For example, you could use a high-res repeating texture to draw the seats inside the aircraft, copy-paste the seat down the cabin, and then unwrap a second UV map that covers the entire cabin uniquely. Bake to this second UV map, down-size the texture to super low res (it’s ambient occlusion, “soft” is okay) and you’ll get high-res detail with unique correct lighting queues all over the aircraft. This is a standard work-flow for 3-d game engines and seems like a good fit for aircraft interior.
Edit in the Sim: we can take another clue from game engines and provide editing of graphical aircraft information inside X-Plane. We already do this for the particle system – the editor is built into the sim itself.**** The advantage of editing in the sim is that you can see your work exactly how it will look in real time.
* Engines that focus on interior spaces often have techniques like portal culling built-in and tools to precompute the information for this culling automatically.
** This is part of the new FMOD SDK – we will get this documented around or shortly after 11.0 goes final.
*** I realize this isn’t very “next-gen” in the world of rendering engines – it’s just the next major modeling revision for X-Plane.
**** The particle system isn’t documented because it isn’t quite finished yet. It’s shipping in mobile, enabled on desktop, but it is not running the default effects right now.
This has been a point of confusion for third party developers, particularly ones who were in the private beta (and saw versions of the sim that…cough cough…didn’t work right).
Screen space ambient occlusion (SSAO)*, when enabled by the highest rendering settings, only affects exterior objects. This means scenery and aircraft-attached objects marked “exterior” for lighting.
I tried SSAO in the cockpit interior, and it had a few problems:
- The scale for occlusion in the interior and exterior of the cockpits is really different – I couldn’t find one size for the effect that fit all cases.**
- When I went to apply the effect to our fleet, I found that virtually all of our aircraft already had occlusion baked into the cockpit by the artists. The dynamic AO thus provided almost no value and made the cockpit even darker than it already was.***
- SSAO only works at the highest rendering settings (and requires HDR to function at all), so if artists remove their baked AO, they’re taking a pretty big visual loss in a bunch of settings.
So in net, it just wasn’t worth going to dynamic AO in the cockpit. Our AO isn’t as high quality as what you can bake in a 3-d program (given a few days of rendering time), and it’s not always available.
The real win for SSAO is outside the aircraft, e.g. to cast AO around the wheels of the aircraft on the ground. That’s an effect that you can’t bake, and it helps a lot with lego brick scenery too.
* Nerd note: I’m pretty sure that what we do is actually HBAO
** We could, in theory, apply the effect twice with stenciling at two different scales.
*** The cockpit tends to be dark both due to errors in our approximation for indirect light (because most of the cockpit is in shadow, and thus only lit by indirect light) but also because cockpits are actually pretty dark compared to the great outdoors. But that’s another post.
I’m going to keep going with “random stuff I looked at today” and see if there’s something for authors mixed in.
I spent part of today measuring shader and texture changes in our engine under heavy load – my goal was to get a sense of how much data we’d be pushing through a next-gen API (e.g. Vulkan, Metal, DX12) if we just did a straight port of the engine. This was just a fact finding mission.
The only problem was: the numbers were just absolutely awful. Terrible. Unusable!
Then I noticed the other thing: the entire area of KSEA was littered with thousands of Fed-Ex trucks. Just tons and tons of them! Only Fed-Ex trucks on the road, and only Fed-Ex trucks parked on the street.
Leftovers For Lunch
The Fed-Ex trucks were a left-over. I do this to myself all the time: I create a dumb custom scenery pack to test some part of the sim and then forget to remove it from my working X-Plane folder.
Before X-Plane 1040 there was a bug where cars and trucks on the road could crash the sim if you viewed them across a DSF tile boundary and the 3-d models were not instanced. This last point is why the bug went unfixed for so long; the car set we ship with is entirely instanced for performance.
So I built a library with a Fed-Ex truck that was intentionally not instanced to reproduce the bug and forgot about it. The custom scenery pack was why my traffic looked silly, and the non-instanced traffic was why my stats showed the rendering engine doing 4x more on the CPU work than it was supposed to.
(Since X-Plane was in debug mode, the framerate was expected to be terrible due to unoptimized code and debug checks running on an old laptop with the scenery cranked to the max.)
So there’s a take-away here and it is:
OBJs in a Custom Vehicle Pack Should Be Instancing-Friendly
There are a few custom vehicle packs for X-Plane floating around the web, and the quality of the objects with regards to performance is mixed and overall not very good – probably some of these packs pre-date X-Plane 10.
Instancing is the ability for X-Plane to draw more than one OBJ in a single instruction to the GPU. We implement instancing by observing your OBJ as we load it and noting whether the OBJ contains anything complicated (dataref usage, animation, lots of material changes) or if it is more or less just a big pile of triangles.
If we have the latter case, then we mark the object as instancing friendly, and when it is drawn, all objects of that type are collected and drawn at once. The instancing code path in X-Plane is thus separate and much faster for both X-Plane itself and the driver.
Since you can have a lot of the same car on the roads, even with a varied collection, it’s worth it to be instanced!
How to Tell If Your Object Is Instance-Friendly
To see if your object is instancing friendly:
- Make a custom scenery pack and place ten of the objects very close to each other (e.g. at an airport).
- Load the airport in X-Plane and in DRE set the art control “terrain/kill_clusters” to 1.
When you do this, all of the instanced objects that come from DSFs will disappear, and all of the non-instanced ones will remain.
Your object will be instance-friendly if:
- It uses no animations
- It uses no ATTRibutes mid-object – use the new GLOBAL properties instead
- For cars, LOD is okay (but non-additive LOD will make the WED test fail). For cars you should only use one LOD anyway.
- Only some named lights are instancing friendly; fortunately the headlight/taillight ones are.
Draped geometry is instancing-friendly, but don’t use it for vehicles.
In the new Blender 2.7 exporter (and our branch of the Blender 2.49 exporter) instancing is made quite easy: you mark an object as “instanced” and one of two things will happen:
- Blender will write only stuff that is instancing friendly or
- The export will fail with an error telling you what you did wrong.
Thus when you -need- something to be instanced (scenery objects, etc.) you just tell the exporter to enforce it.
Here are some things where instancing really matters:
- Repeated buildings in autogen.
- Static aircraft that repeat a lot.
- “Clutter” on the ramp (baggage trucks, etc.).
- 3-d modeled vegetation that gets repeated.
- Cars (both parked and moving)
Here are some cases where it does not matter:
- Aircraft-attached objects. Since aircraft attached objects aren’t usually repeated and almost always have a lot of complicated stuff, instancing doesn’t matter or work here. Instancing is really for scenery.
- Single extremely complicated objects like the Nimitz.
Right now objects drawn with the XPLMDrawObjects API call do not benefit from instancing, but this is probably something that will change in the future, as long as every “instance” is fed through a single XPLMDrawObjects call.
I mentioned in a previous post that we are working with Ondrej on a next-generation Blender 2.7 OBJ exporter. I am excited for this work because I believe it will greatly improve the artist interface to X-Plane. Let’s use instancing as an example to explain the idea.
X-Plane 10 will sometimes draw scenery objects using hardware instancing. When an object is drawn with instancing, performance is a lot better than without it; the huge numbers of objects you can see in the autogen scenery are due to instancing. But the conditions for instancing are, to put it mildly, complicated.
- The object has to be attached to a DSF. Well, that’s not crazy.
- There’s a giant pile of things you’re not allowed to do in an instanced object – animation, material attributes, smoke puffs, bla bla bla. (The object has to be simple so that the GPU can draw a big pile of objects without the CPU intervening to handle things like smoke generation on a per-object basis.)
- Buuuuut…not every ATTRibute is a problem. You can use ATTR_hard in an instanced object, no problem! But don’t use ATTR_shiny_rat – that’ll kill instancing.
- But wait, there are these weirdo new attributes like GLOBAL_specular that seem to replace ATTR_shiny_rat that do work with instancing.
If you model, and this seems confusing, it’s because it is. You were never supposed to see this!
File Formats for Machines and Applications For Humans
My view is this: the file formats of X-Plane are meant to be seen by programmers, not artists. When was the last time you had to hand-edit an .acf? You just use Plane-Maker. You don’t hand-edit a PNG file or worry about its internal compression – you use PhotoShop.
OBJ should be the same way – you should export from a 3-d tool and never have to look inside the OBJ itself. This means the OBJ8 format can serve two purposes:
- Help X-Plane load models quickly and draw good looking content and
- Maintain compatibility so older scenery continues to load.
Note that “be really easy to understand in Notepad” is not on the list!
Blender the Transformer
Now here’s the trick: the rules for OBJ that a 3-d modeler can present can be different from the rules that the OBJ8 format itself has. And that is exactly what we are trying to do in the new Blender exporter.
Rather than expose global attributes and non-global attributes and all of the crazy complexity of OBJ8, our strategy with the new exporter is this:
- When you export a scenery object, you specify if you want the object to be instanced or not.
- If the object is not instanced, Blender creates the best OBJ it can for this case.
- If the object is instanced, Blender tries to create the best OBJ it can for this case.
- If the object is supposed to be instanced but you’ve done something that is not instancing-friendly, the exporter tells you, in terms you can understand.
So for example, if you make an animated radar dish that spins and attempt to export with instancing, the exporter can say “you cannot have animation in an instanced object.” Now you, the scenery designer, can make a decision: is it more important to have the radar dish draw really really fast, or is it more important that it spins?
This is the strategy we used for our modifications of Marginal’s 2.49 exporter* – the artist specifies instancing and gets a check that instancing requirements have met. This means instance-tagged objects will be fast. (It is possible to check instancing within the sim with DataRefEditor but it’s not easy, especially for large projects.)
Don’t Expose the Weird
This idea that Blender can transform your work, and thus hide weird X-Plane rules, is not specific to OBJ, not new to X-Plane, and not even specific to X-Plane. When you look at major 3-d game engines (e.g. for combat games and racing games) a ton of code goes into the “art asset pipeline”, transforming the artist’s original work into something already digested for the 3-d engine.
Another example of this is WED. DSFs have an annoying rule that polygons can’t cross DSF boundaries. There are also some even weirder exceptions for a few special cases, introduced in X-Plane 10.20.
WED knows all of these rules; you draw polygons wherever you want and set the export target for the version of X-Plane you want to fly in, and WED figures out the best way to export your work, chopping up polygons as needed.
Shedding Light on Things
Our current work on the Blender exporter focuses on WYSIWYG animation and the material model (which includes instancing support). There is one more area that I think will make a huge difference to authors that we haven’t started working on yet: lighting.
The lighting values for commands like LIGHT_PARAM are, to put it mildly, completely goofy. If you’ve ever tried to read this, you know that even when things are explained, they make no sense.
No author should ever have to write a LIGHT_PARAM. This is a classic case where the exporter should do the transformation for us. What I would like to get into Blender 2.7 is the ability to place a cone light in Blender and have the exporter write the spill light automatically, e.g. filling in the parameters from the position and shape of the light. You light your scene and you see the same thing in X-Plane.
For years we’ve been behind the curve on user experience when it comes to 3-d modeling. I think we’re starting to fix some of those problems in a major way, which should help make the power of X-Plane 10’s rendering engine quite a bit more accessible.
*As a side note, I have no idea what the current 2.49 script status is. We view the 2.7 scripts as the long term way forward, due to Blender 2.49’s not being maintained, so our effort on a truly user-friendly tool is going into 2.7. But we also maintain updates to 2.49 to support our internal team. X-Plane 10.50 will feature a few new OBJ commands, so I will try to post our branch of the 2.49 scripts (which do have this new support) for anyone whose aircraft is in 2.49.
In the long term the 2.7 scripts will feature a migration tool, but I expect we will have a useful 2.7 release (for 2.7 authors) without migration first, and then migration will come later.
Update: the comments form is fixed – sorry about that!
I’ve been working a bit on scenery tools this week. Here’s a road map of some of what’s coming up.
WED and the X-Plane Scenery Gateway
We are working on a release of the latest scenery gateway airports for X-Plane 10.45. Like all releases, we’ve found problems with airports that WED does not detect. So I will try to release a new version of WED with stricter validation soon.
Airport Parking Spots
Austin is working on new code to place static aircraft at unused ramp parking spots. I’l describe this in more detail in another post, but here are some key points:
- As an airport author, you simply place ramp starts, not static aircraft.
- X-Plane will feature some new static aircraft in the update.
- Third parties can further add to the static aircraft and have them be used via the library system.
- There will be a revision to the apt.dat format that stores more data per ramp spot and a WED update to support this new data.
- Since there may be scenery now with static aircraft on top of ramp starts*, we will auto-remove static aircraft from ramp starts in the gateway export as a temporary measure until authors can resolve the situation and post the fixes to the gateway.
- We are not removing the old static aircraft from the library, but we will be hiding them from WED’s library so that authors use ramp starts instead of placing them by hand.
Static aircraft in parking spots will ship next year, not this year, but is planned as a v10 update.
Scenery Tools on OS X
I made significant progress this week porting WED for OS X to 64-bit and modern Mac APIs. This effort basically meant rewriting the OS-level UI code in WED to be new AppKit based calls instead of the old Carbon API.
What this means is that developers will be able to build all of the scenery tools on a modern Mac running Yosemite or El Capitan with X-Code 7. Since Chris has already updated the projects to compiled WED in MSVC, a developer can build all of the common scenery tools from the most widely used open source IDEs.
It also brings us closer to a 64-bit WED on Mac, which is desperately needed since OS X provides the least amount of usable address space to 32-bit apps. I am not sure of the 64-bit status of the Windows WED build; it may need more work on the libraries.
Will It Blend
This might be the most significant scenery tools development: we’ve been working with Ondrej (der-On on Git-Hub) on new features for the Blender 2.7 exporter. This will include:
- Much better animation support. Complete WYSIWYG animation of data blocks and bones, with no work-arounds needed. Bone animations match Blender 2.49 so you can move your projects forward.
- Modernized material support including instancing for a really clean work-flow that takes advantage of X-Plane 10’s features.
- Updates for the latest OBJ features.
- Our plan is to create a migration script to bring 2.49 projects into 2.7, converting the special tags used for an X-Plane 2.49 export into 2.7.
Many of our artists still use 2.49, but there’s no question that 2.49’s days are numbered. It’s a question of when it stops working on OS X, not if. With the migration step, we can move our projects forward without artists having to redo work.
Like the previous 2.7 exporter, this one is open source and will be free, and should be able to export existing 2.7-type projects with no modifications – we are trying to maintain full backward compatibility.
* This situation is slightly silly – if the user picks the ramp start to fly, the user will be on top of a static aircraft.
That got your attention, eh? Sorry, this is not a tip on how to tune your X-Plane system; it’s a tip for aircraft authors to make sure their 3-d cockpits are running at maximum performance.
Prefill is when X-Plane blocks out the clouds that will be behind the airplane cockpit. The biggest cause of GPU slow-down is cloud rendering, so reducing the area that the clouds have to fill is really important.
In the 2-d cockpit, X-Plane pre-fills automatically. But in a 3-d cockpit, the airplane author has to specify which objects should be used to pre-fill.
Aircraft Authors: go watch this video or read this page to learn how to set up pre-fill in your aircraft! If you aircraft has a 3-d cockpit this optimization is very important!
If you are creating an airplane or scenery pack and you need to create a fully customized spill light (visible in HDR mode only in v10) there are two ways to do it.
First, we have a parameterized light called “full_custom_halo” that takes nine parameters, e.g.
LIGHT_PARAM full_custom_halo 0 20 0 1 0.5 0.5 1 50 0 -1 0 0.5
(Phew!) The first 3 numbers 0,20, are the XYZ position (this light is 20 meters above our object origin). The next four are the RGBA color (100% red, 50% yellow, 50% green, 100% brightness*), so it’s a very light red. RGB colors for spills are in linear space, so you’ll have to experiment to get your colors perfect. The size is 50 meters (a huge light throw), and it points in the direction 0, -1, 0 (straight down). 0.5 is the “semi-width” of the cone – 60 degrees in this case. Basically cosine(cone width * 0.5) gives you this width parameter, or pass 1.0 for an omnidirectional light.
This light is on all the time – use full_custom_halo_night for the night version.
There’s a second option: OBJ files have a custom spill command:
LIGHT_SPILL_CUSTOM 0 20 0 1 0.5 0.5 1 50 0 -1 0 0.5 your/dataref/here
The position and 9 light parameters all have the same meanings, but in this case you get to provide a dataref. The dataref must be a float-array dataref of size 9; when your dataref callback is called, the array is pre-initialized to the 9 params, and you can change them at will. With this dataref, your plugin can change the light parameters in real-time.
Which technique should you use?
- Use LIGHT_SPILL_CUSTOM if you need the dataref to do clever customization.
- Use the PARAM_LIGHT with the nine params if you don’t need the dataref.
For scenery the param-light version may be notably faster when used many times in an object. So if you’re building a light used a lot (a streetlight, a taxiway light, an airport lighting fixture) you really want that param version.
Update: this was not documented at the time, but if you are using datarefs with LIGHT_CUSTOM_SPILL, the dataref format does not match the OBJ8 format. This page now documents the right format for plugin objects!
* The mathematically minded will note that there is no need to have an alpha on lights because they are additive. This is true – just set alpha to 1.0 and use darker colors!
Edit: Normally I label the overly technical posts as being for a target audience, but I did not this time. My bad — this post is really only of interest (and will only make sense) to serious 3-d modelers – the advanced airplane and scenery nerds!
The brightness of specular hilights is out of sync between HDR and non-HDR mode in X-Plane 10.11. This wasn’t intentional – it’s a bug. 10.20 will fix this; specualr hilights will have the brightness you see in non-HDR mode (which we think is more like they were supposed to work*) but the tinting of HDR mode (non-HDR mode was overly red in 10.11).
I get a lot of requests for ‘hardness’ control – that is, the exponent that controls how wide a specular hilight is. We’ll get this feature eventually – it’s too important to ignore. The main delay in having this feature is that X-Plane uses a deferred renderer, so the specular exponent has to be stored in the G-Buffer somewhere, and storage is tight.
For similar reasons, it is very very unlikely that we’ll ever have RGB tinting of specular hilights. Doing so is 3x as expensive in G-Buffer storage, and we need that storage for other features.
* That is, unless we discover that non-HDR mode looks spectacularly bad in some cases, in which case we may have to push things a little more toward how HDR was.
We have received a number of bug reports on the livery system in X-Plane 10, as well as complaints from both users and authors about how the system works. This post describes what I am thinking for liveries; if this proposal seems hair-brained, the comments section would be a good place to counter-propose.
Two notes on UI discussion before we jump into the details:
- We hate check-boxes. If the UI debate is “which is better, UI A or B”, then the answer is pretty much never “let the user pick A or B with a check-box”, because the point of UI is to present the program in a human-friendly manner. Having two different UIs with selection forces the user to become the UI designer, which is inherently harder. So while we don’t have zero check-boxes in our UI, we really try to keep the ‘have it your way’ stuff to a minimum; X-Plane is a product for sophisticated users and if we put in a check-box every time we get a request for one, the product would be absolutely unusable.
- In arguing for UI, describe what you want to do, not how you want to do it. If you describe an implementation but we can’t do the implementation, the discussion is over. If you describe what you want to do, we can find several implementations and pick the best one.
As of X-Plane 10.11, you can:
- Select your livery when you open a plane using Open Aircraft…
But you cannot:
- Change the livery without reloading the airplane, mid-flight.*
- Select your livery from the Quick Flight dialog box.
- Change your livery quickly (since a plane reload is slow).
- Change which livery the QF dialog box picks for you – it always pick “no livery” (that is, default paint).
These first two bugs go hand-in-hand. Because you have to reload the plane to change liveries, you lose the initialization that Quick Flight may have done for you.
* There is one bug to note: if you go to the open aircraft dialog box, select a different livery and hit cancel, X-Plane will change your livery on the fly but not reload the plane. Some users have noticed this and use it as a back-door way to change livery mid-flight.
For the short term, I am converting the bug in the Open Aircraft dialog box into a feature – the dialog box will have a “change livery and keep flying” button to change your livery on the fly, and the “cancel” button will not unexpectedly change your livery. Thus the functionality of the old “open livery…” v9 functionality will be part of “Open Aircraft.”
This isn’t perfect, but it at least addresses the issues of changing liveries quickly, or changing them while flying, without having to know about and use a hidden UI bug.
For the Future
There are more features we’d like to do in the future:
- Have a dedicated livery-change UI again – perhaps one that ‘floats’ over the main window while you fly, so that you can see the liveries as you click on them. This would be a quicker way to rapidly preview a large number of liveries.
- Remember the last user selected livery in the per-aircraft preferences (along with quick-look keys) so that if you go to open an aircraft and don’t do anything else, we can pick the last livery you used.
- Someday have ‘drill down’ functionality in the Quick Flight window so that you can set more detailed info about your plane (livery, weight and balance, fuel, weapons) and then go back to the main QuickFlight window. This is a long ways off though.
None of this is going to make it into 10.20 – I mention it only to explain where we’re trying to go – the change for 10.20 are designed to not interfere with this future work. The future work is all based on user selected livery choice, with preferences an easy selection.
Livery Choice in Plane-Maker
This finally brings me to livery choice in Plane-Maker. I have always considered this a bit of a weird feature; it is inoperative in 10.20 and we are looking to get rid of it permanently – that is, setting a livery in Plane-Maker has no use in any of the above plans. Our view:
- The first livery you see if you first open a plane for the very first time in QuickFlight will be the default one.
- Preferences should record the users choice of livery, and this should be done entirely from X-Plane. It should not be necessary to open Plane-Maker to change livery preferences, any more than Plane-Maker is needed to change rendering settings or joystick preferences. User customization should be 100% in-X-Plane.
As I said before in the top of this article, if this seems half-baked to you, please describe what you want to do, not how you want to do it. And please understand that when it comes to UI, less is more; we need to identify a small, highly leveragable set of UI options to cover a wide variety of features. We don’t want to have 6 ways to do everything!
This rather odd 747 picture is from a quick test I did to make sure the shadow options in Plane-Maker were working right after beating the shadow code silly with a hammer. The wing objects have been marked “interior only” for shadows, and since we are in an exterior view…the wings don’t cast shadows. 🙂
Now this is a totally silly way to use the feature, but there is a legitimate use: mark as many of your interior objects as “inside shadow only” as possible; for example, in the 747 the interior passenger cabin object can be marked as interior only – it doesn’t cast meaningful shadows on anything outside the airport.
By marking an object as no-shadow in Plane-Maker you save the sim the work of drawing the object, which is good for fps. If your airplane is used for an AI plane, this makes AI plane drawing less expensive.
In fact, you save it the work of drawing it multiple times. X-Plane using a shadowing technique called “cascading shadow maps”. Basically X-Plane renders different parts of the world at different resolutions, so that the closer shadows (that can be seen in more detail on screen) have a higher resolution. The user’s plane ends up being drawn in a lot of these rendering passes, and as a result the cost of high-geometry-count objects in an airplane can be amplified several times over by shadows. So savings in object-shadow count matter!
(Given the choice of turning off shadows in Plane-Maker or via GLOBAL_no_shadow, use Plane-Maker; it stops drawing earlier and thus saves more CPU.)