Physical Object Representation
SDxWiki

Physical representations of objects are needed for primarily for two things:

(Note that collision detection is a subsystem distinct from the core simulation of kinetics, but still falls under the general umbrella of physics simulation.)

Representing objects as composites of smaller objects is a desirable software feature. It provides a lot of flexibility in representing objects. By allowing for relatively dynamic compositions, one can model a wide variety of interesting things:

In the most general case, composite objects are arranged hierarchically. I believe that some physics simulators use hierarchical representations to model connections via articulated joints, but we don't anticipated the need to model joint physics in our simulation. (True? What about 'towing'?) ODE, a freely available physics simulator, treats all individual bodies independently, with the joints forming explicit interconnections among them. The hierarchy of connected objects is thus implicit in the joint definitions.

We will use an explicit hierarchical representation. This will make it convenient, for instance, to dock two ships -- the overall object has two subobjects (the ships), which themselves may be composed of multiple subobjects.

To navigate the hierarchy of subobjects, the common technique in C++ is the Visitor pattern. (But this pattern is unnecessary if you use a language that has multimethods, like CommonLisp. Much, much simpler.) This pattern is a bit complex and messy to maintain, but has the advantage that the Visitor code is separated from the subobjects themselves. Thus, for instance, collision-detection code and rendering code is embodied in Visitor objects that are distinct from the subobject representations, a fact which will be desirable when composing our libraries into client and server programs. The Visitor pattern is most manageable when the set of components is relatively static. It seems reasonable to assume that our set of subobject classes will stabilize after some time, with a limited finite number of basic geometric shapes that can be handled directly by the collision detection and rendering systems. Ideally, these two systems will be able to handle the same basic geometry elements, so that a single composite representation can be used by both. Variations that are important to these systems will have to be parameterized. These variations come to mind:

More concretely, from the point of view of code that uses a physical simulation:

In the renderer, this leaves open the question of how to associate component object descriptions with data intended for the rendering engine. This is especially difficult if components are dynamic. For instance, an exhaust region's geometry will be constantly changing with throttle changes, necessitating recalculation of rendering data. However, other components will have fixed geometries, and it would be a waste to recalculate rendering meshes. (The reason that rendering information is not simply part of the object has to do with the architecture; the physical simulator has to be efficiently useable in servers even where no UI is present.)

Storing Rendering Data

Just random ideas...

Idea One

To address this, every component object could have a local id unique within the scope of the root object. A dynamic component gets a new id whenever it changes. This would facilitate lookup of previously calculated and cached rendering data.

Problems:

Idea Two

Component object has a pointer to a CompositeObjectRenderer (COR), which is an abstract interface -- possibly very simple, with just one function, Render. This pointer is empty by default. Rendering engine, when visiting composite objects, can retrieve or set this pointer. When it finds a non-empty pointer, it would presumably just call Render. Otherwise, it would build rendering info and stow the pointer. If the composite object is destroyed or its geometry updated, the composite object deletes the associated COR, if any. Thus the COR is created as needed by the renderer, destroyed when associated component goes away or changes.

Possible refinement: COR is allowed to store a pointer to the CO, with the understanding that the CO must not be used when the COR's destructor is called (because the CO is also in its destructor). This might allow the COR to be useable across minor geometry changes. Problem with this refinement is that it is either/or: you do it, or you don't. It might complicate the COR's task somewhat.

Problems:

Idea Three

Variation of either One or Two: psim knows if it's running in an environment with (without) a rendering engine. COs are chosen accordingly -- there's a variant with or without a rendering ID or pointer, and one with. (How could this be managed easily using templates to bind the variation at compile time?)

Much later ... Idea Four

A rendering engine is an object in its own right, and is simplify notified whenever objects are added to or removed from the physical simulation. The rendering engine can keep references to physical objects. It will probably keeping a list of known renderable objects, of an internal class type, which each stores both rendering data and a reference to the associated physical object. Removing an object will require finding it in this list, given the physical object reference.

This effectively decouples renderer storage from the physical objects, while giving renderers access to the physical objects.