SITE UNDER CONSTRUCTION

Overview of HyperMatter API

We describe in this Section the main features of the core HyperMatter API. In the following Section, we outline a special 'HMScene' function approach that enables scene data produced from the HyperMatter Standalone to be easily exported into 3D graphics applications and physically based effects to be applied to objects, with minimal coding, using just a handful of API function calls.

The core HyperMatter API consists of four main classes, whose ultimate purpose is to enable physically based motion of user-geometry (usually polygonal or spline-based geometry, but could be just a simple collection of vertex points).

The most important class is the HMHypObject class, whose instances are HyperMatter objects (or 'Hyp objects', for short). Hyp objects are the physically based, elastically deformable, mesh type objects that actually perform the dynamics.

Their motion is conferred, after each frame, onto their associated 'Geo' objects, if any, which are instances of the HMGeoObject class. In essence, Geo objects are HyperMatter's internal representation of user-geometry. A Geo object contains a vertex list and possibly a face list, and two or three special transforms whose use depends on the actual role of the Geo object in the scene.

There are also two 'group' classes, namely the HMHypGroup and HMGeoGroup classes, which can be used for managing pluralities of Hyp objects and Geo objects, respectively.

 

Creation

The programmer first creates a 'Geo' object, which will be HyperMatter's internal representation of the user-geometry object(s). A single Geo object could represent a single geometry object or several, and is created by passing in a vertex list and possibly also a face list. A (rigid-body) transform is also supplied, denoting a special 'axes-aligned' configuration that will be used for creating a Hyp object from the Geo object.

Once a Geo object has been created that represents and interfaces with the user-geometry, a Hyp object can then be created that roughly matches the shape of the Geo object and which will be used subsequently to control the motion of the Geo object. A Hyp object can be created directly from a Geo object, or objects, or it can be created independently and then later associated with Geo object(s). After creation, Hyp objects can be re-shaped and/or re-aligned, if necessary, to achieve a better match with the shape of associated geometry. In many cases the precise shape and resolution of a Hyp object might not matter too much, but it might. For example, if contacts or collisions are involved.

We illustrate below the main steps to create a Hyp object from a) an HMForm 'shape-template' (a 3D grid whose volume elements can be filled-in to define the shape/structure of the new Hyp object), and b) a pre-existing Geo object, resulting in a Hyp object that roughly matches the shape of the Geo object. For sake of brevity, we omit arguments specifying desired resolution, matter, etc, of the new Hyp.:-

HMForm hform(5,5,4);                          //create (empty) HForm 'shape template' (dims: 5x5x4 pts)

hform.fill();                                 //fill-in template ('block' shaped)

HMHypObject *phobj = hform.createHyp(...);    //create Hyp object from template (args omitted...)

phobj->evaluate(0,NULL,NULL);                 //initialise new Hyp at frame '0'

HMGeoObject *pgobj = ...                      //create Geo object (details not shown here!)

HMHypObject *phobj = phgobj->createHyp(...);  //create Hyp object from Geo (args omitted...)

phobj->evaluate(0,NULL,NULL);                 //initialise new Hyp at frame '0'

Groups of Objects


The API includes classes for handling 'pluralities' of Geo and Hyp objects. An instance of the HMGeoGroup class contains a linked list of Geo objects, and an instance of the HMHypGroup class contains a linked list of Hyp objects.

When they are created, Geo objects and Hyp objects are assigned unique '+ve' integer identifiers (ID-numbers). User-defined 'groups' (or 'sub-groups') of objects can be defined, which have '-ve' integer identifiers. The GeoGroup and HypGroup classes generally have the same functionality as the GeoObject and HypObject classes, but take an extra argument denoting the (+ve or -ve) ID-number of the object or group of objects that they operate on. By convention, group '-1', in both cases, denotes ALL objects in the group, for which we use the constants HALLGEOS and HALLHYPS, respectively.

