VR-Vantage 2.5 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleModelArticulationDistributed

Table of Contents

Overview

This example shows how to use the articulated model agent. The application loads a geometry file, adds the geometry to the scene and articulates parts of the geometry. Of particular interest in this tutorial is the use of agents to load and manage the geometry.

Example details

VR-Vantage uses agents to create and synchronize scene objects among all display engines in the configuration. The master creates and owns agents which causes scene objects to be created locally and simultainiously sends messages to the distributed systems to manage their own copies of the same scene object. Agents in VR-Vantage take the same name as the objects they manage with the added suffix 'Agent'. Because agents are used to send messages to distributed system (and not receive back replies), they are one-way communication objects. Their APIs expose the write-only interface of the objects they manage.

This application loads a geometry file using a DtArticulatedModelAgent (which manages an underlying DtArticulatedModel) and inserts the model in the scene using a DtSceneObjectAgent (which manages an underlying DtSceneObject). The DtSceneObjectAgent is used to position the object within the scene, and the DtArticulatedModelAgent is used to move the articulated parts of the model. To coordinate articulation of the model, a custom DtDriver is used to manage both the DtSceneObjectAgent and DtArticulatedModelAgent. DtDriver objects registered with the display engine have the benefit of being called when the simulation starts, when the simulation stops, and every simulation time-update at regular intervals.

The custom DtDriver in this application creates a new DtSceneObjectAgent and DtArticulationModelAgent when the simulation starts (in its 'onStart()' function), and destroys the objects when the simulation stops (in its 'onStop()' function). During the simulation time-updates, the custom DtDriver's onTick() function is called, where it updates the articulated parts of the model. Because the agents are considered to have a 'write-only' API, the custom DtDriver stores its own copy of the model-status used for calculating articulation updates. For this application, the only model-status data stored are current rotation values used to transform selected articulated parts.

Derived from a DtDriver is a custom driver used to load and manipulate the model. The custom driver stores the current part orientation in a map for use when calculating the next part-articulation update.

class MyArticulationDriver : public DtDriver
typedef std::map<int, DtTaitBryan> PartOrientationMap;
PartOrientationMap myPartMap;

The constructor for the custom DtDriver takes a display engine reference, with which it registers a geometry-file definition and then initializes the part-orientation map for specific part-ids in the model.

MyArticulationDriver(DtDe& de)
{
DtModelDefinition md("theModel");
md.setParameter("filename", dataFile);
de.sharedState().addModelDefinition(md);
myPartMap[turretId] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[barrelId] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[gun1Id] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[gun2Id] = DtTaitBryan(0.0f, 0.0f, 0.0f);
}

When the custom DtDriver is notified that the simulation is starting it creates a new DtArticulationModelAgent and set it to the model-definition created at construction time.

virtual bool onStart()
{
myModel = DtArticulatedModelAgent::create(myAgentManager);
myModel->setModelDefinition("theModel");

Then the custom DtDriver creates a DtSceneObjectAgent and adds the model-agent to it.

mySceneObject = DtSceneObjectAgent::create(myAgentManager);
mySceneObject->addModel(myModel, 0);
return true;
}

During the running simulation, the custom DtDriver gets notified at regular intervals when it is time to update itself. It first gets the simulation time, then calculates the delta-time since the last update.

virtual bool onTick()
{
double simTime = myAgentManager.de().simulationTime();
double deltaTime = simTime - mySimTime;
mySimTime = simTime;

The custom DtDriver then uses the simulation times to update the articulated-parts of the model using private functions.

rotatePart(turretId, deltaTime);
rotatePart(gun1Id, deltaTime);
pitchPart(barrelId, simTime);
pitchPart(gun2Id, simTime);
return true;
}

The articulated parts that are rotated have their current rotation values incremented by some factor every simulation tick. The current rotation value is stored with the custom DtDriver instead of being retrieved from the DtArticulationModelAgent because the agent does not export getter functions.

