You can add any node to more than one group. A bicycle, for example, might use the same basic wheel group for both the front and rear wheels, with slight modifications for size and location of the two wheels. The term shared instancing refers to such cases, where a single node has more than one parent.
The robot example can instance the leg group twice to form a left and right leg, as shown in Figure 3.10, “ Scene Graph Showing Shared Instancing of the Leg Group ”. The basic leg group contains nodes for a cylinder (the thigh), a transformed cylinder (the calf), and a transformed cube (the foot). The left and right leg groups (the parents: rightLeg and leftLeg) each contain an additional SoTransform( C++ | Java | .NET ) node to position the complete legs correctly onto the robot's body.
Any change made within the leg group is reflected in all instances of it. Here, for example, if the height of the cube in the foot node is doubled, both the left and right feet double in height.
Shared instancing offers database and program economy, since objects can be reused without duplicating them. You save both time and space by reusing nodes (and groups) when possible.
Do not, however, create cycles within a given scene graph. A node can connect to multiple parents but should not be a child of itself or any of its descendants.
Example 3.2, “ Robot.c++ ” shows the code for the robot as described up to this point. The rendered image is shown in Figure 3.11, “ Rendered Image of the Robot ”.
Example 3.2. Robot.c++
// Robot with legs // Construct parts for legs (thigh, calf and foot) SoCube *thigh = new SoCube; thigh->width = 1.2; thigh->height = 2.2; thigh->depth = 1.1; SoTransform *calfTransform = new SoTransform; calfTransform->translation.setValue(0, -2.25, 0.0); SoCube *calf = new SoCube; calf->width = 1; calf->height = 2.2; calf->depth = 1; SoTransform *footTransform = new SoTransform; footTransform->translation.setValue(0, -2, .5); SoCube *foot = new SoCube; foot->width = 0.8; foot->height = 0.8; foot->depth = 2; // Put leg parts together SoGroup *leg = new SoGroup; leg->addChild(thigh); leg->addChild(calfTransform); leg->addChild(calf); leg->addChild(footTransform); leg->addChild(foot); SoTransform *leftTransform = new SoTransform; leftTransform->translation = SbVec3f(1, -4.25, 0); // Left leg SoSeparator *leftLeg = new SoSeparator; leftLeg->addChild(leftTransform); leftLeg->addChild(leg); SoTransform *rightTransform = new SoTransform; rightTransform->translation.setValue(-1, -4.25, 0); // Right leg SoSeparator *rightLeg = new SoSeparator; rightLeg->addChild(rightTransform); rightLeg->addChild(leg); // Parts for body SoTransform *bodyTransform = new SoTransform; bodyTransform->translation.setValue(0.0, 3.0, 0.0); SoMaterial *bronze = new SoMaterial; bronze->ambientColor.setValue(.33, .22, .27); bronze->diffuseColor.setValue(.78, .57, .11); bronze->specularColor.setValue(.99, .94, .81); bronze->shininess = .28; SoCylinder *bodyCylinder = new SoCylinder; bodyCylinder->radius = 2.5; bodyCylinder->height = 6; // Construct body out of parts SoSeparator *body = new SoSeparator; body->addChild(bodyTransform); body->addChild(bronze); body->addChild(bodyCylinder); body->addChild(leftLeg); body->addChild(rightLeg); // Head parts SoTransform *headTransform = new SoTransform; headTransform->translation.setValue(0, 7.5, 0); headTransform->scaleFactor.setValue(1.5, 1.5, 1.5); SoMaterial *silver = new SoMaterial; silver->ambientColor.setValue(.2, .2, .2); silver->diffuseColor.setValue(.6, .6, .6); silver->specularColor.setValue(.5, .5, .5); silver->shininess = .5; SoSphere *headSphere = new SoSphere; // Construct head SoSeparator *head = new SoSeparator; head->addChild(headTransform); head->addChild(silver); head->addChild(headSphere); // Robot is just head and body SoSeparator *robot = new SoSeparator; robot->addChild(body); robot->addChild(head);
// Robot with legs // Construct parts for legs (thigh, calf and foot) SoCube thigh = new SoCube(); thigh.width.Value = 1.2f; thigh.height.Value = 2.2f; thigh.depth.Value = 1.1f; SoTransform calfTransform = new SoTransform(); calfTransform.translation.SetValue(0.0f, -2.25f, 0.0f); SoCube calf = new SoCube(); calf.width.Value = 1.0f; calf.height.Value = 2.2f; calf.depth.Value = 1.0f; SoTransform footTransform = new SoTransform(); footTransform.translation.SetValue(0.0f, -1.5f, 0.5f); SoCube foot = new SoCube(); foot.width.Value = 0.8f; foot.height.Value = 0.8f; foot.depth.Value = 2.0f; // Put leg parts together SoGroup leg = new SoGroup(); leg.AddChild(thigh); leg.AddChild(calfTransform); leg.AddChild(calf); leg.AddChild(footTransform); leg.AddChild(foot); SoTransform leftTransform = new SoTransform(); leftTransform.translation.Value = new SbVec3f(1.0f, -4.25f, 0.0f); // Left leg SoSeparator leftLeg = new SoSeparator(); leftLeg.AddChild(leftTransform); leftLeg.AddChild(leg); SoTransform rightTransform = new SoTransform(); rightTransform.translation.SetValue(-1.0f, -4.25f, 0.0f); // Right leg SoSeparator rightLeg = new SoSeparator(); rightLeg.AddChild(rightTransform); rightLeg.AddChild(leg); // Parts for body SoTransform bodyTransform = new SoTransform(); bodyTransform.translation.SetValue(0.0f, 3.0f, 0.0f); SoMaterial bronze = new SoMaterial(); bronze.ambientColor.SetValue(0.33f, 0.22f, 0.27f); bronze.diffuseColor.SetValue(0.78f, 0.57f, 0.11f); bronze.specularColor.SetValue(0.99f, 0.94f, 0.81f); bronze.shininess.SetValue(0.28f); SoCylinder bodyCylinder = new SoCylinder(); bodyCylinder.radius.Value = 2.5f; bodyCylinder.height.alue = 6.0f; // Construct body out of parts SoSeparator body = new SoSeparator(); body.AddChild(bodyTransform); body.AddChild(bronze); body.AddChild(bodyCylinder); body.AddChild(leftLeg); body.AddChild(rightLeg); // Head parts SoTransform headTransform = new SoTransform(); headTransform.translation.SetValue(0.0f, 7.5f, 0.0f); headTransform.scaleFactor.SetValue(1.5f, 1.5f, 1.5f); SoMaterial silver = new SoMaterial(); silver.ambientColor.SetValue(0.2f, 0.2f, 0.2f); silver.diffuseColor.SetValue(0.6f, 0.6f, 0.6f); silver.specularColor.SetValue(0.5f, 0.5f, 0.5f); silver.shininess.SetValue(0.5f); SoSphere headSphere = new SoSphere(); // Construct head SoSeparator head = new SoSeparator(); head.AddChild(headTransform); head.AddChild(silver); head.AddChild(headSphere); // Robot is just head and body SoSeparator robot = new SoSeparator(); robot.AddChild(body); robot.AddChild(head);
// Robot with legs // Construct parts for legs (thigh, calf and foot) SoCube thigh = new SoCube(); thigh.width.setValue(1.2F); thigh.height.setValue(2.2F); thigh.depth.setValue(1.1F); SoTransform calfTransform = new SoTransform(); calfTransform.translation.setValue(0, -2.25F, 0); SoCube calf = new SoCube(); calf.width.setValue(1); calf.height.setValue(2.2F); calf.depth.setValue(1); SoTransform footTransform = new SoTransform(); footTransform.translation.setValue(0, -1.5F, .5F); SoCube foot = new SoCube(); foot.width.setValue(0.8F); foot.height.setValue(0.8F); foot.depth.setValue(2); // Put leg parts together SoGroup leg = new SoGroup(); leg.addChild(thigh); leg.addChild(calfTransform); leg.addChild(calf); leg.addChild(footTransform); leg.addChild(foot); SoTransform leftTransform = new SoTransform(); leftTransform.translation.setValue(new SbVec3f(1, -4.25F, 0)); // Left leg SoSeparator leftLeg = new SoSeparator(); leftLeg.addChild(leftTransform); leftLeg.addChild(leg); SoTransform rightTransform = new SoTransform(); rightTransform.translation.setValue(-1, -4.25F, 0); // Right leg SoSeparator rightLeg = new SoSeparator(); rightLeg.addChild(rightTransform); rightLeg.addChild(leg); // Parts for body SoTransform bodyTransform = new SoTransform(); bodyTransform.translation.setValue(0.0F, 3.0F, 0.0F); SoMaterial bronze = new SoMaterial(); bronze.ambientColor.setValue(.33F, .22F, .27F); bronze.diffuseColor.setValue(.78F, .57F, .11F); bronze.specularColor.setValue(.99F, .94F, .81F); bronze.shininess.setValue(.28F); SoCylinder bodyCylinder = new SoCylinder(); bodyCylinder.radius.setValue(2.5F); bodyCylinder.height.setValue(6); // Construct body out of parts SoSeparator body = new SoSeparator(); body.addChild(bodyTransform); body.addChild(bronze); body.addChild(bodyCylinder); body.addChild(leftLeg); body.addChild(rightLeg); // Head parts SoTransform headTransform = new SoTransform(); headTransform.translation.setValue(0, 7.5F, 0); headTransform.scaleFactor.setValue(1.5F, 1.5F, 1.5F); SoMaterial silver = new SoMaterial(); silver.ambientColor.setValue(.2F, .2F, .2F); silver.diffuseColor.setValue(.6F, .6F, .6F); silver.specularColor.setValue(.5F, .5F, .5F); silver.shininess.setValue(.5F); SoSphere headSphere = new SoSphere(); // Construct head SoSeparator head = new SoSeparator(); head.addChild(headTransform); head.addChild(silver); head.addChild(headSphere); // Robot is just head and body SoSeparator robot = new SoSeparator(); robot.addChild(body); robot.addChild(head);
Tip: When constructing a complicated scene graph, you may want to define the graph using the Inventor file format (see Chapter 12, Importing data) and read the graph from a file or from a string in memory. This approach can be easier and less error-prone than constructing the scene graph programmatically. |