Sunday, May 21, 2006

Why Show/Hide Is Tricky

I've been asked by a few object authors to put a show/hide command in the OBJ8 format for more advanced animation. It turns out this is trickier than you might think. For example, consider this set of OBJ8 commands (based on a hypothetical ANIM_hide command):
ATTR_flat
TRIS 0 30
ANIM_begin
ANIM_hide sim/flightmodel/whatever
ANIM_smooth
TRIS 30 30
ANIM_end
TRIS 60 30
What's tricky here is: the use of state changes inside the "hidden" part of the object. Should the triangles after the animation be smooth, flat, or change depending on the animation?

Internally X-Plane has an object optimizer; when objects are loaded we analyze it and attempt to reduce the number of total commands, so that object drawing is as fast as possible. I strongly recommend you optimize your objects heavily - if we optimize, we might make the object faster, but if you optimize you will make it faster. Our optimizer is aimed at speeding up internal commands that are generated by X-Plane as it translates the object from OBJ7 or OBJ8 to our internal memory structure.

The problem with using show/hide to optionally skip commands is that the optimizer can no longer remove state changes. Because we don't know whether we're flat or smooth (after a hide command) we can't know whether the next flat or smooth attribute is needed or unnecessary. So if show/hide is truly conditional (meaning it can skip commands) then it actually can cause things to be slower because it prevents X-Plane from removing unnecessary state change.

(The case of smooth/flat might seem trivial and contrived; it is. But there are additional "hidden" attributes that are generated by X-Plane as it translates the OBJ into our in-memory internal format. So state change can come from places you might not expect. Thus it's important that the optimizer do its best to remove state change that can't be addressed in the OBJ itself.)

The alternative (and one that is more likely to get implemented) is show/hide as state. Under this model, the full object is completely evaluated, but the ANIM_hide command basically causes triangles to not appear. This is similar to the workaround that people are doing now: using ANIM_translate to move the unwanted geometry a very long way away (and hoping it is out of sight).

Show/hide as state makes a trade: all commands are executed always, so we run no faster by hiding, but since the execution of the object never changes its flow, it can be more heavily optimized.

I am currently leading toward the latter approach for this reason: currently objects are slow because the CPU must do the work of state change (ATTRibutes, etc.). But graphics cards are becoming more sophisticated; in the future it may be possible to run an object with state change as a single command for the graphics card, with no CPU intervention, making things faster. But the graphics card does not yet have the ability to handle conditional logic, so show/hide as conditional logic could stop us from fully utilizing the graphics card in the future.

(Some OpenGL geeks may be thinking now "but the latest graphics cards do have conditional logic". This is true, but currently it is only usable in shaders; the cards do not yet have the ability to skip whole commands conditionally. I believe they will be able to handle static state change before they can handle conditional state change.)

No comments: