Skip to content
This repository has been archived by the owner on Mar 28, 2024. It is now read-only.

[BUG-232445] Pivot point / prim hierarchy proposal feasibility discussion #9714

Open
sl-service-account opened this issue Aug 5, 2022 · 17 comments

Comments

@sl-service-account
Copy link

How would you like the feature to work?

Recent discussions at Creator User Group discussed adding adjustable pivot points to prims, to allow for more convenient rotation. That turns out to have enough side effects that it's worth considering going all the way to a hierarchy of prims. This JIRA is to turn that discussion into something actionable. Please comment.

Second Life only allows one level of child prims. Philip Rosedale has said that was his biggest design mistake when designing Second Life. So this note discusses what it would take to retrofit a general hierarchy to Second Life. This would allow child prims to have their own child prims. Each prim's position and rotation would be relative to its immediate parent. The root prim's position is relative to the region.

Interestingly, that's the way the UDP messages which send prim positions
to the viewer work now. Having been doing viewer work, I'm too familiar with this area. Objects are sent to the viewer using ObjectUpdateCompressedObjectData messages. These contain

local_id - the ID of this prim in this region (u32)
pos - position (vector)
rot - rotation (quaternion)
omega - optional rotation rate (vector)
parent_id - optional local ID of parent (u32)

This is sufficient to describe a hierarchy. A prim can have a parent_id which is not the root prim. Viewers already use this for 3-level hierarchies - seat, avatar, and attachment. While the C++ code in the viewer may need some minor work to handle the general case, this is almost implemented already.

That's the part that has to be most pervasive. All viewers have to handle the general case.

If you have a full hierarchy, you get the ability to changing a pivot point along with it. This is done by creating an "empty", an object with no visible faces. For example, when making a door, the "empty" would take the role of a door hinge, placed along the hinge line. The door itself would then be parented to the empty, with the appropriate offset.

Most graphic design tools such as Blender and Maya already understand such hierarchies. This is visual and easy for artists to understand. It beats messing with quaternions.

It's even possible to express an empty mesh object within the SL system, although the uploader may not currently allow it. Having one pre-built empty mesh object whose fixed UUID is known to the uploader could handle that. Just as there are a few pre-built textures such as "plywood", "white", and "transparent" whose UUIDs are well known.

So the part of this which affects non-creator users is not too difficult.

The LSL interface to a hierarchy creates some problems. There's enough expressive power in llCreateLink and llBreakLink to allow creating hierarchies. But the link number system, with all items in a link set being numbered in sequence, is a problem. Especially because some link numbers are special.

To retain compatibilty, it's probably going to be necessary to have two sets of link numbers, one for the whole linkset, and one for each prim's children. LSL calls such as llGetNumberOfChildPrims(), llGetChildPrim(N), and llGetParent will probably be needed. Existing linksets and their scripts should continue to work as before.

Anyway, this looks do-able at the message and viewer level. The server side will have to be examined by others.

Why is this feature important to you? How would it benefit the community?

There's been much recent discussion of adjustable pivot points for prims. This solves that problem. It simplifies doors, handlebars of bicycles and motorcycles, and anything else with moving parts. It also aligns the way SL does object hierarchies with the way almost all graphics systems do it.

The overall goal is that something built in Blender or Maya or a comparable 3D program should, when uploaded, look and work the same way it did in the creator program. This is one part of that. (The other part involves textures and shaders, a separate subject.)

