OBJ Overview

Revision History 6/3/10 - Updated for Wiki 5/11/07 - Updated for X-Plane 850 and 860. 9/16/05 - Initial Draft.

This document describes the X-Plane OBJ8 modeling system. Please note that this document is current for X-Plane 940 and OBJ8.

Attributes and State
X-Plane 8 and 9 objects consist of a series of commands, each of which draw triangles. The object "state" affects how the objects are drawn. Basically X-Plane draws in a certain manner; you use an attribute command to change how the drawing takes place. The drawing stays the same until you use another attribute command or the model is over.

The sections below discuss the various object state in more detail.

''The typical way you use attributes is to fix special problems with your model. Indeed, some models will not need any attributes at all. Check the documentation with your 3-d modeler and it's export plug-in for how you actually create these attributes.''

PERFORMANCE: X-Plane attempts to draw the geometry of your model in bulk; OpenGL can draw 100 triangles about as fast as it can draw 1, and its most efficient mode is drawing a lot of triangles in sequence. But each time you change state, X-Plane has to stop and reconfigure OpenGL.

Each time X-Plane reconfigures OpenGL and then draws a series of triangles in bulk, this is a batch. (Think of a factory making batches of parts--the factory has to close down for a few hours to reconfigure between batches.) The frame rate of your object is probably more affected by the number of batches than the number of triangles!

You can easily see the number of batches in an OBJ8; each use of the TRIS, LINES and LIGHTS command represents a batch. For example, consider this object excerpt:

ATTR_poly_os 3.000000 TRIS 0 6 ATTR_poly_os 0.000000 ATTR_shade_smooth TRIS 6 48 ATTR_shade_flat TRIS 54 54 smoke_white 0.000000 35.000000 0.000000 2.000000 TRIS 108 48 ATTR_hard TRIS 156 12 LINES 168 8 LIGHTS 0 4 This object contains 7 batches. This object would be faster if the smoke-white command were moved to the bottom; two batches of triangles could be combined, improving framerate.

X-Plane does not reorder your object commands; you will see below that certain effects can only be achieved if you have complete control over the drawing order of your object, so it is important that you organized your object to minimize batches. How you do this will depend on your 3-d program and its export plug-in; it may be able to optimize this for you, or it may require a certain structure.

AC3D:In the AC3D exporter, a single surface may be one or two-sided. If you make an object with a mix of one and two-sided surfaces and then copy it a thousand times, AC3D essentially exports the object in the order of objects, meaning it will do a few one-sided and then a few two-sided surfaces over and over. The result is two thousand batches! If you separate your one-sided and two-sided geometry into groups and copy them separately, you can cut this down to two batches.

On modern hardware, X-plane can draw tens of thousands of triangles in an object without a noticeable frame rate hit. If your object seems to be killing frame rate, take a look at the text file and see if you are getting too many batches.

In X-Plane 850 you can use ATTR_layer_group to control the order that objects are drawn. However this inhibits optimization of the draw order, so you should only use this when it is necessary (for example, to get polygon offset to look good.)

Polygon Offset and Z-Buffer Thrash
X-Plane uses a technique called z-buffering to draw in 3-d. Basically for every pixel drawn on the screen, X-Plane remembers how far away from the viewer it is. When a new model is drawn, only pixels that are closer to the viewer are visible.

If X-Plane did not use Z-Buffering, then objects that were behind a hill would be drawn over the hill. With Z-buffering, the hill obscures the object even though it is drawn first.


 * [[Image:about_obj8_zbuf.gif]]

In the picture on the left, the buildings are drawn in the order numbered. But Z-buffering assures that closer buildings appear on top. For example, building 7 is partly not drawn because building 6 is "closer" to the veiwer. On the right, Z-buffering is disabled; the effect is similar to overlaying paper cutouts.

A problem happens when you have a piece of your model overlaying the ground. Due to a lack of precision on the graphics card, in some places the model will be drawn over the ground, and in some cases the ground will be drawn over the model. This is called Z-Buffer Thrash.


 * [[Image:about_obj8_zthrash.gif]]

