Exporting HyperMatter Scene Data

The Standalone is designed to enable physically based scenarios to be developed as simply and quickly as possible, given the wide range of object set-ups, parameter settings and constraint mechanisms that are possible.

Although HyperMatter can be used in both real-time applications and computer animation, computer animation benefits from the fact that playback speed is not so crucial, and that more 'contrived' and less general methods can be employed.

An extension of the core HyperMatter API makes it particularly simple to write a HyperMatter plug-in for 3rd-party animation systems that enables physically based motions and effects developed in the Standalone to be applied, via an output '.hms' scene file, to objects in your animation scene.

Importing your own (e.g. polygonal) geometry objects into the Standalone is straightforward. The more challenging task is exporting the relevant HyperMatter scene file data into your animation scene so that it can be executed and saved as part of the animation scene.

These tasks are facilitated by use of a special 'HMCIF' class that holds encoded scene data, and a few special (HMS) 'scene functions'. You then have both the speed and power of the Standalone, as well as full control over integration, with access to all the usual API functions.

(NOTE: Although we focus in this section on animation systems, the same methods we outline here could also apply to certain real-time applications).



An HMCIF class object consists of four (simple type) arrays, namely: a 'char' array, an 'int' array, a 'float' array and 'double' array, together with four integers denoting their respective lengths. The data held in HyperMatter scenes, or any component of a scene, can be encoded as an HMCIF object.

HyperMatter scene components used by the Standalone include a Geo group and a Hyp group, containing the Geo and Hyp objects belonging to the scene, and a Constraint Script that executes through the Standalone's HMConstraintSystem (see previous section). These are the only scene components that are needed for producing physically based effects. The other scene components, including camera and lighting settings, are used for 'displaying' objects through the Standalone.


HyperMatter 'Scene Functions'

A special set of  API 'scene functions' enable a HyperMatter 'scene environment' to be created, internally, from HMCIF scene data, and to be evaluated at arbitrary frames, using just two or three function calls. Geo object vertex or transform data, or any other information provided through the API, can then be obtained as and when needed.

The scene function HMS_CreateHMScene( ) creates, internally, an 'empty' scene environment, which we call an 'HMScene'. The scene environment can then be populated by loading into it HMCIF data.

The scene function HMS_LoadSceneCIF(cif) takes as argument an HMCIF object and extracts from it any Geo and Hyp group data and any constraint data, and builds a physically based HMScene environment from this data. The HMScene can then be evaluated at a target frame using the scene function HMS_Evaluate(frame), or time-stepped through a single frame from its current frame using HMS_Animate( ). These routines would normally be called from a central 'hmUniverse' node in your animation system, described below. Access to the internal Geo and Hyp groups can be obtained using the scene functions HMS_GetGeoGroup( ) and HMS_GetHypGroup( ), which return pointers to the respective groups.

(Note that this set-up is different to a normal HyperMatter plug-in or application, where the Geo and Hyp groups and constraint system would be created and managed by the application explicitly).


Plug-in Implementation

Perhaps the simplest way of creating a HyperMatter plug-in for your animation system, using the 'scene function' approach, is as follows:

First, you will need to define a special data structure that can hold pointers to the HMGeoGroup and HMHypGroup, which can be passed as user data between connected nodes in your system.

You will also need to create a special, central 'hmUniverse' node, to which selected scene objects (e.g. polygon surfaces/objects) can be connected (e.g. via 'deformer' nodes). The hmUniverse contains, as node attributes, four data arrays, corresponding to those in the HMCIF class. The simple internal data of a HMCIF class object can then easily be copied directly into these hmUniverse node data arrays, and vice versa. (These copy operations are performed below by the plug-in functions CopyCIF_to_NodeArrays( ) and CopyNodeArrays_to_CIF( ).)

Then, once a HyperMatter scene file has been output from the Standalone, it can then be re-opened from within your animation system, and its HMCIF data then copied directly onto the corresponding hmUniverse node data arrays, so that the HyperMatter scene data will henceforth be copied as part of the animation scene data. The HyperMatter scene file data only needs to be imported into your animation system once.

In future, whenever your animation scene file is opened, the hmUniverse node data can then be copied into an HMCIF object, which can then be used to load the corresponding HMScene environment. Then during playback, via your scene's 'time-changed' callback, the HMScene can be evaluated at the current frame. The HMScene's internal Geo and Hyp objects are now updated, ready for their data to be copied to your animation scene objects. The appropriate scene objects can then be updated via their corresponding deformer node'sconnection to the hmUniverse node, using the Geo group pointer passed as user data. (It might be convenient to adopt the convention of giving Geo objects the same name as the animation scene objects to which they correspond).


Example (schematic):

By way of example, we will imagine that you wish to apply physically based effects to 'MyPoly1' in your animation system.

Firstly, the plug-in creates a Geo object from MyPoly1, using HyperMatter's API. This is trivially simple, involving only the copying of MyPoly1's vertex list and face list, and optionally a couple of transforms to denote its axis-aligned orientation and/or initial configuration. Other Geo object data can also be supplied if desired (e.g. UV sets, for display, and keyframe data), and, of course, properties can also be ascribed to the Geo once it is imported into the Standalone).