If a particular application uses only one Hyp object, or several Hyp objects that are dynamically independent, then the HypGroup class would not be necessary (although it may be convenient, for managing pluralities). But if Hyp objects 'touch' or 'impact' with each other, or are 'glued' together, or in any way 'interact', then the HypGroup class must be used, and the Hyp objects must be time-stepped as a group using the HypGroup's evaluate() or animate() functions. Similarly, if a single Hyp object is to be created from (and control) a group of Geo objects, then the GeoGroup class must be used. HyperMatter allows many different implementations and object set-ups, ranging from simple applications involving only one or two non-interacting objects (such as screen-savers, and simple games and toys), to complex standalone or plug-in applications with full functionality.

.
.
HMHypObject *phobj = hform.createHyp(...);    //create Hyp object from template (args omitted...)

phgrp->add(phobj);                            //add new Hyp object 'phobj' to Hyp group 'phgrp'

phgrp->evaluate(HALLHYPS,0,NULL,NULL);        //initialise ALL Hyps (in group) at frame '0'

.
.

HMHypObject *phobj = phgobj->createHyp(...);  //create Hyp object from Geo (args omitted...)

phgrp->add(phobj);                            //add new Hyp object 'phobj' to Hyp group 'phgrp'

phgrp->evaluate(HALLHYPS,0,NULL,NULL);        //initialise ALL Hyps (in group) at frame '0'


Assuming use of the HMGeoGroup and HMHypGroup classes, almost any operation can be performed via these two classes. They allow operations to be performed on both pluralities of objects and individual objects. And, of course, when needed, a pointer can always be obtained to an individual object, and then its methods called. In the case of 'distributive' operations, the resultant effect will be the same whether the operation is applied to a group of objects or applied individually to each object in the group. However, 'non-distributive' operations will sometimes need to be applied via the group class.

 

Initialisation

A Hyp object might 'always' control its associated Geo object, or it might only take control after a certain time, or if and when a certain condition obtains. A key-framed Geo object, for example, might move rigidly through space for a while, and then control of its motion be handed over to HyperMatter at a particular instant, to model its free-fall and subsequent bouncing, rolling, sliding, etc.

For such cases, various simple procedures are available to define an appropriate Initial state for a Geo's controlling Hyp object, to guarantee 'continuity of motion' of the Geo object at the instant of handover. Otherwise, the programmer is free to ascribe to a Hyp object any Initial state whatsoever. Once the Hyp object has its Initial state defined, and a set of material attributes have been chosen, the Hyp object can be time-stepped, or 'animated'.

 

Time-Stepping and Constraints

For simplicity, we assume here that the application uses a single HMGeoGroup and HMHypGroup class, in which all Geo and Hyp objects reside. Our comments here can be straightforwardly adapted for other cases.

Time-stepping of Hyp objects is performed through either the HMHypGroup's 'evaluate( )' or 'animate( )' functions, usually from within the application's 'timer' or 'time-changed' callback or idle-time 'work' procedure.

The evaluate( ) function takes a (target) frame argument and time-steps the Hyp group from its current state to the target frame. The animate( ) function time-steps the Hyp group through a single frame, irrespective of its current state or frame. HyperMatter's internal frame-counters (or 'clocks') will be updated accordingly.

The evaluate( ) and animate( ) functions are passed two (optional) callbacks, namely a 'Constraint' callback and a 'PostAnimate' callback.

The Constraint callback is called during each internal time-step, and is where constraints are executed, for controlling the motion or behaviour of Hyp objects. For example, parts of a Hyp object could be attached to key-framed 'control' objects, or temporarily rigidified, or made to engage in collision detection, etc. Without any constraints applied, a Hyp object's motion when time-stepped will be its 'natural' motion, as determined by Newton's laws, its Initial state and its material attributes.

On the receiving side, the Constraint and PostAnimate callbacks both pass in a pointer to the calling Hyp group, the integer ID-number of the Hyp object(s) being time-stepped, and also (optional) user data.