In the picture above, the two helipads are objects that touch the terrain. On the left the polgon is thrashing with the terrain; on the right a polygon offset of 1 has been applied, so it draws cleanly.

In order to render a model that is 'on the ground' properly, you need to change the state of model drawing using the "polygon offset" attribute. This attribute tricks the graphics card into favoring your model over the ground for every pixel, removing the thrash. Polygon offset is set via an integer, 0 being normal (off), or positive numbers indicating the amount of thrash protection. Usually an offset of 1 or 2 is adequate, but you may have to experiment to get best results.

IMPORTANT: only use polygon offsets greater than zero for the parts of the model that are on the ground; if you use offsets that are greater than zero for the rest of your model, it will cause incorrect rendering!

IMPORTANT: the draw order matters for polygon offset geometry. You should always draw in this order: This does imply three batches (see state above), first ground, then what's on the ground, then the 3-d stuff, but it is critical that polygon-offset geometry be drawn in this order or else artifacts will be introduced.
 * 1) Anything that is the ground.
 * 2) Anything that overlays the ground, with polygon offset on.
 * 3) Anything that is truly 3-d, like a building, with polygon offset off.

''A typical use of polygon offset would be to add markings to airport pavement. The polygons that are flat on the ground and have pavement texture must have a poly_os of 1; any polygons that represent real 3-d things like cars and trucks and buildings must have a poly_os of 0.''

PERFORMANCE: Like all attributes, polygon offset is a state change and requires a new batch. Consider merging many pavement markings or other poly_os geometry into a single large object to avoid thrash.

Blending and Alpha Channel Control
Your object's texture may optionally contain an alpha channel. Where the alpha channel is transparent, you will be able to see through your object; where it is opaque you will not. This can be used to create windows and other holes in your object easily.

Where the alpha channel has an intermediate value, your object will be translucent. But here is the problem: anything drawn after your model but behind a translucent texture will not be drawn! In order for translucency to work, it requires in-order drawing.

This is a big problem; X-Plane draws models in a random order designed to maximize frame rate. So you may not know what other models will be drawn. This can lead to some very strange effects.


 * [[Image:about_obj8_windows.gif]]

This building has two windows ; the left is translucent (tinted dark) and the right is transparent. In the left-hand picture, because of drawing order, the inside back wall of the building is visible through the right-hand window but the mountains show through the left window. In the right picture, the back wall is visible through both windows because it is drawn first.

X-Plane models are always drawn in the order you specify within your OBJ file, so you can safely use translucency as long as you make sure your object is drawn in the same order. But you cannot use translucency between objects - sometimes the objects will be drawn in the wrong order and you will have artifacts.

It gets more complicated: as the camera moves, your textures may become stretched to fit the model. As part of this stretching your alpha channel can be interpolated. Therefore, even if you have an alpha channel with only opaque and transparent objects, you will still possibly get translucent alpha channel due to stretching.


 * [[Image:about_obj8_alpha_lin.gif]]

On the left, a tree; the alpha mask is actually entirely opaque or transparent. Due to stretching, though, some border pixels become translucent. On the right, the actual alpha mask being used; note the soft gray edges.

This can cause the 'halo' effect. Where your texture is transparent you will get correct rendering, but right at the edge of a transparent and opaque zone, the translucent pixels will show the incorrect thing behind them, which can be visible.

To solve this problem, you can turn off alpha blending. When blending is off, all translucent pixels of 50% opaque or less will be drawn transparent; all translucent pixels of 50% opaque or more will be opaque. This will make a crisp border between opaque and transparent areas.

Note that you can pick the "cutoff percentage" for alpha blending. Different cutoff ratios will make alpha-based textures look more or less "thick". See the OBJ8 spec for more details.


 * [[Image:about_obj8_alpha_halo.gif]]

