Tutorial

Un article de OpenMASKWiki.

Jump to: navigation, search

This tutorial is considered as the "historical" one, the first provided with the first V4 release.
After we have added the OSOBis example.

Sommaire

Prerequisites

This tutorial assumes you have knowledge of C++ programming and are able to setup and compile an OpenMASK 4.* version application

The current version of the Tutorial ( Part : Using existing extension and OSO code) can be find here : Tutorial.tar . (It's an old one)
A more up to date is also available on the forge (Config files ans OSO sources).


Introduction

In this tutorial you will be introducing with the main concepts of OpenMASK 4 : OpenMASK SimulationObject (OSO), VisualObject, Animator, Extension, Attribute and reusability.
This tutorial is divided in two parts:

  • first one illustrates an OpenMASK application built with reusable components.
  • second one defines a new OSO dedicated to your new application.

Each one is on the same example: the scooter.

Scooter example

The goal of the tutorial is to animate a simple scooter using OpenMASK (e.g. translate its position and rotate its wheels).

Design

Image:Tuto_Example_init.jpg

The scooter application is composed of two OSO : the scooter and the visual rendering service.
A Transform is an OpenMASK type encapsulating a translation vector, a rotation matrix and a scale vector. So the scooter OSO could be defined by three Transform attributes. One for its frame position and two for its two wheels positions.
The visual rendering service is using Ogre 3D library. It can visualize OSO thanks to Visual Object (VO). The animation is performed through animators withing a VO. The VO handles the association of a 3D ogre visual model of the scooter with attributes of the scooter OSO. The 3D model of the scooter is a hierarchical model which contains the scooter frame and its wheels. Three transform animators assume the connection between the OSO attributes and the ogre transform nodes. One animator translates the whole object. Two animators handle the rotation of the two wheels

First way to do that, is to browse reusables components to find ones covering your needs.
Second way to do that, is to develop a new OSO.

3D model

To animate a 3D model with openMASK, we need to use the Ogre3D hierarchical format .scene and define animation point where to connect OpenMASK animtor.
These animation points are basicly Ogre Node, historicly prefixed by "DCS_"

Note that the 3D model of the scooter is for free non-commercial use and is supplied by Wegit [1] on the 3dTotal site

The model has been quickly simplified for tutorial purpose and exported by OgreMAX [2]

On the next figure, you can see the hierarchy defined on 3dsmax to easily animate the scooter :

Image:Tuto_Example_hierarchie.jpg

The corresponding .scene :

<scene formatVersion="1.0" upAxis="y" minOgreVersion="1.4" author="OgreMax Scene Exporter by Derek Nedelman (www.ogremax.com)">
   <nodes>
      <node name="DCS_position" id="158" isTarget="false">
      <node name="scooterFrame" id="96" isTarget="false">
           <scale x="1" y="1" z="1" />
           <position x="-12.5185" y="7.22895" z="-4.2141" />
           <entity name="scooterFrame" id="96" meshFile="scooterFrame.mesh" static="false" castShadows="true" receiveShadows="true">
           </entity>
           <node name="PivotFrontWheel" id="157" isTarget="false">
               <scale x="1" y="1" z="1" />
               <position x="-1.13005" y="-7.09494" z="4.2141" />
               <rotation qx="0" qy="0" qz="0.713542" qw="0.700613" />
               <node name="DCS_front" id="158" isTarget="false">
                   <node name="backWheel1" id="159" isTarget="false">
                       <scale x="1" y="1" z="1" />
                       <position x="0.0268917" y="0.0348252" z="-0.0323215" />
                       <rotation qx="-5.02806e-015" qy="3.09317e-008" qz="-0.707635" qw="0.706578" />
                       <entity name="backWheel1" id="159" meshFile="backWheel.mesh" static="false" castShadows="true" receiveShadows="true">
                       </entity>
                   </node>
               </node>
           </node>
           <node name="PivotBackWheel" id="154" isTarget="false">
               <scale x="1" y="1" z="1" />
               <position x="12.5949" y="-7.09494" z="4.2141" />
               <rotation qx="0" qy="0" qz="0.713542" qw="0.700613" />
               <node name="DCS_back" id="155" isTarget="false">
                   <node name="backWheel" id="23" isTarget="false">
                       <scale x="1" y="1" z="1" />
                       <position x="0.0268917" y="0.0348253" z="-0.0323215" />
                       <rotation qx="-2.51403e-015" qy="3.09317e-008" qz="-0.707635" qw="0.706578" />
                      <entity name="backWheel" id="23" meshFile="backWheel.mesh" static="false" castShadows="true" receiveShadows="true">
                      </entity>
                   </node>
               </node>
           </node>
       </node>
   </nodes>
</scene>


The current limitation of the Transform OpenMASK Animator, is to not taking care of the current value of the DCS_Node before overwriting, so to preserve the rotation center position, you need to add another higher hierarchie (e.g PivotFrontWheel).

Using reusable components

For simple animation, we have already a list of OSO and extension wich can handle scooter animation.

OSO

We split the scooter OSO in two trajectory OSO. One to manage the scooter position and one to handle the rotation of the wheels.

Trajectory

Manages a current position along a trajectory.

OgreVis

Manages visualisation through VO.

Simulation Extension

PostOffset

introduce new output associated to a new attribute

PreOffset

introduce new input associated to a new attribute

Key Extension

PlusMinusTransformExtension

Modify through a key the value of a transform.

PlusMinusFloatExtension

Modify through a key the value of a float.

Visuazation Extension

InputExtension

CameraListener

Manages the point of view with mouse buttons and keys.

ExitOnEsc

Exit the application with Escape key.

SceneDetails

Switches to wire drawing.

DebugOverlay

Informations on overlay

Example

Fichier de configuration

 #OpenMASK3

root // the root <=> the controller
{
  Class Controller
    UserParams
    {
      TraceAll off //(1)
        //TraceIds [ "Kernel:Event" "Kernel:Attribute" "Kernel:Object" ] //(1)
        TraceFile "trace.txt" //(1)
        Plugins [ ["${OMK_HOME}/lib" "OMKInputs"] ["${OMK_HOME}/lib" "OMKAddOn"] ]  //(2)
    }
  Sons // the objects
  {
   ScooterMove
    {
      Class Trajectory
        Scheduling
        {
          Frequency 60
        }
      Extensions
      {
        plus
        {
          Class PlusMinusFloatExtension
            Increment 0.0001
            Key P
            Attribute Step
            VisuName visuOgre
        }
        minus
        {
          Class PlusMinusFloatExtension
            Increment -0.0001
            Key O
            Attribute Step
            VisuName visuOgre
        }
      }

      UserParams
       {
         Targets [ [[10.0 0.0 0.0]]  [[0.0 0.0 0.0]] [[-10.0 0.0 0.0]] [[-20.0 0.0 0.0]] ]
          Step 0.0
      }
    }
    // Rotation Wheel
    ScooterMoveWheel
    {
      Class Trajectory
        Scheduling
        {
          Frequency 60
        }
      Extensions
      {
        rotation
        {
          Class PostOffset
            Attribute Position // the name of the attribute to offset
             Offset [[0.0 0.0 0.0]]
        }
        increment
        {
          Class PreOffset // or PreOffset
            Attribute rotation // the name of the attribute to offset
             Offset [[0.0 0.0 0.0][0.0 0.0 0.0 d]]
        }
        plusRot
        {
          Class PlusMinusTransformExtension
             Increment [[0.0 0.0 0.0][0.0 0.0 0.1 d]]
            Key P
            Attribute increment
            VisuName visuOgre
        }
        moinsRot
        {
          Class PlusMinusTransformExtension
             Increment [[0.0 0.0 0.0][0.0 0.0 -0.1 d]]
            Key O
            Attribute increment
            VisuName visuOgre
        }
      }

      UserParams
       {
         Targets [
           [[0.0 0.0 0.0] ]
           [[0.0 0.0 0.0] ]
          ]
          Step 0.0001
      }
    }
    // Visualization !
    visuOgre
    {
      Class OgreVis
        Scheduling
        {
          Frequency 60
        }
      Extensions
      {
        input
        {
          Class InputExtension
            camera
            {
              Class CameraListener
            }
          ExitOnEsc ON
        }

        sceneDetails
        {
          Class SceneDetails
            Key f4
            VisuName visuOgre
        }

        debugOverlay
        {
          Class DebugOverlay
            DebugOverlayName "Ov_OpenMASK/Debug"
            Key d
            VisuName visuOgre
        }
      }
      UserParams
      {
        OgreHome "${OGRE_HOME}"
          ResourcesFile "resources.cfg"
          SceneFile "config.scene" // Decor + camera + shadow 
          Camera "cameraTuto" // name of the Ogre camera used
          VisualObject
          {
            scooterVO
            {
              Class OgreObject
                ResourceGroup "General"
                GeometryFile "scooter_reduce.scene"
                Animator
                {
                  positionScooter
                  {
                    Class TransformAnimator
                      NodeName DCS_position
                     // NodeName scooterFrame
                      ConnectTo [ScooterMove Position]
                  }
                  rotationScooter
                  {
                    Class TransformAnimator
                      NodeName DCS_front
                      ConnectTo [ScooterMoveWheel Position]
                  }
                  rotationScooter2
                  {
                    Class TransformAnimator
                      NodeName DCS_back
                      ConnectTo [ScooterMoveWheel Position]
                  }
                }
            }
          }
      }
    }
  }
}

Result

Image:Tuto_Result.jpg

To lauch this example :

$OMK_BIN/bin/OMKReferentialApplication cfg_start.OpenMASK

Press the "P" key to start and increase the speed.
Press the "O" key to decrease the speed.
Now these keys manages the move and the rotation but you can dissociate them.

Programming new OSO bis

This part could be get from the forge.

Building new plugin

Follow intructions found with our OMKplugin skeleton.

OSOBis Code

This OSOBis class is closed from the next OSO class but it does not use the attributeAnimator. It just uses attributes which should be connected "by hand" to animators in the configuration file.

Associated configuration file

root // the root <=> the controller
{
 Class Controller
   UserParams
   {
         ...
   }
 Sons // the objects
 {
   scooter   //our new OSOBis
   {
     Class ScooterBisOSO
     Scheduling
       { Frequency 60}
     UserParams
     {
         Max "40"
         Min "-40"
         Step "0.5"
         RotStep "-0.1"
     }
  }
  visuOgre       // Visualization 
  {
     Class OgreVis
     Scheduling
       { Frequency 60}
     Extensions
     {   ...   }
     UserParams
     {
          ....
       VisualObject
       {
         scooterVO
         {
           Class OgreObject
           ResourceGroup "General"
           GeometryFile "scooter_reduce.scene" 
             Animator
             {
               positionScooterAnimator
               {
                  Class TransformAnimator
                  NodeName DCS_position
                  ConnectTo [scooter positionScooter]
               }
               rotationFrontWAnimator
               {
                  Class TransformAnimator
                  NodeName DCS_front
                  ConnectTo [scooter rotationFrontW]
               }
               rotationBackWAnimator
               {
                  Class TransformAnimator
                  NodeName DCS_back
                  ConnectTo [scooter rotationBackW]
               }
            }
 ...

Test

To lauch this example with windows 7 :

OSOBisExample.bat

Programming new OSO

Compilation

We provide the CmakeList.txt need to compile the tutorial.
The first one in "Tutorial" folder only call the Main one on the Source folder
To easy compile an OpenMASK4 application we highly recommend to use the FindOpenMASK4.cmake wich gonna extract from pkg-config or windows environment all it needs.

So on Tutorial Folder

cmake .
make

If it can'f find OpenMASK, check :

  • PKG_CONFIG_PATH on linux with OpenMASK.pc on. (chek pkg-config OpenMASK --libs)
  • OMK_HOME or OMK_BIN on windows

    Plugin

    The files : OMKPluginTuto.h and .cpp handle the plugin definition such as OMKPLUGINTUTo_API var and OBT::PluginInformation :

    OBT::PluginInformation pluginInfo( "OMKPlugin_Tuto", "Tutorial OpeMASK Plugin", 0, 1, "First version", "23/01/08" ) ;
    

    OSO Code

    ScooterOSO.h

    #ifndef SCOOTEROSO_HEADER
    #define SCOOTEROSO_HEADER
    
    #include "OMKExtensibleSimulatedObject.h"
    #include "OMKAttributeAnimator.h"
    #include "OMKAttribute.h"^M
    #include "OMKTransformType.h"
    
    #include "OMKPluginTuto.h" //def OMKPLUGINTUTO_API
    
    /**
     * ScooterOSO \n
    */
    
    class OMKPLUGINTUTO_API ScooterOSO :
      public OMK::ExtensibleSimulatedObject
    {
      public:
       DECLARE_OBJECT_FACTORY( ScooterOSO ) ;
     // Already on the Macro   
    /*  ScooterOSO( 
            OMKController& ctrl,
            const OMKObjectDescriptor& objectDescriptor);
        virtual ~ScooterOSO (void) ;
    */
      /// Reads in the configuration node the values to set the attributs.
      virtual bool loadParameters( const OMK::ConfigurationParameterDescriptor * node ) ;
        /// init connection
        virtual void init ( void);
        /// compute Position
        virtual void computeParameters (void);
      protected:
         //var
        OMK::AttributeAnimatorT< OMK::Type::Transform  > _position ;
        OMK::AttributeAnimatorT< OMK::Type::Transform  > _frontWheel ;
        // 2nd  way 
        //OMK::AttributeAnimatorT< OMK::Type::Transform  > _backWheel ;
        OMK::AttributeAnimatorTypeT< OMK::Type::TransformType  > _backWheel ;
        //
        float _step;
        float _rotStep;
        float _max;
    };
    #endif // SCOOTEROSO_HEADER
    

    An AttributeAnimator, is an attribute, wich will be automatically connected to a animator according to the OSO configuration file.
    If an attributeAnimator is named TOTO, then at initAnimator(), OpenMASK will search the Key TOTOAnimator on the configuration file and will handle the animator link to the attribute.
    So when the user will call the method set on an attribute, automaticaly the animator will get the value of the attribute by himself, without sending event or handling Output/Input.

    We have to sort of attributeAnimator : OMK::AttributeAnimatorT and OMK::AttributeAnimatorTypeT.
    The first is using any UserData structure, and the other one is an OpenMASK type.

    ScooterOSO.cpp

    #include "ScooterOSO.h"
    
    using namespace std;
    using namespace OMK;
    using namespace OMK::Type ;^M
    
    #include <OMKSystemEventIdentifier.h>
    #include "OMKTracer.h"^M
    #include "OMKAttribute.inl"^M
    #include <string>
    
    REGISTER_OBJECT_FACTORY( ScooterOSO, "ScooterOSO" ) ;
    //---------------------------------------------------------------------------
    // constructor
    //---------------------------------------------------------------------------
    ScooterOSO::ScooterOSO (
        Controller& ctrl,
        const ObjectDescriptor& objectDescriptor):
      OMK::ExtensibleSimulatedObject( ctrl, objectDescriptor ),
      _position( "positionScooter", OMK::Type::Transform()),
      _frontWheel( "rotationScooter", OMK::Type::Transform()),
      _backWheel( "rotationScooter2", OMK::Type::TransformType()),
      _step(0.1),
      _rotStep(0.01),
      _max(20.0)
    {
      OMTRACEID ("ScooterOSO","On Construction");
      addAttribute ( _position,true); // Flow Creation 
      addAttribute ( _frontWheel);
      addAttribute ( _backWheel);
    }
    //---------------------------------------------------------------------------
    // destructor
    //---------------------------------------------------------------------------
    ScooterOSO::~ScooterOSO ()
    {
    }
    //---------------------------------------------------------------------------
    // Read configuration file
    //---------------------------------------------------------------------------
     bool ScooterOSO::loadParameters( const ConfigurationParameterDescriptor * node )
    {
    
      ParametersAccessor::get( node, "Max", _max ) ;
      ParametersAccessor::get( node, "Step", _step ) ;
      ParametersAccessor::get( node, "RotStep", _rotStep ) ;
      return true;
     }
     
     //---------------------------------------------------------------------------
    // Init connection
    //---------------------------------------------------------------------------
    void ScooterOSO::init (void)
    {
    
      OMK::ExtensibleSimulatedObject::init();
    
      _position.initAnimator();
      _frontWheel.initAnimator();
      _backWheel.initAnimator();
    
    }
    void ScooterOSO::computeParameters()
    {
      float currentX =  _position.get().getTranslate().X();
    
        if (( currentX > _max ) || ( currentX < 0.0))
          _step =- _step;
    
      OMK::Type::Transform trans = OMK::Type::Transform(  Wm4::Vector3f (_step,,));
      _position.set( product(_position.get(), trans));
    
      OMK::Type::Transform rot;
      rot.setOrientation(,,_rotStep);
      _frontWheel.set( product(_frontWheel.get(),rot));
    
      _backWheel.set( _frontWheel.get());
    
    
     OMTRACEID("DebugTUTO", "Current  : " << trans
          << " Step " << _step
          << " ROT " << rot);
    }
    

    Associated configuration file

     #OpenMASK3
    
    root // the root <=> the controller
    {
      Class Controller
        UserParams
        {
          TraceAll off //(1)
            //TraceIds [ "DebugTUTO" ] //(1)
            TraceFile "trace.txt" //(1)
            Plugins [ ["${OMK_HOME}/lib" "OMKInputs"] ["${OMK_HOME}/lib" "OMKAddOn"]
                       ["lib" "OMKPlugin_Tuto"]
                     ]  //(2)
        }
      Sons // the objects
      {
       // Visualization !
        visuOgre
        {
          Class OgreVis
            Scheduling
            {
              Frequency 60
            }
          Extensions
          {
            input
            {
              Class InputExtension
                camera
                {
                  Class CameraListener
                }
              ExitOnEsc ON
            }
    
            sceneDetails
            {
              Class SceneDetails
                Key f4
                VisuName visuOgre
            }
    
            debugOverlay
            {
              Class DebugOverlay
                DebugOverlayName "Ov_OpenMASK/Debug"
                Key d
                VisuName visuOgre
            }
          }
          UserParams
          {
            OgreHome "${OGRE_HOME}"
              ResourcesFile "resources.cfg"
              SceneFile "config.scene" // Decor + camera + shadow 
              Camera "cameraTuto" // name of the Ogre camera used
              VisualObject
              {
                scooterVO
                {
                  Class OgreObject
                    ResourceGroup "General"
                    GeometryFile "scooter_reduce.scene"
    
                }
              }
          }
        }    scooter
        {
          Class ScooterOSO
            Scheduling
            {
              Frequency 60
            }
          //   Extensions
          //   {  
          //     offset
          //     {
          //       Class PostOffset
          //         Attribute Position
          //         Offset [[0 0 -500]]
          //     }
          //   }
          UserParams
          {
            Max "20"
            Step "0.01"
            RotStep "0.01"
            VisuName "visuOgre"
    
            positionScooterAnimator
            {
              Class TransformAnimator
                NodeName DCS_position
                VisualObjectName scooterVO
                //ConnectTo [ScooterMove Position]
            }
            rotationScooterAnimator
            {
              Class TransformAnimator
                NodeName DCS_front
                VisualObjectName scooterVO
                //ConnectTo [ScooterMoveWheel Position]
            }
            rotationScooter2Animator
            {
              Class TransformAnimator
                NodeName DCS_back
                VisualObjectName scooterVO
                //ConnectTo [ScooterMoveWheel Position]
            }
    
          }
        }
    
    
      }
    }
    

    result

    To lauch this example : $OMK_BIN/bin/OMKReferentialApplication cfg_OSO.OpenMASK

    Suggested Next Step

    Image:Tuto_Example.jpg

    To improve the wheel animation, we can add an extension which computes the rotation needed depending on the value of scooterPosition translation attribute.
    Therefore using twice the same extension will guarantee the same animation is applied to both wheels.

  • Navigation