15.13.  Nodes Used for Animation

Engines are usually connected to nodes. You can, though, create a node class that has built-in engines automatically connected to it. Here are some examples that Inventor provides. These nodes provide a convenient mechanism for adding animation to a scene graph:

Let's look at examples of rotor and blinker nodes.

The SoRotor SoRotor SoRotor node, derived from SoRotation SoRotation SoRotation , changes the angle of rotation at a specified speed. You can use an SoRotor SoRotor SoRotor node any place you would use an SoRotation SoRotation SoRotation . It has these fields:

The number of times a second it is updated depends on the application. This node contains an engine that is connected to the real-time global field. Example 15.7, “ A Spinning Windmill Using an SoRotor Node ” illustrates how you could use this node to rotate the vanes of a windmill. It specifies the rotation and speed for the rotor node and adds it to the scene graph before the windmill vanes, as shown in Figure 15.19, “ Scene Graph for Rotor Node Example. The rotation axis of the windmill vanes is (0.0, 0.0, 1.0) and the initial angle is 0.0. This rotation angle is updated automatically by the rotor node.



   // Read the whole file into the database
   SoSeparator *myGraph = SoDB::readAll(&mySceneInput);
   if (myGraph == NULL) {
      fprintf(stderr, "Problem reading file\n");
      return NULL;
   } 

   mySceneInput.closeFile();
   return myGraph;
}

main(int, char **argv)
{
   // Initialize Inventor and Xt
   Widget myWindow = SoXt::init(argv[0]);

   SoSeparator *root = new SoSeparator;
   root->ref();

   // Read in the data for the windmill tower
   SoSeparator *windmillTower = 
            readFile("windmillTower.iv");
   root->addChild(windmillTower);

   // Add a rotor node to spin the vanes
   SoRotor *myRotor = new SoRotor;
   myRotor->rotation.setValue(SbVec3f(0, 0, 1), 0); // z axis
   myRotor->speed = 0.2;
   root->addChild(myRotor);

   // Read in the data for the windmill vanes
   SoSeparator *windmillVanes = 
            readFile("windmillVanes.iv");
   root->addChild(windmillVanes);

   // Create a viewer
   SoXtExaminerViewer *myViewer = 
            new SoXtExaminerViewer(myWindow);

   // Attach and show viewer
   myViewer->setSceneGraph(root);
   myViewer->setTitle("Windmill");
   myViewer->show();
    
   // Loop forever
   SoXt::show(myWindow);
   SoXt::mainLoop();
}
                 
            // Read the whole file into the database
            SoSeparator myGraph = SoDB.ReadAll(mySceneInput);
            if (myGraph == null)
            {
                Console.WriteLine("Problem reading file\n");
                return null;
            }

            mySceneInput.CloseFile();
            return myGraph;
        }

        public void CreateSample()
        {
            SoSeparator root = new SoSeparator();

            // Read in the data for the windmill tower
            SoSeparator windmillTower = readFile("../../../../../data/windmillTower.iv");
            root.AddChild(windmillTower);

            // Add a rotor node to spin the vanes
            SoRotor myRotor = new SoRotor();
            myRotor.rotation.SetValue(new SbVec3f(0.0f, 0.0f, 1.0f),(float)(Math.PI / 32.0f)); // z axis
            myRotor.speed.Value = (0.1f);
            root.AddChild(myRotor);

            // Read in the data for the windmill vanes
            SoSeparator windmillVanes = readFile("../../../../../data/windmillVanes.iv");
            root.AddChild(windmillVanes);

            // Create a viewer
            myViewer = new SoWinExaminerViewer(this, "", true,
                SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);
            // attach and show viewer
            myViewer.SetSceneGraph(root);
            myViewer.SetTitle("Windmill");
        }
    }
}
               
          
        

The SoBlinker SoBlinker SoBlinker node, derived from SoSwitch SoSwitch SoSwitch , cycles among its children by changing the value of the whichChild field. This node has the following fields:

When it has only one child, SoBlinker SoBlinker SoBlinker cycles between that child (0) and SO_SWITCH_NONE. Example 15.8, “ Using a Blinker Node to Make a Sign Flash ” shows how you could make the text string “Eat at Josie's” flash on and off.


Example 15.8.  Using a Blinker Node to Make a Sign Flash

// Add the non-blinking part of the sign to the root
root->addChild(eatAt);
   
// Add the fast-blinking part to a blinker node
SoBlinker *fastBlinker = new SoBlinker;
root->addChild(fastBlinker);
fastBlinker->speed = 2;  // blinks 2 times a second
fastBlinker->addChild(josie);

// Add the slow-blinking part to another blinker node
SoBlinker *slowBlinker = new SoBlinker;
root->addChild(slowBlinker);
slowBlinker->speed = 0.5;  // 2 secs per cycle; 1 on, 1 off
slowBlinker->addChild(frame);
                       
// Add the non-blinking part of the sign to the root
root.AddChild(eatAt);

// Add the fast-blinking part to a blinker node
SoBlinker fastBlinker = new SoBlinker();
root.AddChild(fastBlinker);
fastBlinker.speed.Value = (2);  // blinks 2 times a second
fastBlinker.AddChild(josie);

// Add the slow-blinking part to another blinker node
SoBlinker slowBlinker = new SoBlinker();
root.AddChild(slowBlinker);
slowBlinker.speed.Value = (0.5f);  // 2 secs per cycle; 1 on, 1 off
slowBlinker.AddChild(frame);
                     
// Add the non-blinking part of the sign to the root
root.addChild(eatAt);

// Add the fast-blinking part to a blinker node
SoBlinker fastBlinker = new SoBlinker();
root.addChild(fastBlinker);
fastBlinker.speed.setValue(2);  // blinks 2 times a second
fastBlinker.addChild(josie);

// Add the slow-blinking part to another blinker node
SoBlinker slowBlinker = new SoBlinker();
root.addChild(slowBlinker);
slowBlinker.speed.setValue(0.5f);  // 2 secs per cycle; 1 on, 1 off
slowBlinker.addChild(frame);