In practice, the HMHypGroup evaluate( ) and animate( ) functions are nearly always called over all Hyp objects in the Hyp group, so the Constraint and PostAnimate callbacks' (second) Hyp ID-number argument can usually be ignored. (It is included for completeness, since there may be applications where it would be necessary, and provided that the objects are dynamically independent).

The user data would typically include a pointer to the application's Geo Group, and any other data needed by the callbacks. (The need to pass a pointer to the Geo group as user data follows from the fact that Hyp objects do not know anything about Geo objects).

The HMHypGroup and HMHypObject classes include methods for getting/setting positions, velocities and angular velocities of parts of Hyp objects, for (rigidly or softly) attaching parts of Hyp objects to (possibly) key-framed Geo objects (or user geometry), or fixing them in space, or for controlling the 'orientation' of parts of Hyp objects. Parts of Hyp objects can also be rigidified during motion (whilst the rest of the object moves and deforms naturally). Other constraint methods allow Hyp objects to impact with walls and floors, or arbitrary planar surfaces, or enable contacts and collisions between Hyp objects, or between Hyp objects and Geo objects.

In the following 'simplified' example we illustrate constraining the Y-position of a (pre-defined) part of a Hyp object to equal twice the current 'time' (in seconds). The 'HST_CD' constant denotes the 'current dynamic' state of the Hyp object, which is used for calls made to the setPos( ) function from inside a constraint callback function. The 'HVC_Y' constant denotes that we are restricting the operation to the 'Y'-component of the vector.

int ConstraintGCB(HMHypGroup *phgrp, int hypns, void* userdata)    //(we ignore 'hypns' arg here)
{
       .
        .
       
MyDataClass *mydata = (MyDataClass *)userdata;   //<<< cast to ptr to 'MyDataClass'
        .
        .

        HMGeoGroup *pggrp = mydata->pGeoGroup;           //<<< pre-defined member (not used here)
        .
        .
        float curtime = phgrp->getCurrentTime();         //<<< in seconds!
        .
        .
        HMVector hpos(0.0f);                             //<<< set Y-component of hpos vector to
        hpos.y = curtime * 2.0f;                         //<<< twice current_time
        .
      //Set Y-position of part '4' of Hyp '1' to Y-component of vector 'hpos' :-
        int hobjn = 1;
        int hprtn = 4;
        phgrp->setPos(hobjn,hprtn, HST_CD, HVC_Y, &hpos, NULL,NULL);
        .
        .

}

As mentioned, a second, PostAnimate, callback function can optionally also be passed to the evaluate( ) and animate( ) member functions. Whereas the Constraint callback is called in the 'middle' of each internal time-step to execute constraints, the PostAnimate callback is called 'after' each computed frame of animation. The PostAnimate callback is included for completeness. It might be used, for example, if an application needed to display the scene during intermediate frames, whilst evaluating from the current frame up to a target frame, in which case it would include code necessary to update user geometry and prompt re-drawing of the scene. We will ignore it in our examples.

In the following code fragment we use the HypGroup evaluate( ) function to first initialise all Hyp objects at frame '0', and then to time-step the objects from frame 0 up to frame 50. In the third call, we evaluate at frame 30. The evaluation mechanism will automatically first initialise back to frame '0' and proceed time-stepping from there.

 

phgrp->evaluate(HALLHYPS, 0,ConstraintCB,NULL);    //initialise at frame 0

phgrp->evaluate(HALLHYPS,50,ConstraintCB,NULL);    //timestep (from frame 0 to frame 50)

phgrp->evaluate(HALLHYPS,30,ConstraintCB,NULL);    //timestep (from frame 0 to frame 30)

(Future editions of the API will include 'DStates', which are full blown 'dynamic states' of Hyp objects that can be defined at arbitrary frames and to which initialisations can be made by the evaluation mechanism in order to reach a target frame in the most efficient way possible. Especially useful for 'looping' animation sequences over arbitrary frame ranges, in order to tweak or fine-tune constraint parameters, for example).

 

