Captain Peter Hager for sending me his A340 as a nice test case for texture compression. Peter (like many aircraft authors) has never been very happy with the artifacts introduced by DXT compression.
First the basics: DXT1-5 are a series of texture compression formats. They store the same number of pixels in a smaller number of bytes via clever encodings of the pixels.
When your image has no alpha channel, the savings from DXT1 compression are 8:1. (Modern graphics cards store RGB images in 32 bits for alignment, so the 4-bits-per-pixel DXT encoding is an 8:1 savings, not the 6:1 you’d expect on paper.) RGBA images take 8 bits per pixel, for a 4:1 savings. That’s as much as reducing the image size by a factor of 2 in each dimension.
DDS is an image format that contains a compressed image. DDS files load faster (because the image is already compressed), look better (because the image is compressed using a slower, higher quality process before sim load) and let you pick the DXT algorithm choice. (In some cases, the choice between DXT3 or DXT5 matters!) However, once an image is compressed into a DDS file, the pixels lost in compression never come back – DXT is a lossy compression format! (This is just like saving a JPG as a PNG – if the JPG quality was too low, the PNG will contain the same blocky artifacts that the JPG had.)
Compression is useful for more than just saving VRAM – because the amount of data needed to texture a given pixel is smaller (4 bits per pixel instead of 32) compressed textures can speed up framerate if the memory bus between the GPU and its own VRAM is congested.
Now let’s look at some pictures.
This is the Swiss Air livery at extreme res, uncompressed, sourced from a PNG. This is our reference image for how good the original image can look before we start trading off quality for VRAM.
This is the same image, extreme res, texture compression on, sourced from a PNG. It just looks awful. The graphics card has done the compression, and it has done a fast job, not a high quality job. (In the driver’s defense, X-Plane asks for a fast compression rather than a high quality one to avoid slowing the sim down.)
This is also compressed!!! But in this case the livery was pre-compressed using XGrinder/DDSTool (which in turn uses libSquish). DDSTool sets libsquish for maximum quality and then takes quite a while to grind each texture, but the results are better use of those compressed bits. (DXT is a lossy compression, so more compute time can find a better use of the finite quality available in the compressed texture.)
Finally, this is the uncompressed texture at “very high” res – that is, taken down one resolution level. Compare this image to the compressed one above. For an alpha-blended texture, the trade-off is one “size” increment (2x smaller on both sides for 4x VRAM savings) vs. compression. I submit that the compressed version is a better way to save VRAM than down-sizing.
Have Your Cake and Eat It in X-Plane 10
In X-Plane 9 you had to make a trade-off: ship a compressed image in a DDS file and have the very best look be extreme res compressed or ship a PNG file, and have the texture look terrible when texture compression is on. You can see from the above images what the options looked like.
In X-Plane 10 you can do both. If you ship a DDS and a PNG file, X-Plane will load the PNG file when texture compression is off and the DDS file when it is on. The result is a pre-compressed texture for users who need texture compression and an uncompressed texture for those who can afford the VRAM.
VRAM and Memory
One last note on texture resolution for users: most drivers use virtual address space to load textures, and thus texture memory eats into X-Plane’s 2/3/4 GB address space limit. Therefore with high VRAM cards (e.g. a 3 GB card) it probably isn’t possible to absolutely max out texture res until we go 64 bit. For example, on the Mac (where the driver uses a lot of address space and we only get 3.5 GB) running the sim on extreme + uncompressed texture res will almost always run you out of memory.
One thing I have noticed from looking at user’s settings and our own machines is that the textures resolution selector goes in pretty big jumps. Each resolution change cuts VRAM by 75%, so if you are over VRAM (and having performance problems because of that), the next setting down will probably leave VRAM unused.
So I have a todo item to look at putting incremental texture resolutions in that derez the scenery but not the airplane, for example, to hit some in-between points. In that context, we may be able to support mixed compression, where some airplane elements remain uncompressed, but the scenery is compressed.
The recommended practice for developers remains the same:
- If your textures look better without compression, ship DDS and PNG files, and pre-compress using XGrinder/DDSTool.
- If your textures don’t improve much by running uncompressed, ship only DDS files, pre-compressed with XGrinder/DDSTool.
One Exception: Orthophotos
There is one exception to the X-Plane 10 practice of shipping both DDS and PNGs: if you are using orthophotos via either a .pol or .ter with the LOAD_CENTER directive, use DDS and only DDS.
LOAD_CENTER causes your images to be reloaded at high or low res depending on the distance from the user’s aircraft to the image; this can save a lot of VRAM by reducing resolution where the user cannot see the detail. Because DDS contains pre-resized images, it is much more efficient than PNG for load center; I therefore recommend DDS-only for orthophotos.
I’ve been meaning to write a post about the difference between general purpose flight simulators and AAA first person shooters for a while; a particular feature in X-Plane 10.04 brings some of these differences to light.
A typical high-end first person shooter is a closed game; the art content and the rendering engine ship together, and the art content is authored specifically for (or repurposed for) that particular rendering engine. The content is also completely available ahead of time; it can be authored without worrying about rendering engine changes or the addition of third party add-ons. Similarly if a rendering engine change requires revising all art content, this is at least possible, since all art assets live in house.
Compare this to a general purpose flight simulator. The rendering engine and art content may be revised on different schedules. The artists building third party content have limited access to the developers writing the rendering engine, and the rendering engine acts like more of a platform than a closed product.
Because X-Plane’s rendering engine is a platform, rather than part of a closed product, we try to keep optimization and performance work generic. When possible, we put in optimizations that act automatically without author participation. When we do have optimization advice, it tends to be generic advice that applies over a wide range of rendering engine revisions. (For example, using less OBJ ATTributes and atlasing many small textures into one big texture have been good advice for at least the last seven years.)
Sometimes, however, it becomes necessary to put in authoring features that are somewhat specific to the rendering engine and optimization. This is what has happened with cockpit pre-filling.
Before we go any further, you may want to read about pre-filling here. (One thing I am trying to do is to put the specific tutorials and documentation into permanent articles and not blog posts that are lost in the archives after a few months.) Basically when we pre-fill, we draw part of the airplane early on to mask out clouds, saving fill rate on the GPU, improving framerate.*
For the 2-d panel, we put in pre-fill in X-Plane; no artist intervention is needed. But for the 3-d cockpit, we can’t easily pre-fill without you setting some check-boxes on your airplanes.
The problem with the 3-d cockpit is that it is, in its entirety, rather expensive to draw. So we can’t just draw the entire 3-d airplane (for the purpose of masking clouds) or we’d be burning a possibly large amount of CPU to save a possibly large amount of fillrate. The right trade-off depends on the actual plane, and X-Plane can’t figure out automatically what the right thing to do is.
Hence the pre-fill check-box in X-Plane 10.04. With the pre-fill check box, you (the author) mark your content for optimization to hit the right balance of CPU and fill rate savings. (See the articles linked above for guidelines on how to set the flags sanely.)
Fortunately if the check boxes are set wrong, the worst thing you get is poor frame-rate (not crashing). But this is a rare case where third party authors can (and have to) input tuning data directly into X-Plane.
(And for concerned users: if an airplane doesn’t have the pre-fill check-boxes set up, the performance is the same as 10.03 – there’s no loss, this is just an opt-in optimization.)
* If you are asking at this point “why didn’t you guys do this years ago, you idiots?!?” the answer is: because it never mattered before. X-Plane 9 simply doesn’t use much fill rate, so it never made sense to spend CPU time to save fill rate.
A number of third party authors (bravely) promised X-Plane 10 updates to their airplanes. And I believe that a tune-up to be X-Plane 10 compatible isn’t going to represent a lot of man hours.
That is, unless you try to do this job now.
I have a number of open bugs where version 9 airplanes don’t load quite right in X-Plane 10. If you have an X-Plane 9 airplane and you try to work around these bugs, a few things will happen:
- You will only be able to work around some of the bugs, as others are pretty hard-baked into the sim.
- When I actually fix the bugs (in the next weeks) your airplane will be “broken” yet again, since “fixing” the bugs now means trying to make a right with two wrongs.
So third party authors: please do file bugs if you haven’t already, and give us a little time to work through them. Please do not try to work around these bugs, only to have your airplane become “re-broken” when we get the sim corrected.
And users: please be patient with your third party airplane authors. They can’t make their plane v10 compatible until we fix some bugs, and if they try they’re just going to get thrashed.
There are some things that do need to be reworked for version 10, particularly for HDR mode. But a lot of the reports I get are just things that are funky in the sim.
How to File an Airplane Bug
Since I am getting deluged with bug reports, support requests, questions, etc. I want to describe the best way to get an airplane compatibility bug to us. By following these guidelines, you’ll make it easier for us to kill off compatibility bugs fast.
- Please file the bug only once. If you have filed the bug and haven’t heard that it’s fixed, you do not need to tell us in every new beta that it is still broken.
- File bugs via //dev.x-plane.com/support/bugreport.html. We can route this form to whomever we think is best suited to handle the bugs. Please do not just email the last person you conversed with directly.
- Please only file bugs if an airplane looks different in the latest X-Plane 10 build and X-Plane version 9.70. X-Plane 9.70 is the version 9 release that we are targeting – no older version!
- Please get us reproduction materials – preferably a complete ACF pack, and preferably a cut down one if it can be simplified.
- Send us the v9 .acf file, before any modifications. We want to see what your customers would have seen if they just tried to use the plane. If you send us a version resaved in X-Plane 10, we don’t know what happened.
- Please provide illustrations of how the plane should look in version 9 vs how it does look in version 10. We need a reference point.
- Please try to keep reproduction steps as short as possible. If we have to make a 2 hours flight with 400 waypoints to see a bug, that’s a time sink for us.
A number of you have already sent us good bug reports – we will get to them as quick as I can. If all goes well tonight my fires will be out and I’ll be able to jump into this shortly.
This is a screenshot of Javier’s new version of the X-15 for X-Plane 10. In this case I have hacked the rendering engine to show the specular channel* (the alpha channel) of Javier’s normal map as the texture of the airplane. In other words, that is the per pixel shininess that Javier “drew into” the normal map. there isn’t any lighting on the airplane; the bright edges are simply parts of the plane that are completely glossy.
Just look at how gnarly and detailed and full of goo it is! When you look at the plane under normal lighting conditions you simply see the regular texture. But when the sun reflects off of the plane, the reflection is messed up by this complex specularity pattern. The fact that the sun reflections change unpredictably and dynamically is what sells the illusion.
I mention this because normal maps are expensive – they aren’t compressed and can chew up 4 or 16 MB of VRAM easily – they have to be at high resolution to get the subtle bump details. As long as you’re going to have the resolution, make use of it by putting “texture” into the specular channel – it’ll make your materials seem a lot more complex.
X-Plane 10: X-Plane 10 will allow you to use a gray-scale PNG as a specular-only image, for this kind of “texture” at 1/4 of the VRAM cost, in case you don’t need the actual bump mapping.
* 3-d nerd: X-Plane’s terminology is different from what you’d see in a typical 3-d modeler materials editor. What we call “shininess” is the specular level – that is, how bright specular hilights appear to be. In a 3-d editor this is usually an RGB color, but X-Plane only gives you a single level control; the specular hilights take on the tint of the sun instead.
The “shininess ratio” or “specular exponent” you’d see in a 3-d editor isn’t available in X-Plane – it is set to a fixed exponent by the sim. The unconventional names is a historical artifact.
Simon and Chip have a whole series of posts reviewing the plane, with lots of nice pictures.
I don’t want to say anything and risk murphy’s law, but it looks like the CRJ will see the light of day after all.
I always enjoy seeing third party add-ons that really show what the rendering engine is capable of. Also, it’s good to know that Javier brushes his teeth. 🙂
Propsman pointed this one out to me yesterday: apparently Blender tangent-space normal maps run from a value of Z=-1 (no blue) to Z=1 (100% blue). This is not how X-Plane normal maps work; our normals go from Z=0 (no blue) to Z=1 (100% blue).
This difference is easy to miss because X-Plane has to renormalize the normal map as the last step of processing the normal map. This turns a big artifact into a small one. The general effect of using the Blender convention rather than X-Plane’s is that your normal map will look ‘less bumpy’ for fairly extreme amounts of bump.
To fix this, simply remap the colors of your blue channel in PhotoShop or some other image editing program. Basically you’ll want to set what was 50% blue to 0% blue, and keep 100% blue the same. This will extend the lighter half of the blue channel over the entire blue channel.
If you have any blue less than 50% in the image, um, that’s a normal that points backward, and X-Plane doesn’t support that.
X-Plane 9 allows you to categorize objects as being on the plane’s outside, inside, or glass. X-Plane depends on these flags being right for a few things:
- The draw order of the airplane is determined by the object types – glass is drawn last to avoid translucency artifacts.
- Interior light from the plane is only spilled on the “inside” objects.
- Glass objects are excluded from shadow calculations to avoid having opaque windows in the airplane shadow.
It is important that you use these flags as intended; X-Plane 10 depends on this information as well, and X-Plane 10’s global spill and global shadowing algorithms are more sensitive to incorrect categorization of objects than X-Plane 9’s forward renderer.
In particular, you should have glass for the airplane windows in an attached object tagged as type ‘glass’; do not attach your glass to the cockpit object, which cannot be categorized as glass. If you have an old plane with glass in the cockpit, consider cutting the object in half in a 3-d editor and attaching the glass separately.
(You should also use our prop disc animation, rather than use an OBJ for prop discs; the OBJ format doesn’t contain the z-buffer tricks necessary to make the prop look right.)
X-Plane 10 will have rendering options for global illumination and global shadows. This leaves one question: what if the user has these features disabled?
The plan for version 10 is this: the OBJ file format will have some extensions to allow conditional commands based on rendering settings. A few notes on these conditional commands:
- They will only be based on rendering settings.
- They will be evaluated once when the object is loaded. (If rendering settings change, the object will be reloaded.)
The idea is to be able to change which lit texture you use or remove a set of shadow polygons depending on rendering settings.
The conditionals are evaluated once at load time so that the object can be fully optimized based on the particular set of conditionals used. For example, if your drop shadow (with ATTR_poly_os) is fully removed at load time (because global shadows are on) your object now has fewer attributes, which is good for frame-rate.
This is very different from ANIM_hide. The hide animation may or may not hide depending on datarefs; to keep this fast, you cannot “hide” an attribute, only triangles. This means you “pay” for your atttributes no matter what.
The motivation for both designs is this: if the set of attributes in a file never changes (e.g. they are either conditionally removed at file load once, or they are always present regardless of animation) then we can optimize the attributes of an object once knowing how they relate to each other, to create the leanest, meanest OBJ.
I wrote up some performance tuning notes for OBJs on the wiki. A few notes on how these rules will change with version 10:
Everything on that note applies to version 10 too. If you’ve tuned your model for version 9, that effort will be worth it in version 10.
A few rules are even more important in version 10 than before. In particular, I’ve done a lot of performance tuning for OBJ drawing, but you don’t get those wins if you use ATTRibutes. Clean your objects out for maximum speed.
One special case: objects with very small vertex count are sometimes extra fast in version 10. For example, in version 9, a tree with 8 vertices and no attributes is horribly slow. In version 10, this tree will be quite fast. So in version 9 you might make the tree have 64 vertices and look nicer; in version 10 by keeping the tree lean and mean, you get a speed improvement.