On the left: two trees. The left tree uses alpha blending, the right does not. The result is translucent pixels around the edge of the left tree. While fully transparent pixels show the building behind the tree, translucent pixels show the sky. The different color appears as a 1-pixel halo. On the rigiht: a close-up of the left-hand tree. The blue color is sky, the gray building.

Here is a summary of the rules for transparency:
 * If you have transparent through which you can see another object, turn off blending to prevent halos (for example, with trees).
 * If you have translucent areas through which your own object is visible, leave alpha blending on for translucency (for example, with a tinted window).
 * If neither case applies, leave blending on because it is the default.
 * You cannot have a translucent area through which you can see other objects!

''Typically you'll want blending off for trees and other structures that use transparency to cut holes in things. You'll want it on for any kind of translucency effects.''

PERFORMANCE: Like all attributes, you want to avoid changing blending mode to keep the number of batches down. If you have an object where some polygons require blending to be on (or off) and for the other polygons blending does not matter, set all of the polygons to be the same, so that one blending mode can be used for the whole object.

If you do not require your object to be drawn in a certain order for the purpose of translucency, reorder your polygons to keep similar-typed polygons together, reducing the number of batches. Translucency and alpha effects (both day and night) and possibly polygon offset are really the only case where you need to control drawing order.

Night Lighting and Alpha Blending
When you use a texture with an alpha mask and a lighting mask that does not, the lighting mask will only be visible where the regular texture is visible. For example, in this case the lighting effect is not visible where the object is transparent.


 * [[Image:about_obj8_lit1.gif]]

This is the texture for a simple shack. Alpha channel is used to cut a hole out of the front. We have the day texture on the left, lit texture on the right. RGB is shown on top and the alpha mask on the bottom (black=transparent, white=opaque). In this case the lighting mask has no alpha channel.


 * [[Image:about_obj8_shack1.gif]]

Unexpected results: while the shack looks good during the day, at night the lighting halo over the front is cut out along with the bricks due to the daytime alpha mask!

To get around this, you can use a lighting mask with an alpha mask. Here's the problem, though: if you use an opaque alpha mask, you will block what was transparent!


 * [[Image:about_obj8_lit2.gif]]

An incorrect fix: adding a fully opaque alpha channel to the lighting mask.


 * [[Image:about_obj8_shack2.gif]]

The lighting mask is opaque; this causes us to not be able to see through the front of the building.

The way to fix this is to make the texture completely bright and use the alpha channel to form the lighting mask.


 * [[Image:about_obj8_lit3.gif]]

The correct lighting mask.


 * [[Image:about_obj8_shack3.gif]]

The building with a halo of light in front.

Note that in this third example, where the daytime texture is opaque, the night lighting mask is opaque and the night lighting texture varies in brightness. But where the daytime texture is transparent, the night lighting mask varies in opacity and the night lighting texture is fully white.

IMPORTANT: At no time do we have variable texture and opacity at the same time in the lighting mask; that would cause the lighting mask to become doubly transparent--this is not what you will want and will result in dark rings around your object.

Here's a summary of the rules for night lighting masks:
 * When lighting an opaque rectangle, use 100% alpha in the light mask 		and use a blend from black to light for the lights.
 * When lighting a transparent rectangle, use an alpha mask to form 		the light and use 100% bright texture.

A similar alpha problem: when creating a light or another bright source, create the light with the alpha mask, not the texture itself.


 * [[Image:about_obj8_dark_ring.gif]]

On the left: a lighting pattern copied to both the texture and the mask. In the middle: what this might look like in Photoshop. On the right: how this looks in X-Plane. The problem is that gray from the middle of the texture in the RGB channels is mixed into the scene in the simulator. This darkens the sky a bit, creating a black ring. The solution to this problem is to set the RGB channels to entirely white or the bright color you want for the light. Use the alpha mask to reduce the intensity of the light near its edges.

PERFORMANCE: X-Plane only allocates an alpha channel for your lighting masks if your PNG contains an alpha channel. (PNGs can contain RGB or RGBA information.) BMPs never have alpha channels for light masks. The inclusion of the alpha channel increases the VRAM needed for the lighting mask by 33% when texture compression is disabled. So if you are going to use a lighting mask with no alpha or with fully opaque alpha, make sure no solid 100% alpha channel is included in your PNG. For a single 1024x1024 texture in extreme res, this saves 1 MB of VRAM.

