OSG using update callbacks to change the model

Source: Internet
Author: User

OSG using update callbacks to change the model

Transferred from: http://blog.sina.com.cn/s/blog_668aae7801017gl7.html

Use the callback class to implement updates to the scene graph nodes. This section explains how to use callbacks to implement updates to nodes in Update traversal (traversal) per frame.


Callback Overview
Users can use callbacks to interact with scene graphics. Callbacks can be interpreted as a user-defined function, and the callback function executes automatically depending on how the traversal is performed (updating update, picking cull, drawing draw). Callbacks can be associated with individual nodes or nodes of the selected type (and subtype). In each iteration of the scene graph, if a node is encountered that is already associated with a user-defined callback class and function, the callback for that node is executed.

Create an update callback

The update callback is executed every time the scene graph runs the update traversal. The code associated with the update callback can be executed at each frame, and the implementation is preceded by picking callbacks, so the callback-related code can be inserted between the viewer.update () and Viewer.frame () functions of the main emulation loop. The OSG callback also provides a more convenient interface for maintaining the above functions. program code that is good at using callbacks can also run more efficiently in multi-threaded work.

In a previous tutorial, if we need to automatically update the DOF (DOF) nodes associated with the turret heading angle and machine gun inclination of the tank model, we can do this in a number of ways. For example, write a callback function for each node that we are going to manipulate: including a callback associated with the machine gun node, a callback associated with the turret node, and so on. The drawback of this approach is that functions associated with different models cannot be centralized, thus increasing the complexity of code reading, maintenance, and updating. Another (extreme) approach is to write only an update callback function to complete the node operation for the entire scene. Essentially, this approach has the same problem as the previous one, because all the code is focused on the simulation loop. This unique update callback function becomes increasingly difficult to read, maintain, and modify as the complexity of the simulation increases. There is no fixed pattern on how to write a callback function for a node/subtree in a scene. In this example we will create a single tank node callback, which will be responsible for updating the degree of freedom of the turret and machine gun nodes.

To implement this callback, we need to add new data based on the original node class. We need to get a handle to the DOF node associated with the turret and machine gun to update the angle value of turret rotation and machine gun pitch. The change in the angle value is based on the last change. Because callbacks are initialized as part of the scene traversal, we usually need only two parameters: one is the node pointer associated with the callback, and the other is the node accessor pointer that is used to perform the traversal. In order to obtain more parameter data (turret and machine gun DOF handle, rotation and pitch angle values), we can use the UserData data members of the node class. UserData is a pointer to a user-defined class that contains all the datasets needed to associate a particular node. For a user-defined class, however, only one condition is required, that is, it must inherit from the Osg::referenced class. The referenced class provides the function of a smart pointer to assist users in managing memory allocations. The smart pointer records the reference count value assigned to an instance of a class. Instances of this class are deleted only if the reference count value reaches 0. For a more detailed description of osg::referenced, see the section later in this chapter. Based on the above requirements, we add the following code to the tank node:

    1. class  tankdatatype:   public  osg::referenced
    2. {
    3. public :
    4. //Public member
    5. "
    6. Protected :
    7. osgsim::D oftransform* tankturretnode;
    8. Osgsim::D oftransform* tankgunnode;
    9. double  rotation;  //(radian value)
    10. double  elevation;  //(radian value)
    11. };

In order to implement the Tankdata class correctly, we need to get a handle to the DOF node. This work can be done in the class's constructor using the Findnodevisitor class described in the previous tutorial. Findnodevisitor will be traversed from a start node. In this example we will start the traversal from the root node of the subtree that represents the tank, so we need to pass a pointer to the Tankdatatype's constructor to the tank node. Therefore, the constructor code for the Tankdatatype class should be written as follows: (The steps to assign user data to a particular node are then given)

    1. Tankdatatype::tankdatatype (osg::node* N)
    2. {
    3. rotation = 0;
    4. elevation = 0;
    5. Findnodevisitor Findturret ("turret");
    6. N->accept (Findturret);
    7. Tankturretnode = dynamic_cast <osgsim::D oftransform*> (Findturret.getfirst ());
    8. Findnodevisitor Findgun ("gun");
    9. N->accept (Findgun);
    10. Tankgunnode = dynamic_cast< osgsim::D oftransform*> (Findgun.getfirst ());
    11. }

