OSG uses the update callback to change the model.

Source: Internet
Author: User
Tags class operator

Use the callback class to update scene graphics nodes. This section describes how to use callback to update a node in update traversal of each frame.


Callback Overview
You can use callback to interact with scene images. Callback can be understood as a user-defined function. The callback function is automatically executed based on different traversal methods (Update, select cull, and draw. Callback can be associated with an individual node or a node of the selected type (and child type. In the traversal of scene graphs, if a node has been associated with a user-defined callback class and function, the node callback will be executed.

Create an update callback

The update callback is executed for each update time of the scene image. The Code related to the update callback can be executed at each frame, and the implementation process is prior to the picking callback. Therefore, the Code related to the callback can be inserted into the viewer of the main simulation loop. update () and viewer. between frame () functions. The OSG callback also provides more convenient interfaces for maintenance to implement the above functions. Program code that is good at using callback can also be run more efficiently in multi-thread work.

In the previous tutorial, if we need to automatically update the DOF (Degree of Freedom) node associated with the turret heading angle and machine gun inclination of the tank model, we can accomplish this task in multiple ways. For example, you can write a callback function for each node you want to operate on, including a callback associated with the machine gun node and a callback associated with the turret node. The disadvantage of this method is that functions associated with different models cannot be centralized, which increases the complexity of code reading, maintenance, and updating. Another (extreme) method is to write only one update callback function to complete node operations in the entire scenario. Essentially, this method has the same problem as the previous one, because all the code is concentrated in the simulation loop. As the complexity of simulation increases, the unique update callback function becomes increasingly difficult to read, maintain, and modify. There is no rule for writing the node/subtree callback function in a scenario. In this example, we will create a single tank node callback, which will be responsible for updating the freedom node of the turret and machine gun.

To implement this callback, we need to add new data based on the original node class. We need to get the handle of the DOF node associated with the turret and machine gun to update the angle value of Turret rotation and machine gun pitch. The angle value must be based on the previous change. Because the callback is initialized as part of the scenario traversal, we usually only need two parameters: one is the node pointer associated with the callback, one is the node accessor pointer used for traversing. To obtain more parameter data (turret and machine gun DOF handle, rotation and pitch angle values), we can use the userdata Member of the node class. Userdata is a pointer to a user-defined class, which contains all datasets required to associate a specific node. For a user-defined class, only one condition is required, that is, it must inherit from the OSG: referenced class. The referenced class provides the smart pointer function to help users manage memory allocation. The smart pointer records the reference count value assigned to an instance of a class. Instances of this class are deleted only when the reference count value reaches 0. For more details about OSG: referenced, see the sections later in this chapter. Based on the above requirements, we add the following code to the tank node:

Class tankdatatype: Public OSG: referenced {public: // Public Member protected: osgsim: doftransform * tankturretnode; osgsim: doftransform * tankgunnode; double rotation; // (radian value) double elevation; // (radian value )};

To correctly implement the tankdata class, we need to obtain the handle of the DOF node. This can be done using the findnodevisitor class described in the previous tutorial in the class constructor. Findnodevisitor will traverse from a starting node. In this example, we start to traverse the root node of the sub-tree that represents the tank. Therefore, we need to pass the pointer of the tank node to the tankdatatype constructor. Therefore, the code of the tankdatatype class constructor should be written as follows: (the steps for assigning user data to a specific node will be given later)

tankDataType::tankDataType(osg::Node* n){rotation = 0;elevation = 0;findNodeVisitor findTurret("turret");n->accept(findTurret);tankTurretNode = dynamic_cast <osgSim::DOFTransform*> (findTurret.getFirst());findNodeVisitor findGun("gun");n->accept(findGun);tankGunNode = dynamic_cast< osgSim::DOFTransform*> (findGun.getFirst());}

We can also define how to update turret rotation and machine gun pitch in the tankdatatype class. Now we only need to simply change the fixed value for each frame of the turret and machine gun. For the height of the machine gun, we need to determine whether it has exceeded the actual limit. If the limit value is reached, the angle of elevation is reset to 0. The turret rotation can be performed freely within a circumference.

Void tankdatatype: updateturrenttation () // The Turret of the control tank will rotate at different angles {rotation + = 0.01; tankturretnode-> setcurrenthpr (OSG: vec3 (rotation, 0, 0);} void tankdatatype: updategunelevation () // control the elevation of angle of the barrel of the tank in the Y direction, and control the lifting of the barrel {elevation + = 0.01; tankgunnode-> setcurrenthpr (OSG: vec3 (0, elevation, 0); If (elevation> 0.5) Elevation = 0.0 ;}

After the code is added to the class content, the newly defined class is as follows:

Class tankdatatype: Public OSG: referenced {public: tankdatatype (OSG: node * n); void updateturrenttation (); void updategunelevation (); protected: osgsim: doftransform * handle; osgsim: doftransform * tankgunnode; double rotation; // (radian value) Double elevation; // (radian value )};

The next step is to create a callback and associate it with the tank node. To create this callback, We need to overload the "()" operator, which includes two parameters: the node pointer and the node accesser pointer. In this function, we will update the DOF node. Therefore, we need to execute the update method of the tankdata instance. The tankdata instance uses the userdata Member of the tank node to associate with the tank node. The pointer to the tank node can be obtained by using the getuserdata method. Because the returned value of this method is a pointer to the OSG: referenced base class, you need to safely convert it to a pointer of the tankdatatype class. To ensure that the reference count value of user data is correct, we use the template type OSG: ref_ptr <tankdatatype> to point to user data. The entire class is defined as follows:

class tankNodeCallback : public osg::NodeCallback {public:virtual void operator()(osg::Node* node, osg::NodeVisitor* nv){osg::ref_ptr<tankDataType> tankData = dynamic_cast<tankDataType*> (node->getUserData() );if(tankData){tankData->updateTurretRotation();tankData->updateGunElevation();}traverse(node, nv); }};

The next step is to "Install" the callback: associate it with the tank node we want to modify to implement the UPDATE function execution at each frame. Therefore, we must first ensure that the user data of the tank node (the instance of the tankdatatype class) is correct. Then, we use the setupdatecallback method of the osg: node class to associate the callback with the correct node. The Code is as follows:

// Initialize the variables and model, establish the scenario OSG: ref_ptr <OSG: node> tanknode = osgdb: readnodefile ("t72-tank_des.flt "); tankdatatype * tankdata = new tankdatatype (tanknode); tanknode-> setuserdata (tankdata); tanknode-> setupdatecallback (New tanknodecallback );

After the callback is created, we enter the simulation cycle. The simulation cycle Code does not need to be changed. When we call the frame () method of a viewport class instance, we enter an update traversal. When the update traversal is passed to the tank node, the "()" function of the tanknodecallback class operator is triggered.

The complete source code is as follows:

# Include <osgviewer/Viewer> # include <osgdb/readfile> # include <OSG/nodevisitor> # include <OSG/node> # include <OSG/group> # include <osgsim/ doftransform> # include <osgutil/optimizer> # include <OSG/nodevisitor> # include <iostream> # include <vector> // The DOF node is used in the model, to clearly express a part of the tank. For example, the turret node can be rotated, and the machine gun node can raise class findnodevisitor: Public OSG: nodevisitor {public: findnodevisitor (); findnodevisitor (const STD: string & searchname ); virtual void apply (OSG: node & searchnode); Virtual void apply (OSG: Transform & searchnode); void setnametofind (const STD: string & searchname); OSG :: node * getfirst (); typedef STD: vector <OSG: node *> nodelisttype; nodelisttype & getnodelist () {return foundnodelist;} PRIVATE: STD: String searchforname; nodelisttype foundnodelist;}; findnodevisitor: findnodevisitor (): OSG: nodevisitor (Reporter), searchforname () {} findnodevisitor: findnodevisitor (const STD: string & searchname ): OSG: nodevisitor (traverse_all_children), searchforname (searchname) {} void findnodevisitor: setnametofind (const STD: string & searchname) {searchforname = searchname; foundnodelist. clear ();} OSG: node * findnodevisitor: getfirst () {return * (foundnodelist. begin ();} void findnodevisitor: Apply (OSG: node & searchnode) {If (searchnode. getname () = searchforname) {foundnodelist. push_back (& searchnode);} traverse (searchnode);} void findnodevisitor: Apply (OSG: Transform & searchnode) {osgsim: doftransform * dofnode = dynamic_cast <osgsim :: doftransform *> (& searchnode); If (dofnode) {dofnode-> setanimationon (false);} apply (OSG: node &) searchnode); traverse (searchnode );} class tankdatatype: Public OSG: referenced {public: tankdatatype (OSG: node * n); void updateturrenttation (); void updategunelevation (); protected: osgsim: doftransform * handle; osgsim: doftransform * tankgunnode; double rotation; // (radian value) Double elevation; // (radian value)}; tankdatatype: tankdatatype (OSG: node * n) {rotation = 0; Elevation = 0; findnodevisitor findturret ("turret"); N-> Accept (findturret); tankturretnode = dynamic_cast <osgsim: doftransform *> (findturret. getfirst (); findnodevisitor findgun ("gun"); N-> Accept (findgun); tankgunnode = dynamic_cast <osgsim: doftransform *> (findgun. getfirst ();} void tankdatatype: updateturrenttation () // The Turret of the control tank will rotate at different angles {rotation + = 0.02; tankturretnode-> setcurrenthpr (OSG :: vec3 (rotation,);} void tankdatatype: updategunelevation () // controls the elevation of angle of the tank barrel in the Y direction, control the barrel lifting {// elevation + = 0.02; // control the tank barrel lifting in the Y direction tankgunnode-> setcurrenthpr (OSG: vec3 (0, elevation, 0); If (elevation> 0.5) Elevation = 0.0;} class tanknodecallback: Public OSG: nodecallback {public: Virtual void operator () (OSG: node * node, OSG: nodevisitor * NV) {OSG: ref_ptr <tankdatatype> tankdata = dynamic_cast <tankdatatype *> (node-> getuserdata (); If (tankdata) {tankdata-> updateturrenttation (); tankdata-> updategunelevation ();} traverse (node, NV) ;}; int main (void) {// initialize variables and models, create a scenario: OSG: ref_ptr <osgviewer: viewer> viewer = new osgviewer: Viewer (); OSG: ref_ptr <OSG: group> root = new OSG :: group (); OSG: ref_ptr <OSG: node> tanknode = osgdb: readnodefile ("t72-tank_des.flt"); tankdatatype * tankdata = new tankdatatype (tanknode ); tanknode-> setuserdata (tankdata); tanknode-> setupdatecallback (New tanknodecallback); root-> addchild (tanknode. get (); // osgutil: optimizer; optimizer. optimize (root. get (); // set the scenario data viewer-> setscenedata (root. get (); // initialize and create a window viewer-> realize (); // start rendering viewer-> Run (); Return 0 ;}

The final result is as follows:

 

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.