Main page → NatNet SDK → NatNet: Data Types
This page provides an overview of the general data structure used in the NatNet software development kit (SDK) and how the library is used to parse received tracking information.
For specific details on each of the data types, please refer to the NatNetTypes.h header file.
When receiving streamed data using the NatNet SDK library, its data descriptions should be received before receiving the tracking data. NatNet data is packaged mainly into two different formats: data descriptions and frame-specific tracking data. Utilizing this format, the client application can discover which data are streamed out from the server application in advance to accessing the actual tracking data.
For every asset (e.g. reconstructed markers, rigid bodies, skeletons, force plates) included within streamed capture sessions, their descriptions and tracking data are stored separately. This format allows frame-independent parameters (e.g. name, size, and number) to be stored within instances of the description structs, and frame-dependent values (e.g. position and orientation) to be stored within instances of the frame data structs. When needed, two different packets of an asset can be correlated by referencing to its unique identifier values.
When streaming from Motive, received NatNet data will contain only the assets that are enabled in the Project pane and the asset types that are set to true under Streaming Settings in the Data Streaming pane.
To receive data descriptions from a connected server, use the NatNetClient::GetDataDescriptionList method. Calling this function saves a list of available descriptions in an instance of sDataSetDescriptions.
The sDataSetDescriptions structure stores an array of multiple descriptions for each of assets (MarkerSets, RigidBodies, Skeletons, and Force Plates) involved in a capture and necessary information can be parsed from it. The following table lists out the main data description structs that are available through the SDK. For a complete list of structs and their members, are listed in the NatNetTypes.h header file.
typedef struct sMarkerSetDescription { char szName[MAX_NAMELENGTH]; // MarkerSet name int nMarkers; // # of markers in MarkerSet char** szMarkerNames; // array of marker names } sMarkerSetDescription;
// Rigid Body Definition typedef struct sRigidBodyDescription { char szName[MAX_NAMELENGTH]; // RigidBody name int ID; // RigidBody identifier int parentID; // ID of parent Rigid Body (in case hierarchy exists; otherwise -1) float offsetx, offsety, offsetz; // offset position relative to parent int nMarkers; // Number of markers associated with this rigid body MarkerData* MarkerPositions; // Array of marker locations ( [nMarkers][3] ) int* MarkerRequiredLabels; // Array of expected marker active labels - 0 if not specified. ( [nMarkers] ) } sRigidBodyDescription;
// Skeleton Description typedef struct sSkeletonDescription { char szName[MAX_NAMELENGTH]; // Skeleton name int skeletonID; // Skeleton identifier int nRigidBodies; // # of rigid bodies (bones) in skeleton sRigidBodyDescription RigidBodies[MAX_SKELRIGIDBODIES]; // array of rigid body (bone) descriptions } sSkeletonDescription;
// FrocePlate description typedef struct sForcePlateDescription { int ID; // used for order, and for identification in the data stream char strSerialNo[128]; // for unique plate identification float fWidth; // plate physical width (manufacturer supplied) float fLength; // plate physical length (manufacturer supplied) float fOriginX, fOriginY, fOriginZ; // electrical center offset (from electrical center to geometric center-top of force plate) (manufacturer supplied) float fCalMat[12][12]; // force plate calibration matrix (for raw analog voltage channel type only) float fCorners[4][3]; // plate corners, in world (aka Mocap System) coordinates, clockwise from plate +x,+y (refer to C3D spec for details) int iPlateType; // force plate 'type' (refer to C3D spec for details) int iChannelDataType; // 0=Calibrated force data, 1=Raw analog voltages int nChannels; // # of channels (signals) char szChannelNames[MAX_ANALOG_CHANNELS][MAX_NAMELENGTH]; // channel names } sForcePlateDescription;
// Peripheral Device description (e.g. NIDAQ) typedef struct sDeviceDescription { int ID; // used for order, and for identification in the data stream char strName[128]; // device name as appears in Motive char strSerialNo[128]; // for unique device identification int iDeviceType; // device 'type' code int iChannelDataType; // channel data type code int nChannels; // # of currently enabled/active channels (signals) char szChannelNames[MAX_ANALOG_CHANNELS][MAX_NAMELENGTH]; // channel names } sDeviceDescription;
As mentioned in the beginning, frame-specific tracking data are stored separately from the DataDescription instances as this cannot be known ahead of time or out of band but only by per frame basis. These data gets saved into instances of sFrameOfMocapData for corresponding frames, and they will contain arrays of frame-specific data structs (e.g.sRigidBodyData, sSkeletonData) for each types of assets included in the capture. Respective frame number, timecode, and streaming latency values are also saved in these packets.
The sFrameOfMocapData can be obtained by setting up a frame handler function using the NatNetClient::SetFrameReceivedCallback method or by calling the GetLastFrameOfData() method. In most cases, a frame handler function must be assigned in order to make sure every frames are promptly processed. Refer to the provided SampleClient project for an exemplary setup.
(labeled markers not associated with a "MarkerSet").
A collection of MarkerSets (MarkerSet, Rigid Body, or Skeletons) in the frame. The struct includes name, number of involved markers, and their corresponding X/Y/Z locations.
\NatNet SDK\Sample
Refer to the NatNetTypes.h header file or the NatNetML.dll assembly for the most up to date descriptions of the types.
Most of the NatNet SDK data packets contain ID values. This value is assigned uniquely to individual markers as well as each of assets within a capture. These values can be used to figure out which asset a given data packet is associated with. One common use is for correlating data descriptions and frame data packets of an asset.
For each member object that is included within a parental model, its unique ID value points to both its parental model and the member itself. Thus, the ID value of a member object needs to be decoded in order to parse which objects and the parent models they are referencing to.
For example, a skeleton asset is a hierarchical collection of bone rigid bodies, and each of its bone rigid bodies has unique ID that references to the involved skeleton model and the rigid body itself. When analyzing skeleton bones, its ID value needs to be decoded in order to extract the segment rigid body ID, and only then, it can be used to reference its descriptions.