Original Jira Fields
Field Value
Issue BUG-232445
Summary Pivot point / prim hierarchy proposal feasibility discussion
Type New Feature Request
Priority Unset
Status Accepted
Resolution Unresolved
Reporter animats (animats)
Created at 2022-08-05T00:31:12Z
Updated at 2022-08-31T21:11:48Z
{
  'Build Id': 'unset',
  'Business Unit': ['Platform'],
  'Date of First Response': '2022-08-05T09:27:27.044-0500',
  'How would you like the feature to work?': 'Recent discussions at Creator User Group discussed adding adjustable pivot points to prims, to allow for more convenient rotation.  That turns out to have enough side effects that it\'s worth considering going all the way to a hierarchy of prims. This JIRA is to turn that discussion into something actionable. Please comment.\r\n\r\nSecond Life only allows one level of child prims. Philip Rosedale has said that was his biggest design mistake when designing Second Life. So this note discusses what it would take to retrofit a general  hierarchy to Second Life. This would allow child prims to have their own child prims. Each prim\'s position and rotation would be relative to its immediate parent. The root prim\'s position is relative to the region.\r\n\r\nInterestingly, that\'s the way the UDP messages which send prim positions\r\nto the viewer work now. Having been doing viewer work, I\'m too familiar with this area. Objects are sent to the viewer using ObjectUpdateCompressedObjectData messages. These contain\r\n\r\n    local_id  - the ID of this prim in this region (u32)\r\n    pos - position (vector)\r\n    rot - rotation (quaternion)\r\n    omega - optional rotation rate (vector)\r\n    parent_id - optional local ID of parent (u32)\r\n    \r\nThis is sufficient to describe a hierarchy. A prim can have a parent_id which is not the root prim. Viewers already use this for 3-level hierarchies - seat, avatar, and attachment. While the C++ code in the viewer may need some minor work to handle the general case, this is almost implemented already.\r\n\r\nThat\'s the part that has to be most pervasive. All viewers have to handle\r\nthe general case.\r\n\r\nIf you have a full hierarchy, you get the ability to changing a pivot point along with it. This is done by creating an "empty", an object with no visible faces. For example, when making a door, the "empty" would take the role of a door hinge, placed along the hinge line. The door itself would then be parented to the empty, with the appropriate offset.\r\n\r\nMost graphic design tools such as Blender and Maya already understand such hierarchies. This is visual and easy for artists to understand. It beats messing with quaternions.\r\n\r\nIt\'s even possible to express an empty mesh object within the SL system, although the uploader may not currently allow it. Having one pre-built empty mesh object whose fixed UUID is known to the uploader could handle that. Just as there are a few pre-built textures such as "plywood", "white", and "transparent" whose UUIDs are well known.\r\n\r\nSo the part of this which affects non-creator users is not too difficult.\r\n\r\nThe LSL interface to a hierarchy creates some problems. There\'s enough expressive  power in llCreateLink and llBreakLink to allow creating hierarchies. But the link number system, with all items in a link set being numbered in sequence, is a problem. Especially because some link numbers are special.\r\n\r\nTo retain compatibilty, it\'s probably going to be necessary to have two sets of link numbers, one for the whole linkset, and one for each prim\'s children. LSL calls such as llGetNumberOfChildPrims(), llGetChildPrim(N), and llGetParent will probably be needed. Existing linksets and their scripts should continue to work as before.\r\n\r\nAnyway, this looks do-able at the message and viewer level. The server side will have to be examined by others.',
  'ReOpened Count': 0.0,
  'Severity': 'Unset',
  'Target Viewer Version': 'viewer-development',
  'Why is this feature important to you? How would it benefit the community?': "There's been much recent discussion of adjustable pivot points for prims. This solves that problem. It simplifies doors, handlebars of bicycles and motorcycles, and anything else with moving parts. It also aligns the way SL does object hierarchies with the way almost all graphics systems do it.\r\n\r\nThe overall goal is that something built in Blender or Maya or a comparable 3D program should, when uploaded, look and work the same way it did in the creator program. This is one part of that. (The other part involves textures and shaders, a separate subject.)",
}
@sl-service-account
Copy link
Author

Extrude Ragu commented at 2022-08-05T14:27:27Z

I've created complex vehicles in the past and doors that rotate around non-center pivot points, it's a bit of a pain to code once, but once you've done it once you can do it a thousand times easy by re-using the same code

In my opinion, just the ability to change the pivot point on it's own would not be a big enough usability improvement to warrant the effort put in.

What would make this nice is if we could then use key framed motion on those child prims.. ie implement a llSetLinkKeyFramedMotion, as that would then make it possible to do very complex object animations such as fairground rides where the animations are all client-side and the quality of which is not beholden to the users latency/packet lost

