Arms and legs are modeled using a single cylinder primitive. The primitive should be positioned with its point of attachment at the origin when applying the joint rotation. However, the cylinder obtained with makeCylinderGeo() creates a vertical cylinder (along y), and puts the origin at the center of the object. So, it would seem like creating a Transform Node that translates the cylinder by half it's length and then rotates into the base pose (horizontal for the arms) would be the way to go. However, sharing nodes between multiple parents is not allowed in OpenSG. Only cores may be shared.
Two approaches were taken in this example: 1- creating separate Transform Nodes with a child Geometry Node, and 2- performing the placement when the articulation is applied, using an untransformed Geometry node. A single Geometry core was used for all of the leg and arm segments.
For the arms, a separate Transform Node was created for each segment, the Transform placing the arm's end at the origin, with the rest of the cylinder extending along +x or -x depending on if it is a left or right arm segment. This makes the articulation transformation simple: rotate the object about the origin by the joint angle, and then move the origin (attatchement point) to its position relative to the parent node.
For the legs, the second approach was used. The link body for the leg segments are modeled using a
Geometry node referencing the shared Geometry core.
The articulation transformation is then made more complex, by the need to first
position the cylinder with it's end at the origin, then rotating by the joint angle,
then moving the attachment point to its location relative to the parent.
Since the parent of the lower leg segment has its origin at its center, this final translation
is by half the cylinder length, instead of the full cylinder length as might be first thought.