To be able to 'import' the Geo object into the Standalone it must belong to an HMScene. So we create an empty HMScene, calling the scene function HMS_CreateHMScene( ), obtain a pointer to the HMScene's (empty) Geo group, and add the Geo to the group, so that the HMScene now contains the single Geo object. The HMScene can then be encoded as HMCIF data and saved to a '.hms' file, say, 'MyPoly1Geo.hms'. (Several Geo objects could be created from your scene and added to the Geo group, all together, but we restrict to a single Geo object for simplicity) :-

//Export Geo object from animation system :-


HMGeoGroup *pggrp = HMS_GetGeoGroup();

CHMGeoObject *pgobj1 = CreateGeo("MyPoly1");  //<<< (using regular HM API methods)


char *filepathname = "C:\\...\\MyPoly1Geo.hms";


The new 'MyPoly1Geo.hms' scene file can now be imported into the Standalone, along with any other pre-created scene elements. You now have all the resources of the Standalone to script your physically based scenario. If you need to import other scene objects from the original animation scene 'just for reference', then of course this is also possible. When you are happy with the scene, you can then save it in another (output) scene file, say, 'MySceneOUT.hms'.

Next, the plug-in then opens the new scene file, MySceneOUT.hms, from within the animation system, and loads in the scene data, encoded as an HMCIF object. This data can then be directly copied onto corresponding array attributes of the central 'hmUniverse' node, so that it will henceforth be automatically saved as part of the animation scene data. The plug-in also connects a 'deformer node' controlling MyPoly1 to the hmUniverse node, so that it can be updated during animation.

//Import HMScene data into animation system :-

HMCIF cif;

char *filepathname = "C:\\...\\MySceneOUT.hms";
int retval = cif.load(filepathname);

if (retval==0){

We now have the HMScene data saved as part of the animation scene data. So, in future, whenever the animation scene is opened, this data can then be copied back into an HMCIF object. An 'empty' HMScene environment can then be created, by calling the API scene function HMS_CreateHMScene( ), and then the HMCIF object can be passed to the scene function HMS_LoadSceneCIF(cif), which will populate the internal HMScene environment, ready for execution :-

//Load HMScene data from node array data :-


HMCIF cif;

int retval = HMS_LoadSceneCIF(cif);

(Later, when the animation scene is closed, or the plug-in is unloaded, the scene function HMS_DestroyHMScene( ) must be called to delete all the components of the HMScene environment, including the HMGeoGroup and HMHypGroup created internally to hold the Geo and Hyp objects).

Now, with the HMScene data loaded, whenever 'time changes', the API scene function HMS_Evaluate(frame) can be called for the current frame, which time-steps the internal scene environment from its current frame up to the target frame (the evaluation mechanism will first initialise the scene to a previous frame and time-step from there if the target frame is less than the current frame). Alternatively, if progression is always monotonic (e.g. in real-time contexts), the function HMS_Animate( ) can be called, which simply time-steps through a single frame :-

//hmUniverse node evaluates HMScene at current frame :-


The internal HMScene environment is now updated at the current frame. So, your animation scene's 'deformer' nodes can then access the Geo group via their connections to the central hmUniverse node, and regular API methods used to update their associated geometry objects from their corresponding Geo objects in the Geo group. HyperMatter can also supply updated Geo face and vertex normals, if necessary, assuming deformation takes place. Similar remarks apply for extracting Geo object transform data, in cases where their motions are 'rigid' :-

//deformer node in animation scene (graph) updates its geometry object :-

HMGeoGroup *pGgrp =  //...from connection to hmUniverse node
HMHypGroup *pHgrp =  //...from connection to hmUniverse node
HMGeoObject *pgobj = pGgrp->getGeo("MyPoly1");

if (pgobj){
    int numvtxpts =

//get vertex array (positions), and update :-
    HVector *pgvtxpos = pgobj->getArrayPosC();
    ... update MyPoly1 vertex positions ...

//get vertex normals (if approp?), and update :-

    HVector *pgvtxnrm = pgobj->getArrayNormV();

    ... update MyPoly1 vertex norms (if approp?) ...

    ... etc


... etc

Finally, when the scene is closed, or the HyperMatter plug-in is unloaded, the hmUniverse node should be deleted, including its data arrays, and the HMScene destroyed :-

//Destroy HMScene data on hmUniverse deletion :-


//+ delete data arrays.

This shows how simple a HyperMatter plug-in can be. Once the basic set-up is implemented, there are of course countless ways a basic plug-in can be extended, incrementally, as and when their need arises.

For example, the plug-in could replace the HMS_Evaluate( ) scene function with its own customised alternative, possibly whilst still utilising the HMConstraintSystem used by the Standalone, and/or using your own customised constraint functions. Also, methods could be developed to enable 'live data' in your animation scene to be read 'directly' during playback and passed into the constraint mechanism, etc, etc.

Writing a plug-in 'from scratch' that fully integrates HyperMatter's functionality within your animation system would be an ambitious task, and time consuming, but would ultimately give you 'complete' control over all aspects. However, starting from the simple 'scene-function' approach, this could be done incrementally, whilst allowing a wide range of motions and effects to be utilised (almost) immediately. ...and, of course, we will be augmenting the core API over time as well.