Programming a Character




Photo
Camille


There are two parts in this chapter :



Programming a Static Character

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()
We will write our 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
Let's call our character Camille, and give her a class of her own. She has to inherit two classes: PsSimulatedObject, which is the base for any simulated object of OpenMASK, and PsvMechanismPartner, which allows her to be displayed. In Camille.h, we write:
        #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

The simulation tree describes -- in a format special to OpenMASK -- all the objects you want to use in the simulation. This includes your own objects (eg, our character), a visualisation object that will allow to display them, and objects to manage interaction with the user (for instance, to allow navigating in the 3D world with the keyboard).

Makefile

There are two concerns when compiling our program. The first is to specify the right path for all the OpenMASK include files and library. The second is to link with the right libraries.

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


Making It Move

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:

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.

Working With OpenGL Performer

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:


Having the camera's coordinates and orientation


Download this archive :Camera.tar.gz

Details of the archive :
      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

When you move, the console show you the camera's coordinates and orientation.
It is important to say that the camera's coordinates are initialised in camille_simTree.OpenMASK3.

On the console you have two points : the LookAt point and the LookFrom point.
The lookFrom point is the position of the camera (the camera's coordinates).
The lookAt point is the point where you are looking at (from the lookFrom point).

Return to the summary