Editing Constraints

The task of controlling Hyp (and possibly Geo) objects during time-stepping is one of the most important. In a toy or game, for example, the constraints would probably be 'hard-coded' in the constraint callback function, perhaps referencing external control devices. But during application development, or within an end-user 'editing' environment, the user would ideally need the power of something close to a programming language, and possibly with 'instant' response to edits.

To assist this task, the HyperMatter API also includes the 'HMConstraintSystem' class. Use of the HMConstraintSystem class is optional, but in certain contexts may save much time and effort on behalf of the API programmer. The HyperMatter Standalone's Constraint Editor is based directly on the HMConstraintSystem class. It is also used in our 'HMScene' approach, which we introduce in the next Section.

The HMConstraintSystem class allows various command categories to be defined, and command definitions within each category, and enables a linked list of commands (command 'items') that reference these definitions to be created and edited (e.g. through a user-interface), and to be executed (independently of any user-interface).

The HMConstraintSystem's execution method would be called from within the HMHypGroup's constraint callback as usual, and ultimately calls the same API constraint methods as any other application. However, whilst it is designed to execute as efficiently as possible, its use will inevitably entail a small computational overhead.

The HMConstraintSystem also allows the use of 'variables' of various types, including 'int', 'float', 'vector' and 'matrix' types, which can be passed as arguments or returned by commands. Constant values can also be used as command arguments.

Default command categories include logic, arithmetic, trigonometric, matter, effects, etc, and two dynamics categories that contain HyperMatter constraint commands. A special 'control' category is also included whose commands enable basic logical flow of control.

These features are designed to give the user almost the same power as a programmer in terms of control over objects during time-stepping, but without having to re-compile and restart the application after edits. The data defining a command script (sequence of commands) can also be 'encoded' in a highly compact form, so that it can afterwards be saved and loaded as 'scene data'.

In principle, the command system can also be augmented by any other categories or special command definitions that an application might require.

For more information, refer back to the section describing the Standalone's Constraint Editor, whose functionality is based entirely on the HMConstraintSystem class.

Alternatively, if an application's constraints cannot be hard-coded then custom designed constraint editing and execution methods could be written by the API programmer. For example, involving the parsing or interpreting of 'text-based' constraint scripts, or through a graphical user interface.

However, one of the advantages of our HMConstraintSystem approach is that it does allow real-time editing and tweaking of constraint scripts during playback, with minimal key presses and mouse-clicks. The programmer would need to evaluate all these factors when deciding the best 'constraint handling' approach for their particular application.

 

Geo Interpolation and Soft-Transforms

When a Hyp object is created from a Geo object, or when a Geo object is explicitly 'materially associated ' with a Hyp object, a set of 'material coordinates' will be automatically assigned to each Geo vertex point. These 'bind' the vertex points to the Hyp object and will be used subsequently by the Geo's interpolation and soft-transform methods.

In the case of 'static' Geo objects, which do not move relative to their controlling Hyp object deformers, the material association would need to be defined only once, prior to any time-stepping. But if a Geo object is soft-transformed with respect to any Hyp object(s), then its vertices' material coordinates will need to be updated each frame before interpolation takes place. Special soft-transform methods are included that handle both the efficient re-computation of material coordinates and subsequent interpolation.

Soft-transforms can be 'daisy-chained', allowing deformational layers to be applied hierarchically, whilst preserving continuity of motion. For example, rotating Geo eyes could be soft-transformed through a deforming Hyp head onto a deforming Hyp body. The first Hyp (head) object might be used to obtain facial expressions, whilst the second Hyp (body) object might be fixed to a vehicle in order to simply model inertial responses and deformations.

The interpolation and soft-transforming of Geo objects, and the subsequent updating of the vertex data of their corresponding user-geometry objects, would typically be performed from within the 'post-animate' callback function passed to the animate() and evaluate() methods described above.

 