void rotatePart(int partId, double deltaTime)
{
PartOrientationMap::iterator iter(myPartMap.find(partId));
DtTaitBryan& taitBryan(iter->second);
taitBryan.setPsi(taitBryan.psi() + (deltaTime * myRadsPerSecond));
myModel->setPartOrientation(partId, taitBryan, DtVector());
}

Similarly the articulated parts that are pitched (angled up/down) have their current rotation values set every simulation tick. Again, the current rotation value is stored with the custom DtDriver instead of being retrieved from the DtArticulationModelAgent because the agent does not export getter functions.

void pitchPart(int partId, double simTime)
{
PartOrientationMap::iterator iter(myPartMap.find(partId));
DtTaitBryan& taitBryan(iter->second);
taitBryan.setTheta(((sin(simTime) + 1.0f) * 0.5f) * myMaxAngle);
myModel->setPartOrientation(partId, taitBryan, DtVector());
}

Building the Example

VR-Vantage includes pre-built versions of the example application. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is an application. You can run it by running ./bin64/exampleModelArticulationDistributed.exe (on Windows) or ./bin64/exampleModelArticulationDistributed (on Linux). For more information about running examples, please see Running Applications and Examples.

Learn More

Example Source Files


exampleModelArticulationDistributed.cxx

/*****************************************************************************
* Copyright (c) 2012 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
// This application loads a geometry file using a model agent, then articulates
// parts of the model during each simulation tick. Of particular interest in
// this example application is how a DtDriver is used to update model agents.
#include <string>
#include <cmath>
#include <osg/Math> // for osg::DegreesToRadians
#include <matrix/vlTaitBryan.h>
#include <matrix/vlVector.h>
#include <vrvCore/DtDe.h>
// The name of the geometry file to load.
static const std::string dataPath("$(DATA_DIR)/Vehicles/Tracked/");
static const std::string M1A2_Desert("M1A2_DESERT_V7.0.flt/DB_M1A2_DESERT_V7.0.medf");
static const std::string dataFile(dataPath + M1A2_Desert);
// The ids of the actuation parts embedded in the model.
// These values are defined in the DIS specification.
static int turretId(4096);
static int barrelId(4416);
static int gun1Id(6016);
static int gun2Id(5696);
// All VR-Vantage classes are in the same namespace.
using namespace makVrv;
// This driver class is used to create and manage the articulation-model and
// its scene-object. This driver is registered with the driver-manager in
// order to get regular simulation 'ticks' during the run of the application.
// In each tick, this driver updates the model by moving the articulated parts.
//
// This driver indirectly creates the articulated-model and the scene-object by
// creating their 'agent' counterparts instead. Since this driver is using the
// DtArticulatedModelAgent and DtSceneObjectAgent, any calls to the interfaces
// of these classes get propagated to the underlying objects and also get
// marshaled to other distributed simulations.
class MyArticulationDriver : public DtDriver
{
// Since the agents are write-only classes, we cannot read 'current state'
// from them, so this driver saves a copy of the commanded/current state of
// each articulated part in a map. The only state of interest to this class
// is the orientation of each part, and orientation is defined in the
// DtTaitBryan structures.
typedef std::map<int, DtTaitBryan> PartOrientationMap;
public:
// The constructor of this driver is hard-coded to create a model-definition
// which loads a specific model, then it registers the model-definition with
// the DtDe for later use. The constructor also builds the default map
// of part-ids to part-orientations.
MyArticulationDriver(DtDe& de)
: DtDriver(de.agentManager(), "MyArticulationDriver")
, mySceneObject(0)
, myModel(0)
, mySimTime(0.0)
, myPartMap()
, myRadsPerSecond(osg::DegreesToRadians(15.0f))
, myMaxAngle(osg::DegreesToRadians(60.0f))
{
DtModelDefinition md("theModel");
md.setParameter("filename", dataFile);
myPartMap[turretId] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[barrelId] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[gun1Id] = DtTaitBryan(0.0f, 0.0f, 0.0f);
myPartMap[gun2Id] = DtTaitBryan(0.0f, 0.0f, 0.0f);
}
// This drivers destructor destroys the objects it is currently managing.
virtual ~MyArticulationDriver()
{
if (mySceneObject && myModel)
mySceneObject->removeModel(myModel);
delete myModel;
myModel = 0;
delete mySceneObject;
mySceneObject = 0;
}
// Implement the base-class pure virtual function to return
// a class name. This name is used when registering this class.
virtual const std::string& className() const
{
static const std::string name("MyArticulationDriver");
return name;
}
// When the simulation starts, this driver creates the model-agent and the
// scene-object-agent and saves the starting time of the simulation.
virtual bool onStart()
{
// Create the agent and set the model-definition
myModel = DtArticulatedModelAgent::create(myAgentManager);
myModel->setModelDefinition("theModel");
// Create the scene-object
mySceneObject = DtSceneObjectAgent::create(myAgentManager);
mySceneObject->setModelSet(0);
mySceneObject->setPosition(0, DtVector(0.0f, 25.0f, 0.0f));
mySceneObject->setOrientation(0, DtTaitBryan(
osg::DegreesToRadians(-150.0f),
osg::DegreesToRadians(-30.0f),
osg::DegreesToRadians(-10.0f)));
mySceneObject->addModel(myModel, 0);
// save the starting time of this run
mySimTime = myAgentManager.de().simulationTime();
return true;
}
// When the simulation stops, this driver destroys the model-agent and the
// scene-object-agent that it was managing.
virtual bool onStop()
{
mySceneObject->removeModel(myModel);
delete myModel;
myModel = 0;
delete mySceneObject;
mySceneObject = 0;
return true;
}
// On each simulation update, the driver gets the current simulation time
// then updates the articulated parts of the model based on that time.
virtual bool onTick()
{
// get the running simulation time and delta since last time.
double simTime = myAgentManager.de().simulationTime();
double deltaTime = simTime - mySimTime;
mySimTime = simTime;
// Rotate parts around the Z axis.
rotatePart(turretId, deltaTime);
rotatePart(gun1Id, deltaTime);
// Pitch parts around the Y axis.
pitchPart(barrelId, simTime);
pitchPart(gun2Id, simTime);
return true;
}
private:
// This helper function rotates a given part around its local Y axis to
// change its pitch-angle. Based on simulation time, this function will
// pitch the articulated part up and down according to a sinusoidal wave.
void pitchPart(int partId, double simTime)
{
PartOrientationMap::iterator iter(myPartMap.find(partId));
if (iter == myPartMap.end())
return;
DtTaitBryan& taitBryan(iter->second);
taitBryan.setTheta(((sin(simTime) + 1.0f) * 0.5f) * myMaxAngle);
myModel->setPartOrientation(partId, taitBryan, DtVector());
}
// This helper function rotates a given part around its local Z axis to
// change its heading. Based on the delta-time to the last update, this
// function increments the heading rotation a fraction of a given rate.
void rotatePart(int partId, double deltaTime)
{
PartOrientationMap::iterator iter(myPartMap.find(partId));
if (iter == myPartMap.end())
return;
DtTaitBryan& taitBryan(iter->second);
taitBryan.setPsi(taitBryan.psi() + (deltaTime * myRadsPerSecond));
myModel->setPartOrientation(partId, taitBryan, DtVector());
}
private:
DtSceneObjectAgent* mySceneObject;
double mySimTime;
PartOrientationMap myPartMap;
const double myRadsPerSecond;
const double myMaxAngle;
};
// The main function creates, initializes and runs the application.
// It creates an instance of the driver to populate the scene and
// articulate the model while the application is running.
int main(int argc,char** argv)
{
// Create and initialize a VR-Vantage application.
igApp.initialize(argc, argv);
// Create the driver to manage the objects in the scene.
MyArticulationDriver* driver = new MyArticulationDriver(igApp.de());
// Register the driver with the display engine. The display engine will
// manage the driver so we will not delete it.
igApp.de().driverManager().addDriver(driver);
// Start the driver.
igApp.de().driverManager().startDriver(driver);
// Run the application, render the loaded model and have the driver
// articulate all the parts of the model.
igApp.run();
return 0;
}


Copyright © 2005-2019 VT MAK. All Rights Reserved (www.mak.com)