Hard Polygons
Normally polygons in your model are not sent to the X-Plane physics engine. This means you can fly right through buildings. By turning on 'hard polygons,' X-Plane checks models for collisions. Two warnings about this:
 * Hard polygons takes up RAM and CPU time; use this sparingly!
 * Hard polygons work well for landing on an aircraft, but not well for horizontal collisions. In other words, if you taxi forward into a vertical wall that is 'hard' the resulting collision will not be well- 			modeled.

NOTE: If you have multiple LODs (explained below), hard polygons should only be used in the first, closest, most detailed LOD.

Note that you can pick what "surface properties" a hard polygon has. You can, for example, make your hard polygons react the same way as grass or snow. See the OBJ8 spec for more info on ATTR_hard.

Typically hard polygons are used to make the tops of buildings part of the physics model so that helicopters can land on them.

PERFORMANCE: hard polygons increase CPU load because the physics engine must evaluate more surfaces. But more significantly, they increase RAM usage! Basically, in the current implementation, while object data is kept in memory managed by the driver, the locations of hard polygons are kept separately in system RAM for the physics engine. Worse, these are kept per instance of your object, not once for every instance. So setting a commonly used object to be hard can have enormous RAM implications; use this attribute only when needed.

Panel Texture
Each object uses one texture and one lighting mask; collectively these are referred to as the object texture.

You can also use the plane's 2-d panel as a second texture. When you do this, the panel as it appears instantaneously is used. This means that, for example, you can use the 2-d panel's moving map to make a working moving map in your 3-d cockpit.

When you use the panel texture, the user will be able to click on the clickable parts of the 2-d panel where they are used in your 3-d model. So to make your 3-d panel functional, try to use the 2-d panel texture where possible.

PERFORMANCE: Changing between the regular object and panel texture is extremely expensive. Take extra care to be sure that you consolidate geometry with the panel texture to avoid switching up and back repeatedly! Organize your cockpit objects so that you only have to turn on panel texturing once; of all of the state changes this one is the most expensive.

Two-Sided Geometry
Normally X-Plane only draws one side of your polygons, the "front". (The front is defined as the side where the vertices appear to be going in a clockwise order.) This is done as an optimization; the back sides are not drawn, cutting the number of poylgons drawn roughly in half. This process is called culling.

If you need to have a two-sided polygon, use the no_cull attribute to turn culling off.


 * [[Image:about_obj8_cull.gif]]

In the picture on the left, culling is disabled, so the back wall's "back" (inside) is visible. On the right, culling is enabled, so the back wall is not drawn since it is facing away from the viewer.

One case when you cannot use two-sided geometry; if you want a polygon to have a different texture on each side (for example, a wall that has brick on one side and plaster for the interior of a building on the other) you cannot use one polygon; you'll have to use two one-sided polygons facing away from each other.

NOTE: X-Plane's lighting calculations may not correctly provide light on one side and shadow on the other side of a two-sided polygon. You may want two one-sided polygons for this.

PERFORMANCE: It is faster to draw a single one-sided triangle than a two-sided one. It is faster to draw a single two-sided triangle than two one-sided triangles that face in the same location. But it is slowest of all to change the mode from 1 to 2 sided drawing! Therefore the following rules may make some sense:
 * If you need to have different textures on both sides, use two back-to-back polygons since it is the only way to do this.
 * If you are making a lot of polygons that need to be two-sided, use two-sided for everything.
 * If you are making only one or two polygons that need to be two-sided, double them and leave everything one-sided.
 * If you have enough polygons to have both, group them to avoid state change.

Theoretically the fastest order of one-sided triangles would be to have the front and back triangles be issued consecutively. But I have not profiled this to find	out if it makes a noticeable difference.