@sl-service-account
Copy link
Author

Qie Niangao commented at 2022-08-05T15:34:28Z

I haven't been following the "pivot point" discussions, but I'm pretty sure I have little use for static hierarchies defined in (the current crop of) external programs.

The relevant use cases most valuable to me all involve scripted motion. For that, it seems the changes could be isolated to the script library, introducing two constructs:

  1. an ephemeral subset of links that are to be moved as a unit for the scope of the function, and

  2. an arbitrary origin ("pivot point" and arbitrarily rotated coordinate system) about which motion of such subsets is defined.

    Notionally, then, nesting of these scopes defines a dynamically defined link hierarchy, only for the purposes of the script, rather than a static parentage tree of links.

    This wouldn't necessitate any changes to the viewer nor to the object representation. It's possible the internal representation of objects might change to facilitate the actual motion, but that's "merely" implementation.

    I understand that an extension to sim-viewer messaging could reduce the volume of updates, but that too might be achieved by sharing operations on these dynamically defined data structures rather than preloading static hierarchies for all linksets.

    It basically replaces a bunch of messy script code with library functions that can presumably be much more efficient.

    If KFM could use these ephemeral link subsets and origin-specified coordinate systems, it really would extend functionality beyond what scripts can achieve now, as Extrude Ragu suggests.

    If there's real value to supporting externally-defined hierarchies, I guess they could be referenced when specifying certain origins and link subsets, but I'd consider it a failure if the feature only supported such static link trees. 

@sl-service-account
Copy link
Author

animats commented at 2022-08-05T18:35:57Z

It seems the changes could be isolated to the script library, introducing two constructs:

  1. an ephemeral subset of links that are to be moved as a unit for the scope of the function, and

  2. an arbitrary origin ("pivot point" and arbitrarily rotated coordinate system) about which motion of such subsets is defined.

    Free LSL code for that exists. See:

    https://marketplace.secondlife.com/p/Fourmilab-Mechanisms/20515612

    It's complicated, but a solved problem if you want to do it that way.

    It doesn't help with building the thing in Blender/Maya/etc and having it Just Work.

     

@sl-service-account
Copy link
Author

JIRAUSER333921 commented at 2022-08-05T21:26:56Z

If this also opened up basic 'ragdoll' physics, or somehow allowed the import of (perhaps very simple) animations that don't use the SL skeleton, I could see it as a benefit.

I don't see how llCreate/Break link are sufficient for creating the hierarchies. as it is currently implemented CreateLink has a very penalizing 1 second built-in delay, and only specifies one target, so to create any interesting linkset you would need a script inside most of the linked parts. I'd preffer a llLinkParentChild(key parent, key child) perhaps with the caveat that one or the other (or both, if cyclic parenting is allowed) must be in the linkset containing the script. Also, a link search function llGetLinkKeyPath([1,2,3]), to get the 3rd link of the 2nd link of the root.

You might also need specialized handling for cyclic parenting (A parents B parents C parents A) or checks to ensure it isn't allowed.

Another point, if there are going to be 2 sets of link numbers (legacy link numbers to preserve old functionality) and 'new link numbers' it would be a good organizational habit to refer to 'new links' as something else to lower confusion. perhaps "RelationPaths" or something similar.

@sl-service-account
Copy link
Author

animats commented at 2022-08-05T21:59:33Z

I don't see how llCreate/Break link are sufficient for creating the hierarchies

Probably you'd usually create the linkset and parenting in Blender/Maya, which you can do now. Then upload it to SL and have the same relationships in SL, which you can't do now. Fussing with links dynamically is for picking up stuff with cranes and such.

Another point, if there are going to be 2 sets of link numbers (legacy link numbers to preserve old functionality) and 'new link numbers' it would be a good organizational habit to refer to 'new links' as something else to lower confusion. perhaps "RelationPaths" or something similar.

I'd suggested llGetNumberOfChildPrims() and llGetChildPrim(N), but I have no strong preference.

cyclic parenting ... checks to ensure it isn't allowed.