We can also define how to update turret rotation and machine gun pitch in the Tankdatatype class. Now all we have to do is simply to change the turret and machine gun angle by a fixed value per frame. For the pitch angle of the machine gun, we need to determine whether it exceeds the actual limit value. If the limit value is reached, the reset elevation is 0. The turret rotation can be carried out freely within a circle.

    1. void tankdatatype::updateturretrotation () //control tank turret will rotate at different angles
    2. {
    3. Rotation + = 0.01;
    4. TANKTURRETNODE->SETCURRENTHPR (OSG::VEC3 (rotation,0,0));
    5. }
    6. void tankdatatype::updategunelevation () //control the tank's barrel in the Y direction of elevation, control the barrel of the lift
    7. {
    8. Elevation + = 0.01;
    9. TANKGUNNODE->SETCURRENTHPR (OSG::VEC3 (0,elevation,0));
    10. if (Elevation > 0.5)
    11. elevation = 0.0;
    12. }

After adding the above code to the contents of the class, our newly defined class looks like this:

    1. class  tankdatatype:   public  osg::referenced
    2. {
    3. public :
    4. tankdatatype (osg::node*n);
    5. void  updateturretrotation ();
    6. void  updategunelevation ();
    7. protected :
    8. Osgsim::D oftransform* tankturretnode;
    9. Osgsim::D oftransform* tankgunnode;
    10. double  rotation;  //(radian value)
    11. double  elevation;  //(radian value)
    12. };

The next step is to create the callback and associate it to the tank node. To create this callback, we need to overload the "()" operator, which consists of two parameters: a pointer to a node and a pointer to a node accessor. In this function we will perform the update of the DOF node. Therefore, we need to implement an Update method for the Tankdata instance, where the Tankdata instance uses the UserData member of the tank node to associate with the tank node. A pointer to a tank node can be obtained by using the Getuserdata method. Because the return value of this method is a pointer to a osg::referenced base class, it needs to be safely converted to a pointer to the Tankdatatype class. To ensure that the reference value of the user data is correct, we use the template type osg::ref_ptr<tankdatatype> to point to the user data. The entire class is defined as follows:

classTanknodecallback: PublicOsg::nodecallback
    1. {
    2. Public:
    3. Virtual void operator () (osg::node* Node, osg::nodevisitor* nv)
    4. {
    5. osg::ref_ptr<tankdatatype> tankdata = dynamic_cast<tankDataType*> (Node->getuserdata ());
    6. if (Tankdata)
    7. {
    8. Tankdata->updateturretrotation ();
    9. Tankdata->updategunelevation ();
    10. }
    11. Traverse (node, NV);
    12. }
    13. };

The next step is to install the callback: associate it with the tank node we want to modify to implement the update function for each frame. Therefore, we must first ensure that the user data of the tank node (instance of the Tankdatatype Class) is correct. We then use the Setupdatecallback method of the Osg::node class to associate the callback with the correct node. The code looks like this:

//Initialize variables and models, create scenarios
    1. osg::ref_ptr<osg::node> Tanknode = Osgdb::readnodefile ("T72-tank_des.flt");
    2. tankdatatype* tankdata = new tankdatatype (Tanknode);
    3. Tanknode->setuserdata (Tankdata);
    4. Tanknode->setupdatecallback (new tanknodecallback);

After creating the callback, we enter the simulation loop. The code for the simulation loop does not have to be changed. When we invoke the frame () method of the Viewport class instance, we enter an update traversal. The operator "()" Function of the Tanknodecallback class is triggered when the update traverses the tank node.