AC3D: Because AC3D lets you set 1 or 2-sided drawing for each surface, and because all surfaces in an object are drawn together, there is a risk with AC3D models that you could create a huge number of culling state changes. Make sure you explicitly set all of your objects to the 1 or 2-sided drawing that you want!

Flat vs. Smooth Shading and Per-Vertex Normals.
X-Plane 8 provides flat and smooth shading. In flat shading, the brightness of a triangle (a function of the sun's angle in the sky) is uniform across the entire triangle. With smooth shading, the brightness is computed for every vertex and blended across the object.


 * [[Image:about_obj8_flat.gif]]

The left and the right cylinders have the same number of polygons but the left one does not look round because it is flat-shaded. The right one is smoothly shaded giving the illusion of a perfectly curved surface.

Smooth shading produces continuous brightness changes which can make objects look curved. However the blending rate of the brightness within a triangle is not quite the same as a real round object, so you need to use enough triangles to prevent strange looking brightness.


 * [[Image:about_obj8_smooth.gif]]

The left cylinder has 36 segments while the right has only 10. As a result the shading is a little bit uneven. This effect's noticability varies depending on lighting conditions.

PERFORMANCE: avoid changing this attribute when possible. The default mode is smooth shading. Remember that even in smooth shading, you can create a 'flat shaded' look by setting normals the appropriate way. (This would be done by the export plug-in, not by the modeler.)

AC3D: For AC3D users, the most efficient thing is to set all geometry to smooth and use the crease-angle function to control smoothness. The object will look the same in AC3D and X-Plane.

Materials
You can change the "material" properties of a polygon; this affects the way the object responds to the lighting model. Here are the material properties:
 * Diffuse color - the color of the object in the sun. This is a tint applied to the whole texture, so normally it is set to white, making your texture appear normal.
 * Emissive color - This color is output by your object even when the sun does not shine on it or in the dark. Unlike the lighting mask, this works all the time.
 * Specular ratio - A ratio from 0 to 1 for how shiny your object should appear.

Normally the diffuse color is white and the emissive color is black and shininess is off. X-Plane draws your object by adding together the emissive color, the diffuse color modulated by the sun's angle, and the shininess ratio raised to a power based on the sun's angle (to make the specular spot smaller). This ending lightness level is used to darken your texture.

One strange effect of materials is that this calculation is done separately for the red, green and blue color components, and the results are all limited to 1.0 (max brightness). So for example if you set an emissive color of 1,0,0 (pure red) and a diffuse color of 0,1,0 (pure green), then where the sun hits your object they will be added together and limited to 1,1,0 or yellow! To avoid this, darken the diffuse color when you set an emissive color such that the addition of the two makes sense.

Note: OBJ7 had ambient and specular color commands - they did not work right and are not supported in OBJ8.


 * [[Image:about_obj8_material.gif]]

The bottom sphere is a normal smooth sphere. The left one has been tinted blue using a diffuse color. The top one has an emissive red color; note that it stays fully bright despite the sun setting to the right. The right sphere has a shininess ratio of 1.0 - note the specular hilight on the right side.

PERFORMANCE: I cannot emphasize this enough - MATERIALS ARE SLOW! Think two or three times before using materials in your model.

While material changes are not as slow as changing to the panel texture, they do require a new batch and therefore slow your drawing like any attribute. But unlike other attributes, a lot of what you can do with materials can also be done with creative use of textures. So try to use creative texturing rather than materials where possible.

Really there are only two cases where you should ever use materials (well, at least that I can think of):
 * If you are making an object as part of a plane, use ATTR_shiny_rat to match the shininess of the object with the plane.
 * If you are making a back-lit billboard or sign, use ATTR_emission_rgb to cause it to stay bright even in marginal lighting conditions. This particularly helps taxiway signs.

Do not try to use diffuse color changes to model your object. This is what texturing is for! Even if your modeler provides better editing via colors that textures, find a way to texture; in terms of performance, texturing is infinitely faster than material color changes. For example, you can create blocks of solid colors of a few pixels in your texture and use them to cover your model.

Depth Testing
You can turn off Z-Buffering. However this is generally not a good idea and is not recommended; this feature is only provided for compatibility with older copies of X-Plane.

Level Of Detail
You can specify multiple levels of detail for objects. Levels of detail are distinct versions of your model seen at certain distances. Each level of detail has a range in meters over which it is used; when the camera is farther away than the end of the last LOD distance, the object is not drawn at all. (Even if you use only one LOD you can use this feature to make sure your object is drawn until a certain distance.)


 * [[Image:about_obj8_lod.gif]]

On the left, the most detailed LOD of the KSBD demo object. On the right, a simpler version is used when we zoom out.

If you use LODs, you must pick ranges that are consecutive and do not overlap.

If you do not specify any LODs, X-Plane picks the range over which your object is visible based on how big it is. However X-Plane cannot take into account such factors as how visible the object is from the air, so you may want to specify a LOD for complete control

''There are really two cases where you'd want to use LOD: if you have a very big very complex object then a second LOD can help frame rate. But if you even have only one version, the LOD attribute controls when the object disappears, which is useful to be able to control by hand.''

PERFORMANCE: Before deciding whether to make an LOD, consider three factors:
 * The OBJ engine is pretty fast. Unless you are saving a huge number of triangles, the LOD may just be taking up more RAM without improving framerate.
 * The amount of savings that the LOD provides is also a function of how many times the object is drawn. For example, a jetway that is used 100 times in an airport will save 100 triangles for every triangle you remove from the LOD.  A statue that is used once will save only one triangle for each one you remove.
 * The geometry data for your object is used as a block, so if using more LODs causes your object to have many times more vertices, the LODs may hinder performance.

So really the only objects that are candidates for LODs are ones that have high triangle count and are used repeatedly. Measure the frame rate affect of your objects (for example, use one LOD but set it to disappear early) before deciding to do a second LOD).