Cycles wouldn't work. The viewer has to compute the prim position, working outward from the root, and a cycle will make position ambiguous. Has to be a simple tree. No multiple parents (which creates what theory people call a "directed acyclic graph") either.

@sl-service-account
Copy link
Author

OptimoMaximo commented at 2022-08-06T12:54:17Z, updated at 2022-08-06T12:54:50Z

Anything that would close the gap between SL and any 3d app is welcome and highly desirable. A DAG system aka directed acyclic graph is what should be aimed, also because that would open the way to REAL instancing, which is one of the benefits of DAGs.

 

@sl-service-account
Copy link
Author

Qie Niangao commented at 2022-08-06T21:13:44Z, updated at 2022-08-06T21:14:02Z

Free LSL code for that exists.

The point was to get it running inside the script library itself, saving memory and presumably running an order of magnitude faster, as well as the huge lump of syntactic sugar it would provide.

It doesn't help with building the thing in Blender/Maya/etc and having it Just Work.

Again, I'd hate to be hobbled by a strictly static hierarchy as defined by popular modelling tools.

Or at least it's my assumption that those hierarchies would be static upon import, not subject to being rearranged with llBreak-/CreateLink. If instead SL is going to do surgery on those model hierarchies the way it can with linked prims and component meshes, then we're really only talking about complementary approaches to implementation. (And if it won't be doing such surgery, there's another layer of complexity in this LSL integration, and a need to selectively nerf all viewers' Build Tools.)

Anyway, regarding complementary implementations: A tree is a sequential nested partitioning of a set of nodes, right? so for our purposes, we might identify a node for the purposes of referencing that subset of nodes defined by the branch under that node, usually to move that subset as a unit. That's the whole point of these hierarchies, right? So the question is how that subset comes to be defined, and how operations about it are programmed in LSL and communicated to the viewer. (Also operations within the viewer's Build Tool, whatever those may be for the imported branches of the tree.)

I'm trying to get some benefits without needing to first coordinate simultaneous changes across simulator and all viewers to even display the content. Later there could be efficiency improvements by incorporating the link subset operations into messaging, but at least the content could be visible before every viewer has made changes.

So I'm proposing to preserve and operate on the current link vector representation but introduce partitioning of that link set by identifying subsets on which operations are performed. Those subsets certainly could originate with a tree, analogous to how LISP operated on complex graphs defined on simple lists. To import externally constructed models, the process of exposing the originating tree for reference in LSL might differ: I'd create a separate data structure that "could be referenced when specifying certain origins and link subsets" predefined in those trees; that might be isomorphic with the Child and Parent operations proposed here.

Either way, though, we must be able to redefine those subsets / parenting relations, at least outside any limits of imported content.

@sl-service-account
Copy link
Author

animats commented at 2022-08-06T22:53:49Z

It helps not to over-complicate this. The viewer has to deal with this on every frame. There are lots of nice to have features, from real flexibility to closed kinematic chains. Something that retains backwards compatibility with the message protocol and existing content is more likely to be implemented by LL.

@sl-service-account
Copy link
Author

Qie Niangao commented at 2022-08-07T07:53:34Z

Something that retains backwards compatibility with the message protocol and existing content is more likely to be implemented by LL.

Definitely agreed on that.

I'm reasonably convinced that the same LSL semantics can manipulate within the structure of a mesh model and across multiple linked meshes and/or prims, and we can insert and operate on these "empty" pivot points in linksets. And it's probably unavoidable at this point that internal mesh structure is immutable once imported, so the best we can hope for is to puppeteer their existing structures, accepting that llCreate-/BreakLink will just silently fail when called on those mesh-internal structures.

Until viewers are updated to use the new link hierarchies they'll do fairly silly things with that existing messaging, but they couldn't do anything within the mesh blobs before, so that's maybe not such a big drawback. Existing scripts that manipulate linksets will do silly things, too, when some links are replaced with hierarchically-aware elements, but "silly" may be an acceptable level of backwards compatibility for such cases.

@sl-service-account
Copy link
Author

animats commented at 2022-08-10T03:54:44Z, updated at 2022-08-17T20:35:32Z

