Prim and Object Hierarchy
This article is a feature request
Linden Lab position on object/model hierarchies
In the Google video presentation Glimpse Inside a Metaverse: The Virtual World of Second Life at 30:11 to 31:00 Phillip Rosedale says that one of the first design decisions he made when Second Life was first created, was that skeletal models and object hierarchies would not be implemented.
Cory Ondrejka and Philip both agreed that this was a "blunder" or mistake, and Philip stated that adding object hierarchy was needed. (Transcript extract)
The principle
One of the greatest constraints in SL is that there is no hierarchical object composition: you cannot buy two opaque objects X and Y and create a composite object Z out of them, which can then be used as a component object by someone else.
Object composition is the bedrock of engineering and the key to exponential progress. Without it, all products are limited by the capability of individual producers working from raw materials instead of from pre-existing components. In other words, there can be no riding on the shoulders of giants. Instead of building an ever-rising pyramid, all growth is in breadth-only, always out of raw materials, so progress is severely limited.
Support for hierarchical object composition needs to be added at an infrastructure level: this means being able to create, refer to and manipulate a composite object as if it were a monolithic one, as well as arranging its constituent parts internally as required. SL currently supports only linking of primitive objects, not hierarchical object composition. Linking is severely limited as it cannot build a new component out of existing components, except as unhelpful captive objects.
The problem of lack of hierarchical composition is often illustrated through the need for hierarchy in jointed constructs. It is however far more general than that, and applies equally well to any construction in which one or more discrete inner objects are components of an outer one, recursively.
The problem
Lets say that in SL we would want to make a human skeleton. When we want to do such correctly, we need to think about the bones and how they work together. Very soon we realize that if one bone moves, the bones which are connected to it and the bones connected to them, will follow the movement. Of cause, in the real world, this is only logical, but with a computer, this is a different story. It actually needs program code to make sure that the bones of the wrist, hand and fingers move along if the arm moves. When you think about it, you see that the upper arm depends on the movement of the shoulder; the lower arm depends on the upper arm; the wrist depends on the lower arm, etc.. Clearly, there is a relation between these bones. This relation is often referred to as child and parent. The shoulder in this example is the parent for the upper arm. The upper arm is itself then the parent to the lower arm, which is the parent for the wrist bone.
In SL there is not such a relation between prims. It is possible to put several prims together in a set of linked prims, but if we would want to make something which needs a child-parent relation between prims, then the designer of the object needs to do this him or herself in LSL code, which is a difficult job that takes a lot of time and adds some extra code which makes the script less maintainable.
The solution
The solution is probably fairly easier for the user to understand than it is to make the changes to the viewer and server. For an easy solution, a prim could receive an extra flag indicating that it acts like a bone. If this flag is set (the box is ticked), then the prim has a few extra properties. Among which are a parent prim and child prim, but both are optional. In script some extra commands would be available:
prim llGetPrimParent(prim p); // This returns a pointer (be it a key, name or other) to the parent of the given prim. integer llGetPrimChildCount(prim p); // Returns the number of child prims linked to the given parent. prim llGetPrimChild(prim p, integer n); // Similar to llGetPrimParent(), but returns a pointer to the n'th child. llSetPrimParent(prim child, prim parent); // This command takes two prims and links them by way of script. This is usefull for prims that are rezzed by script. // This sets the parent of the given child prim. Of cause it also sets the child of the given parent to the given child. llAddPrimChild(prim child, prim parent); llRemovePrimChild(prim child, prim parent); // Adds or removes a given child prim to the given parent prim. This seems to do the same as llSetPrimParent, // but there is a subtle difference. While a prim can only have one parent, it can have multiple children. // It is true that these can be used for most of the linkage, but the first prim in a chain never has a parent and to set this, // llSetPrimParent() is needed. llSetJointRotation(prim p, rotation rot); // This would set the angle between the given prim and it's parent. Thereby rotating it around the point where it meets it's parent. llSetSkinPoseRotation(prim p, rotation rot); // This would set a special angle value for the joint. It is called the skin pose, which is the rotation of the joint in a rest. // One might see the skin pose as the initial rotation or a rotation where you want the joint to reset to. llSetSkinPoseRotationAndPosition(prim p, rotation rot, vector pos, bool StretchConnectedPrims, bool MoveConnectedPrims); // Sometimes, it might be needed to also set the position of a child prim and stretch or move other prims accordingly. llSetSkinPose(prim p); // This is a command travels through the entire hierarchy and resets all the joints to their skin pose. // This should be just a bit faster than explicitly setting each joint to its skin pose from a script loop. llSetJointOmega(prim p, vector v, float speed, float time); // Like llSetTargetOmega(), but this one takes into account, the rotation of all the child prims. // By keeping two different commands for this, and the parent-child relationship needing probably a lot of extra code, it is // probably better to keep the function this one offers seperated from the existing llSetTargetOmega().
More such commands could probably be invented. This allows for easy multi axis rotation of objects like disco lights and lots of other designs which need extra flexibility. -Xoren Raymaker