As a rule of thumb, objects of less than 100 triangles are probably not worth doing a second LOD for. Objects of less than 24 triangles are never worth simplifying.

''A jetway would be an excellent candidate for LOD; the near model could contain thousands of polygons, but the far one only a hundred. Used a hundred times in an airport the total LOD savings might be nearly a hundred thousand triangles, which will be significant to performance.''

Animation
You can animate your objects. Animation is provided by rotating and translating (moving) parts of your object. The movement of animations is controlled by datarefs, which are published variables from the simulator. For example, you can make a cockpit model where the engine throttles are rotated based on the engine levels in the sim.

Animations can be nested. For example consider a yoke; the yoke and its column might move forward and backward; attached to the column the yoke rotates left and right. If you nest the animations, this will work as you expect. If you do not, then the column will move but the yoke will become detached.

PERFORMANCE: Each group of animation commands start a new batch! So animation has a definite time penalty.

Do not use animation commands to move parts of your objects if they do not actually move. For example, you could use the ANIM_trans command to draw a truck in two places (draw once, move, draw again). However, the overhead of animations is not worth it! Copy and paste the truck in your OBJ.

You may put multiple conceptually different animations into a single animation group. For example, consider a joint that has several degrees of freedom. You can make one animation group followed by one translate and several rotate commands. There is a limit on the number of nested animation groups, and every animation command takes time, so this is a win.

You can use translation animations to move objects around in the world--for example, to drive a car via a plug-in. However X-Plane increases the area with which it measures your object to decide if it must be drawn based on your animation. For example, if you put a 1000 meter translation into your object, your object will be drawn even if it is off screen by 1000 meters because it could have been drawn due to animation. In other words, X-Plane considers what animation might do, not what animation does do. Therefore large distance animations of complex or heavily used objects can hurt frame-rate by causing X-Plane to over-draw.

Note that showing and hiding geometry is possible via animation commands. However, show/hide animation commands are not useful for performance tuning. The OBJ engine has to do almost as much work when geometry is hidden as when it is shown. Do not use show-hide animations as a do-it-yourself LOD--the performance will be much worse.