Notes to flesh this out a bit. Please discuss and criticize.

Prim numbering.

These changes can't change prim numbering for existing link sets. 
Here are the known constraints:

  • Link numbers, as seen by LSL scripts and the viewer's editor, start at 1. Link #0 means the entire link set.

  • Sitting on a prim in a link set causes the avatar to be temporarily added to the end of the link set for LSL purposes. LSL can see avatars as links but the viewer's editor does not show them as part of the link set.

  • There are never gaps in link numbers. Multiple avatars sitting and standing will cause the avatar's link number to change.

  • The sitting process looks at sit targets which are properties of the prim. But the seated avatar is a child of the root, not the prim upon which it is sitting.

  • Moving a child prim on which an avatar is seated will not move the avatar. Moving the entire linkset will move the avatar.

    All those properties must be preserved for existing flat link sets, where child prims have no children. Is there anything else that has to be preserved?

    Rather than having two sets of link numbers, old and new, it's probably simpler to  just have the link numbers be what you get from walking the hierarchy tree.

    Like this:

        - Root prim (Link #1)
          - Child (Link #2)
          - Chlld (Link #3)
            - Child of child (Link #4)
          - Child (Link #5)
    

    The link number comes from walking the tree, depth first. Seated avatars are added at the end. This is compatible with the current system.

    Avatars are special. Avatars have to be added at the end. And, currently, they are all tied to the root, regardless of where they sat. Currently, if you seat an avatar on a child prim, and move that prim relative to the root, the avatar does not move. 

    Do we want, or can we have, avatars as children of child prims?  That would be nice for multi-car trains, etc, where the prims in a linkset move relative to each other but you can't sit and follow seats in later cars of the train, where the train is a ilnkset.  Unless someone sees that this is easy to do internally server side, it's probably too much trouble.   It adds considerable complexity. The machinery associated with sitting would need changes. SL already has good multi-car trains. (I recommend the ones of Valkyrie Transport, at Lexicolo, as examples.)

Creating and editing prim hierarchies

The general idea is that it should be possible to upload a linkset from Blender/Maya/etc and get a matching hierarchy in SL. Again, the overall goal is build, upload, get what you built without much fussing within SL.

Edit menu editing can use the existing edit menus. Going through the link numbers one at a time walks the hierarchy tree. But that may be a bit confusing. A display of the hierarchy tree in the viewer would be nice, but is not essential as an initial feature. Eventually it should probably look like all the other folder-type hierarchy displays. 

Building a hierarchy manually with select child, select parent, CNTL-L should work. If you select a non-root prim as the parent and create a link, you get a hierarchy, reasonably enough. 

Applications

Hinged doors

One of the most straightforward ways to do a door with this system is to have a "hinge" object. This could be a visible hinge or hinges. Make the hinge a child of the building, placed on the desired axis or rotation. Make the door a child of the hinge. The hinge handles the scripted movement. Creators could, and probably would, sell scripted hinges, with or without doors.

The hinge could be an "empty", if uploaded that way, but there's an argument for having a visible connecting object, so you can find it for selection.

Steered vehicles

Vehicles where the wheels both point and rotate are difficult in SL. With a hierarchy, they become much easier. The wheels rotate on their axles, and the axle positions are set by the steering script.

This is also useful for semitrailers with openable doors, which currently have to be done by showing and hiding open and closed doors.

Machinery.

Anything with coordinated moving parts is tough in SL. This makes it much easier.

Script compatibility

It's essential that existing scripts work for existing objects. That should not be a problem with this design. Some scripts which now work on any linkset, such as resizing scripts, may need some rework to work on hierarchial linksets.

Proposed LSL changes

New tags for llGetLinkPrimitiveParams:

  • [ PRIM_NUMBER_OF_CHILDREN ] integer  – number of direct children of this link 

  • [ PRIM_CHILD_LINK ]   integer  – Link number of Nth child of this link

  • [ PRIM_PARENT ] integer  – link number of parent link. 0 for root prim. 

    (Should "Nth child count from 1 or 0? Prims count from 1, but there is no such thing as the zeroith child. No opinion.)

    This is enough to allow scripts to find their way around the hierarchy.

    That seems to be all that's really needed. Can anyone think of something you can't do with those and the existing LSL calls?

Limits

The current linking limits and linkset diameter limits should not need changing. There's no obvious way to create more trouble with this than you can now.

Physics

Same as at present. The linkset is one rigid object for physics purposes. It changes shape if you move a child prim, as it does now.

Expected problems

  • Scripts dropped into link sets to resize them may need to become hierarchy-aware to work on new objects.

  • Some user confusion when manually linking results in a messed up hierarchy. (An argument for showing the hierarchy as a tree in edit.)

    What else?

@sl-service-account
Copy link
Author

Kelly Shergood commented at 2022-08-10T15:31:34Z

I agree this would be a great addition, and would also help reduce script complexity and run time by eliminating the need for scripts to explicitly calculate the positions of prims when scripting an articulated object.  I do think allowing avatars as child prims would be critical to make this idea fully useful.  In addition to the examples previously mentioned, some additional examples where avatars as child prims would be useful include:

  • An avatar sitting in a "cherry picker" on the end of an articulated arm.

  • An avatar in a harness, basket or swing, swinging from a cable.

  • A monster with arms that "picks up" and "eats" an avatar (the monster could use llSitOnLink).

  • An avatar using a "child vehicle" of another vehicle.  For example a medical helicopter with a linked stretcher that can be pushed around by an avatar.

    If avatars were excluded from this feature change, then scripts such as those above would need to continue to do the same calculations for the avatars.  This would mean they would not benefit from the complexity and run-time reductions of the hierarchical link-set.

@sl-service-account
Copy link
Author

animats commented at 2022-08-13T03:16:42Z

Shergood, whose helicopters do most of those things, is asking for something SL ought to have. The problem is, it involves modifying the "Sit" machinery, which is known to  be fragile. Sitting interacts with animation, region crossings, and permissions. There are many known problems in those area. Some of those problems are timing dependent.

Think of hierarchical links as a first step. That's a more isolated part of the system. If we ask for too much at once, nothing will get done. It's a step towards doing linksets the way everybody else does them. It brings us closer to GLTF/USD compatibility.

(A general approach would be to generalize "sitting" into "connecting", so that one could connect  objects to other objects without the linkset requirement that they have common ownership. This would allow vehicles to carry more things. Trucks could carry cargoes. Ambulances could carry stretchers with or without avatars. Ferryboats could carry cars.  Shopping trolleys could carry items bought in stores. GTFO trucking could deliver non-copyable items from BeYou to buyer's homes. Since anyone can move physical objects, allowing connecting of physical objects is safe from a permissions standpoint.  As with sitting, connecting something would make it be rigidly attached to the parent object.

That's a bigger effort and needs to be a separate proposal.  Implementing hierarchical links brings it closer.  One step at a time seems appropriate.)

@sl-service-account
Copy link
Author

Kyle Linden commented at 2022-08-17T19:09:06Z

We're leaving this open another week for continued conversation.

@sl-service-account
Copy link
Author

animats commented at 2022-08-23T18:49:53Z

Question: if you add pivot points without a hierarchy, does the server to viewer message format have to change? The viewer needs to know rotation axis for viewer side rotation (llTargetOmega).

@sl-service-account
Copy link
Author

JIRAUSER334703 commented at 2022-08-24T02:41:39Z, updated at 2022-08-24T02:45:10Z

This is absolutely needed and should have already been a thing by now. It would allow so much more flexibility and ease of building complex builds with rotations and such as well. Many benefits to this all around. 

 

Additionally, in future when supporting GLTF if you can manage to support uploaded offset origins then that would be great as well.

@sl-service-account
Copy link
Author

Tech Robonaught commented at 2022-08-24T03:01:04Z

This would change the way everything is done and make scripting much more efficient.

@sl-service-account
Copy link
Author

JIRAUSER341268 commented at 2022-08-31T21:11:36Z

Hi animats,

Thank you for the feature request! We may implement some version of this at a future date.

Please watch future release notes to confirm this feature has been delivered.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant