We try now to have a 3D character show up in an OpenMASK window. For this we
need three basic things: a main
function
which will initialise OpenMASK, read the simulation tree and start the simulation,
a file describing the said simulation tree, and a class for our character.
First of all, download this file : camille_bouge_pas.tar.gz
Uncompress it : tar - xvzf camile_bouge_pas.tar.gz
main()
main
function in
a file of its own: main.cxx. Its basic structure will be the following:
#include <SimpleOpenMASK3Loader.h> #include <PsController.h> #include <PsKernelObjectAbstractFactory.h> #include <PsvInteractive3DVis.h> #include <PsCameraman.h> #include <PsKeyboardNavigator.h> #include <PsException.h>
#include "Camille.h"
int main( int argc, char* argv[] ) { // construction of a simulation tree for root PsObjectDescriptor* simTree;
if (argc >= 2) { // the first argument to camille is the simulation tree file simTree = (new SimpleOpenMASK3Loader(argv[1]))->getRootObjectDescriptor() ; } else { cerr << "usage: camille <simtree>" << endl; exit(1); }
// we create the simulation controller PsController* controller = new PsController ( *simTree, 0 ) ;
// next come the managers for objects in the simulation tree // visualisation controller->addInstanceCreator( "PsvInteractive3DVis", new PsSimpleSimulatedObjectCreator<PsvInteractive3DVis> ()) ; // camera controller->addInstanceCreator ("PsCameraman", new PsSimpleSimulatedObjectCreator<PsCameraman> ()) ; // keyboard navigation controller->addInstanceCreator ("PsKeyboardNavigator", new PsSimpleSimulatedObjectCreator<PsKeyboardNavigator> ()) ; // and our own object: Camille controller->addInstanceCreator ("Camille", new PsSimpleSimulatedObjectCreator<Camille> () );
// finally we initialise and run the simulation try { controller->init(); controller->run(); } catch (PsException& e) { cerr << "Uncaught exception: " << e << endl; }
// and we exit (possibly using Performer's exit function, which frees the graphical resources) if (Psv3DVis::callPfExit) pfExit(); } Character
#include <PsSimulatedObject.h> #include <PsvMechanismPartner.h> #include <PsOutput.h> #include <PsTranslationYRotation.h>
class Camille : public PsSimulatedObject, public PsvMechanismPartner { public: Camille(PsController& ctrl, const PsObjectDescriptor& objectDescriptor); virtual ~Camille(void); };
In Camille.cxx, our constructor just calls PsSimulatedObject and PsvMechanismPartner's constructors:
#include <PsSimulatedObject.h> #include <PsvMechanismPartner.h> #include <PsController.h> #include <PsObjectDescriptor.h>
#include "Camille.h"
Camille::Camille(PsController& ctrl, const PsObjectDescriptor& objectDescriptor) : PsSimulatedObject(ctrl, objectDescriptor), PsvMechanismPartner() { }
Camille::~Camille(void) { }
Simulation Tree
Makefile
The OpenMASK include files are in the following locations:
$(OpenMASKDIR)/kernel/inc $(OpenMASKDIR)/contrib/3DVis/inc $(OpenMASKDIR)/contrib/interactive3DVis/inc $(OpenMASKDIR)/contrib/interactive3DVisUtilities/PsCameraman/inc $(OpenMASKDIR)/contrib/3DVisPartners/inc $(OpenMASKDIR)/contrib/userTypes/math/inc $(OpenMASKDIR)/contrib/userTypes/events/inc $(OpenMASKDIR)/contrib/3DVisInputHandlers/math/inc $(OpenMASKDIR)/contrib/loaders/simpleOpenMASK3Loader/inc $(OpenMASKDIR)/contrib/interactive3DVisUtilities/PsKeyboardNavigator/inc
The necessary libraries are in
$(OpenMASKDIR)/lib
and possibly:
/usr/X11R6/lib
The complete library list you need to link with is:
3DVisPartners 3DVisInputHandlers 3DVis Interactive3DVis Interactive3DVisUtilities UserTypes SimpleOpenMASK3Loader OpenMASK pf pfdu pfutil pfui Xmu X11 GLU GL Xext pvm3
First of all, download this file : camille_bouge.tar.gz
Uncompress it : tar - xvzf camile_bouge.tar.gz
To allow Camille to move, we have to do three things:
init()
and compute().init()
when initialising
your object, and compute()
each time your object is scheduled
for activation. We will use these methods to setup our object, and update
regularly its position.
Here we will create an output in Camille that will represent its position,
of type PsTranslationYRotation
(that is, a translation and
a rotation around the Y axis).
visualiseOutput()
will create an input in the visualisation object, and connect it to our position
output; therefore, after this call, every change Camille makes in her position
output will be reflected on the 3D display.
Wrapping it up, Camille.h now looks like:
#include <PsSimulatedObject.h> #include <PsvMechanismPartner.h> #include <PsTranslationYRotation.h> #include <PsOutput.h>
class Camille : public PsSimulatedObject, public PsvMechanismPartner { public: Camille(PsController& ctrl, const PsObjectDescriptor& objectDescriptor); virtual ~Camille();
virtual void init(); virtual void compute(); private: double theta; PsOutput<PsTranslationYRotation>& positionOutput; };
We just added the methods init()
and
compute(), and the private member positionOutput
, which is a reference
to an output of type PsTranslationYRotation
. We also added a member
named theta
, which we will use to move Camille around.
Camille.cxx becomes:
#include <PsSimulatedObject.h> #include <PsvMechanismPartner.h> #include <PsController.h> #include <PsObjectDescriptor.h> #include <PsvTranslationYRotationInputHandler.h> #include <cmath> using namespace std;
#include "Camille.h"
Camille::Camille(PsController& ctrl, const PsObjectDescriptor& objectDescriptor) : PsSimulatedObject(ctrl, objectDescriptor), PsvMechanismPartner(), theta(0.), positionOutput(addOutput<PsTranslationYRotation>("position")) { // initialise the position output positionOutput.set(PsTranslationYRotation(0.,0.,0.,0.));
// and make it visualised visualiseOutput<PsvTranslationYRotationInputHandler>(positionOutput, "DCS_position"); }
Camille::~Camille(void) { }
void Camille::init() { }
void Camille::compute() { // increment the angle theta += 0.5; // angle in radians double theta_rad = theta * M_PI / 180.; // update the position positionOutput.set(PsTranslationYRotation (4. * cos(theta_rad), 0., 4. * sin(theta_rad), -theta - 90)); }
Notice here how we initialised the output. We used the function addOutput(),
which creates an output of type PsTranslationYRotation
, that OpenMASK
will know under the name ``position''. Inputs and outputs all have a name, which
can be used to connect them later (we won't use that name in this tutorial).
Then, we set a first value for the output, and call visualiseOutput()
on it. The argument ``DCS_position'' is the name of a transform node in the
geometry used to display Camille.
We kept our init()
method empty, as we
do not have any more initialisation to do (like connecting to other objects).
We probably should have put the call to visualiseOutput()
in the init()
method, but as of OpenMASK
3.1, it makes the application crash, so we put it in the constructor.
Our compute()
method updates the position of Camille, so as her
to travel around a circle. For this, we use the method set()
on
our position output. The four arguments to the constructor PsTranslationYRotation()
represent the X,Y,Z coordinates and the rotation around the Y axis.
In OpenMASK 3.1, the visualisation is built on top of OpenGL Performer. This means that OpenGL Performer is the one loading your geometry files, and that it keeps a scene graph used to display your objects. It can be useful to access Performer functions that work efficiently on this scene graph.
For instance, we could be willing to use Performer's facilities to calculate intersections of segments with objects in the scene, for the sake of implementing virtual proximeters.
The OpenGL Performer Scene Graph can be accessed in three different ways:
initPartnerNode()
method), add methods that
work on Performer's representations and call them inside the simulated object
inheriting of the new descendant of PsvPartner we just created.
visualiseOutput<InputHandlerType>()
of a PsvPartner.
A number of InputHandlers are distributed in the directory 3DVisInputHandlers
of $OpenMASKDIR/contrib. New inputHandlers should be created by the user to
implement its own animations or special effects.
main.cxx //A classic OpenMask main file Camille.h //Camille Camille.cxx Camera.h //for the camera's coordinates and orientation Camera.cxx camille_simTree.OpenMASK3 //The OpenMask simulation tree settings_1Window_1Viewport.3DVis.OpenMASK3 camille.pro //Generate the Makefile Makefile