Geo Attachments

Not all operations on Geo objects involve interpolation with respect to Hyp deformer objects. There are certain other important operations that, by contrast, entail rigid motion of Geos.

We have already mentioned that HyperMatter includes basic Geo 'key-framing' methods. Key-framed Geo objects can be used, for example, as 'control objects', to which parts of Hyp objects can be fixed during time-stepping (cf: 'animatronics' style motion control systems).

There are also various mechanisms by which 'rigid' Geo objects can be 'attached' to vertex points of Hyp objects:

The API includes a method for computing, for an arbitrary Hyp vertex point, a set of 'local Cartesian axes' that moves and aligns with the neighbourhood of the point as the Hyp object moves through space. Normally, this would be applied to a rigidly constrained Hyp object. Using this method, the programmer can straightforwardly write their own attachment routines. However, for convenience, the API supplies various methods based on this 'local axes' approach, for attaching rigid Geo objects to Hyp objects. Our 'Kit Car' example scenes use these methods to attach steering and drive mechanisms to the rigid Hyp 'chassis' and 'rotorunit' objects of the physically based vehicle.

Again, the Geo attachment methods, and the subsequent updating of the transform data of their corresponding user-geometry objects, would typically be performed from within the 'post-animate' callback function passed to the animate() and evaluate() methods described above.

 

Control

The central focal point from which everything else is structured is the HMHypGroup's main call to its evaluate( ) or animate( ) function, usually from within the application's 'timer' callback or idle-time 'work' procedure.

The Constraint callback, as mentioned, will be called during each internal time-step, and is where constraints are executed.

The Constraint callback passes in (optional) user data. This would typically include a pointer to the application's HMGeoGroup, and any other data needed by the callbacks.

An application programmer also needs to give careful consideration to certain object dependencies. In particular, Geo transform updates on which Hyp objects may depend would need to be performed before the Hyp group is time-stepped (for example, for Geo key-frame interpolation, or other external motion control methods), whilst any Geo transform updates that depend on the current state of Hyp objects would need to be called after the Hyp group is time-stepped (for example, Geo 'attachments' to Hyp object). The most appropriate place to perform these operations would depend on the particular application.

The following code fragment illustrates a typical set-up, using an 'EvaluateSystem( )' function, which would be called from within the application's 'timer' or 'time-changed' callback or idle-time 'work' procedure :

int EvaluateSystemCB(int frame)
{
       .
        .
       
MyDataClass *mydata = (MyDataClass *)userdata;   //<<< cast to ptr to 'MyDataClass'
        .
        .

        HMGeoGroup *pggrp = mydata->pGeoGroup;           //<<< pre-defined member (not used here)
        .
        .
        float curtime = phgrp->getCurrentTime();         //<<< in seconds!
        .
        .
        HMVector hpos(0.0f);                             //<<< set Y-component of hpos vector to
        hpos.y = curtime * 2.0f;                         //<<< twice current_time
        .
      //Set Y-position of part '4' of Hyp '1' to Y-component of vector 'hpos' :-
        int hobjn = 1;
        int hprtn = 4;
        phgrp->setPos(hobjn,hprtn, HST_CD, HVC_Y, &hpos, NULL,NULL);
        .
        .

}

 

Miscellaneous

Numerous other functions and capabilities exist via the API, enabling, for example, editing of the structure and shape of Hyp objects, editing of material attributes, editing of 'parts' and 'groups' of Geo and Hyp objects, re-alignment of Geo and Hyp objects, establishing of 'material associations' between Geo objects and Hyp objects, creation and editing of Hyp object 'DStates' (which, like Initial States, are full-blown physical states to which Hyp objects can be initialised and time-stepped from), and R3-recordings of Hyp objects (allowing instant evaluation of Hyp objects at particular frames, once physical time-stepping has been performed the first time), etc, etc. ( ... 'DStates' will be available in a future release of the API).