The complete source code is as follows:

  1. #include <osgViewer/Viewer>
  2. #include <osgDB/ReadFile>
  3. #include <osg/NodeVisitor>
  4. #include <osg/Node>
  5. #include <osg/Group>
  6. #include <osgSim/DOFTransform>
  7. #include <osgUtil/Optimizer>
  8. #include <osg/NodeVisitor>
  9. #include <iostream>
  10. #include <vector>
  11. The DOF node is used in the model to clearly articulate a part of the tank. For example, turret nodes can be rotated and machine gun nodes can be raised
  12. class Findnodevisitor: public Osg::nodevisitor
  13. {
  14. Public:
  15. Findnodevisitor ();
  16. Findnodevisitor (const std::string &searchname);
  17. Virtual void Apply (Osg::node &searchnode);
  18. Virtual void Apply (Osg::transform &searchnode);
  19. void setnametofind (const std::string &searchname);
  20. osg::node* GetFirst ();
  21. typedef Std::vector<osg::node*> Nodelisttype;
  22. nodelisttype& getnodelist () { return foundnodelist;}
  23. Private:
  24. Std::string Searchforname;
  25. Nodelisttype foundnodelist;
  26. };
  27. Findnodevisitor::findnodevisitor (): Osg::nodevisitor (Traverse_all_children), Searchforname ()
  28. {
  29. }
  30. Findnodevisitor::findnodevisitor (const std::string &searchname): Osg::nodevisitor (Traverse_all_ Children), Searchforname (Searchname)
  31. {
  32. }
  33. void findnodevisitor::setnametofind (const std::string &searchname)
  34. {
  35. Searchforname = Searchname;
  36. Foundnodelist.clear ();
  37. }
  38. osg::node* Findnodevisitor::getfirst ()
  39. {
  40. return * (Foundnodelist.begin ());
  41. }
  42. void findnodevisitor::apply (Osg::node &searchnode)
  43. {
  44. if (Searchnode.getname () = = Searchforname)
  45. {
  46. Foundnodelist.push_back (&searchnode);
  47. }
  48. Traverse (Searchnode);
  49. }
  50. void findnodevisitor::apply (osg::transform &searchnode)
  51. {
  52. Osgsim::D oftransform* dofnode =
  53. dynamic_cast<osgsim::D oftransform*> (&searchnode);
  54. if (Dofnode)
  55. {
  56. Dofnode->setanimationon (false);
  57. }
  58. Apply ((osg::node&) searchnode);
  59. Traverse (Searchnode);
  60. }
  61. class Tankdatatype: public osg::referenced
  62. {
  63. Public:
  64. Tankdatatype (Osg::node*n);
  65. void updateturretrotation ();
  66. void updategunelevation ();
  67. protected:
  68. Osgsim::D oftransform* tankturretnode;
  69. Osgsim::D oftransform* tankgunnode;
  70. double rotation; //(radian value)
  71. double elevation; //(radian value)
  72. };
  73. Tankdatatype::tankdatatype (osg::node* N)
  74. {
  75. rotation = 0;
  76. elevation = 0;
  77. Findnodevisitor Findturret ("turret");
  78. N->accept (Findturret);
  79. Tankturretnode = dynamic_cast <osgsim::D oftransform*> (Findturret.getfirst ());
  80. Findnodevisitor Findgun ("gun");
  81. N->accept (Findgun);
  82. Tankgunnode = dynamic_cast< osgsim::D oftransform*> (Findgun.getfirst ());
  83. }
  84. void tankdatatype::updateturretrotation () //control tank turret will rotate at different angles
  85. {
  86. Rotation + = 0.02;
  87. TANKTURRETNODE->SETCURRENTHPR (OSG::VEC3 (rotation,0,0));
  88. }
  89. void tankdatatype::updategunelevation () //control the tank's barrel in the Y direction of elevation, control the barrel of the lift
  90. {
  91. Elevation + = 0.02; Control the tank's barrel in the y direction of the lift
  92. TANKGUNNODE->SETCURRENTHPR (OSG::VEC3 (0,elevation,0));
  93. if (Elevation > 0.5)
  94. elevation = 0.0;
  95. }
  96. class Tanknodecallback: public Osg::nodecallback
  97. {
  98. Public:
  99. Virtual void operator () (osg::node* Node, osg::nodevisitor* nv)
  100. {
  101. osg::ref_ptr<tankdatatype> tankdata = dynamic_cast<tankDataType*> (Node->getuserdata ());
  102. if (Tankdata)
  103. {
  104. Tankdata->updateturretrotation ();
  105. Tankdata->updategunelevation ();
  106. }
  107. Traverse (node, NV);
  108. }
  109. };
  110. int Main (void)
  111. {
  112. Initializing variables and models, setting up scenarios
  113. osg::ref_ptr<osgviewer::viewer> Viewer = new osgviewer::viewer ();
  114. osg::ref_ptr<osg::group> root = new osg::group ();
  115. osg::ref_ptr<osg::node> Tanknode = Osgdb::readnodefile ("T72-tank_des.flt");
  116. tankdatatype* tankdata = new tankdatatype (Tanknode);
  117. Tanknode->setuserdata (Tankdata);
  118. Tanknode->setupdatecallback (new tanknodecallback);
  119. Root->addchild (Tanknode.get ());
  120. Optimize scene data
  121. Osgutil::optimizer Optimizer;
  122. Optimizer.optimize (Root.get ());
  123. Setting scene data
  124. Viewer->setscenedata (Root.get ());
  125. Initialize and create a window
  126. Viewer->realize ();
  127. Start rendering
  128. Viewer->run ();
  129. return 0;
  130. }

The final example is as follows:

OSG using update callbacks to change the model

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.