Difference between revisions of "Talk:LlSetKeyframedMotion"

From Second Life Wiki
Jump to navigation Jump to search
m (→‎MINIMAL TIME: new section)
(Explanation of how to "animate" a keyframed object.)
 
(One intermediate revision by one other user not shown)
Line 179: Line 179:
Script warming errors indicate that minimal value for time is to be > 0.1 seconds.
Script warming errors indicate that minimal value for time is to be > 0.1 seconds.
Not clear what >0.1s means exactly since according to test the minimal value is 0.112 in an empty sim with zero lag.[[User:Sigma Avro|Sigma Avro]] 12:50, 12 August 2012 (PDT)
Not clear what >0.1s means exactly since according to test the minimal value is 0.112 in an empty sim with zero lag.[[User:Sigma Avro|Sigma Avro]] 12:50, 12 August 2012 (PDT)
Not sure where it becomes 5/45 in the programming, but it was likely originally written as 0.1 and becomes 5/45 due to per-frame rounding. Either that or it was written and always had been 5 frames, and someone thought it was simpler to make the error say '0.1'.  [[User:Acheron Gloom|Acheron Gloom]] 14:11, 12 August 2012 (PDT)
== Moving linkset while animating ==
Attempting to modify the any prims of a linkset while it's playing a keyframed motion will result in the following error:
'''Cannot use a script to move a linkset while it is playing an animation.'''
I was surprised had not only not been documented, but had no workaround mentioned. In my examination, this function can potentially be used as a sort of "pathfinding lite," or a replacement when dynamic pathfinding is unavailable. As such, it would inevitably used for some critter that needs to play some sort of prim-based animation while sliding along. I've updated the main page with my findings and solutions, but I wanted to mention them in more detail here.
First, the keyframed motion can be paused by calling:
<lsl>llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_PAUSE])</lsl>
Easy peasy. This also works in a second script, if for some reason you can't call it from the original script. Keyframed motion is like particles and hovertext in that it's a prim property, and any script can modify the prim properties without knowing what other scripts are up to. The empty keyframes list doesn't actually clear the keyframes stored.
Restarting the keyframed motion is done with this command:
<lsl>llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_PLAY])</lsl>
But be careful! If you've previous called the function with two blank lists to "stop" the motion entirely, this will restart it. It looks like two blank lists is merely a shortcut to pausing, not a termination and clearing of the keyframe list.
Second, for the actual "animating" of your critter. You'll want to use [[llSetLinkPrimitiveParamsFast]]. Since your goal should be not to interrupt the smooth movement (unless it's not your goal) you should lump all of your prim shifting into one call using [[PRIM_LINK_TARGET]], making one list with all your property changes for all prims. Once the list is compiled, pause the motion, call the llSLPPF function, and restart the motion. In my testing, if this all manages to happen in one frame, the motion will not even be interrupted and remain smooth.
Hopefully this helps someone else who was in a similar spot as me, and found themselves encountering an unexpected error. --[[User:Stickman Ingmann|Stickman]] 10:44, 18 June 2013 (PDT)

Latest revision as of 10:44, 18 June 2013

Animation Types

Instead of setting integer Loop, let's reuse animation flags that was built for llSetTextureAnim function as list to combine flags usage.
LOOP REVERSE PING_PONG SMOOTH ROTATE SCALE and maybe add another flag POSITION(0x80)?


LOOP
Starts from the beginning to the end and returns back to the beginning to start again.
REVERSE
Played backward in following order of the list.
PING_PONG
Starts from the beginning to the end and play backward back to the beginning to start again.
SMOOTH
Could be used as another suggestion between sliding to the next target instead of "llSetPos"-like frames.
ROTATE, SCALE, and POSITION
Allow user to trim list down a bit without the needs to add all three at the same time. (Might be a wishful thinking though.)

Generally allow users to develop system that could have more than one LlSetKeyframedAnimation function call, long as it's not using same axis/scale/position again, which overrides the first of that same flag. One function call use position and second function call use rotation and scale for a type of event call.

I must point out a discussion about stopping, how do to about it. At the moment, suggesting use STOP(0x00) with combination of any flag from above? --Nacon-tag.jpg 03:07, 31 August 2011 (PDT)

These are great suggestions. I'd make a few tweaks, though:
  • Only LOOP, PING_PONG, and maybe REVERSE make sense here (SMOOTH is implicit in the way keyframing works--it is always a smooth interpolation)
  • ROTATE and TRANSLATE make sense and are a good way to reduce the size of the lists required. However, it would not be feasible to support multiple merging the keyframe sets from different calls (e.g., one call with ROTATE and one with TRANSLATE)
  • SCALE is not possibly to implement for physical objects in a way that ensures satisfactory performance. Modifying the scale of a physics shape requires (in simplified terms): (1) rebuilding the shape from scratch, (2) removing the object from the world, (3) applying the new shape to the object, and (4) adding the object back into the world. #1, 2, and 4 are all expensive operations.
To stop the animation, you could simply pass in an empty list of keyframes.
Falcon Linden 19:11, 6 September 2011 (PDT)
As to how to supply these to the function, how about [..., ANIM_FLAGS, integer flags, ...]. -- Strife (talk|contribs) 11:01, 8 September 2011 (PDT)
About SMOOTH, I simply meant when it's not flagged to have SMOOTH, it would just skip straight to the next frame, no animating between the two frames.
As for ROTATE and POSITION(TRANSLATE), treat them separately instead of merging them as one. Which also would cut down the list further when you don't have to have a data at fixed "frame" from where they should perform.
I knew SCALE was a wishful thinking... Maybe only applied to phantom/attachment/hud prims, where physic doesn't apply? People are gonna want something like this for visual display. --Nacon-tag.jpg 09:35, 26 September 2011 (PDT)

Interpolation

I've got a couple ideas for interpolation:

  1. Separate flags for configuring interpolation mode for position and orientation parameters. Defaults being LERP and SLERP respectively. Also some flags that provide smoother acceleration.
  2. Allow the user to instead of supplying a vector or a rotation parameter in the list to supply a float, which should be in the range [0, 1] indicating a proportional interpolated position/orientation between previous and future frames. aka B-Frames
    • So [<0,0,0>, <0,0,0,1>, 0.0, 0.25, 0.0, 0.5, <4,0,0>, <0,0,0,1>, 1.0]
      • So by 0.5 seconds, the position is only <1,0,0> not, <2,0,0> and by 0.75 seconds it would be at <3,0,0>.
    • There is no real reason to restrict the user to the [0, 1] range, and the user may want to overshoot the end so they can mimic oscillating about the end point before reaching it (and having to calculate out the frames).

-- Strife (talk|contribs) 11:01, 8 September 2011 (PDT)

Hey Strife,
Your suggestion has some merit, but also comes with a few major drawbacks:
  1. It makes the list more confusing to understand (and more error-prone to process)
  2. It significantly complicates interpretation and processing of the keyframes (which, right can, can be almost directly passed to Havok for application to the physics body)
  3. It's just plain harder to implement. This is important because, most likely, if this method comes to fruition, it will be implemented exclusively by yours truly and exclusively in my free time (aka when I'm not working on something else at LL and/or on weekends/evenings.) Since I'm only willing to give up so much of my free time to developing these features, we need to keep them as simple as possible. :)
Also, it's worth pointing out that accelerations will always be infinite or zero. That is, the object will always have constant linear and angular velocity and it will switch to new linear/angular velocities in a single simulation frame (aka infinite acceleration). Doing it any other way would remove all benefit from using Havok's keyframing system and would be equivalent to implementing a full-blown object animation system (which is not currently feasible). Surprisingly, I discovered that for reasonable velocities, these limitations don't have any noticeable visual artifacts.
All that said, it is possible that such a feature could be added in the future given the flexibility of the options list parameter.
Falcon Linden 18:51, 8 September 2011 (PDT)
No sweat really, it can be done by preprocessing the list in user code. -- Strife (talk|contribs) 19:19, 8 September 2011 (PDT)
You may want to take a look at SCR-373 ; bezier curves are by far my favourite method for creating custom smoothed motion between two keyframes, and could significantly reduce the number of keyframes required by more complex animations. I've been using them for some time now in CSS3 and it's just so much easier to manage, and actually really easy to implement.
-- Haravikk (talk|contribs) 04:56, 22 July 2012 (PDT)

KFA_DATA

I'm thinking that if KFA_DATA is required, than it shouldn't be part of the options but a function parameter. Does it need to be explicit? It could be inferred from the types in the list but that limits future syntax changes. On the flip side having it in the options simplifies serialization as you can then store them in the same list as opposed to a separate variable that must be (de)serialized along with the lists.

-- Strife (talk|contribs) 11:14, 16 September 2011 (PDT)

some thoughts

just heard about this, sounds really nice, a few thoughts came up when it got mention on the forums...

"Animation" seems kinda misleading to what it does as when on think 3d they tend to think of animation more like changing the relation of multiple parts, I suggested "Motion", Kaluura suggested "Target". mostly minor either way as long as it does what's expected of it.

Kalurra mentioned a callback, although I suppose the "Target" functions could work for that, they are all global, which both limits the use of the function and forces extra calculations to get the global frame.

and finally a minor tweak, allowing blank list items to be cast as the appropriate "zero", so that the list is more collapsible for items that don't change during a frame... that would allow the structure to be retained, but be less overhead for the script (I think).
-- Void (talk|contribs) 23:30, 17 September 2011 (PDT)

llSetPrimitiveAnimation()

Just heard about this via SCR-203, and wanted to point to an older issue of mine in the form of SVC-347, in case it has anything that needs considering, though this function proposal seems like it may be a better format overall.

I wanted to add that with regards to the timing restriction (no translations faster than 0.1 seconds), surely this restriction could be relaxed if the effect were somehow designated as client-side only, since client-side animation is the more desirable case for a lot of applications that would otherwise be very wasteful if done on the simulator-side. In particular, a lot of current animating objects such as prim NPC's could be replaced with a suitable prim-animation feature, however there wouldn't be much point if the simulator-side is still a bottleneck for lag, as even without the script-delay issue any network lag could still mess up effects. Related to this is the consideration of synchronising time features, both for simulator-side and client-side effects, as per SCR-13 and SVC-4897, as this could give us a better idea of what state the animation will be in at a particular moment.

Lastly, one other useful addition may be a PAUSE command that can set the object to a specific keyframe, or a LOOP_UNTIL or some such command; since a script cannot guarantee the state of the animation since 5 seconds of animation and 5 seconds of script wait or timer-delay may not always coincide as closely as expected.
-- Haravikk (talk|contribs) 12:06, 20 September 2011 (PDT)

In particular, what I'd like to see is the use of LOOP, PING_PONG etc. within the key-frames list. As these are integer constants it should be perfectly safe to do as the keyframes themselves are vectors and/or rotations and floats. In this way, if an integer is encountered, then it will simply set a new state for the rest of the animation. This could potentially be done using a bit-filed like so:

<lsl>llSetKeyframedAnimation(

   [
       COMMAND, PLAY, // Start the animation
       FLAGS, SMOOTH | EASE_IN, // Set flags for all following key-frames to use smooth interpolation, and "ease-in" (decelerating movement)
       LOOP, 3, // All following key-frames will loop a total of 3 times
           <0, 0, 10>, ZERO_ROTATION, 5.0, // Move up 10m in 5 seconds
           <0, 0, -10>, ZERO_ROTATION, 5.0, // Move down 10m in 5 seconds
       PING_PONG, 2, // End of previous loop, all following key-frames will ping-pong a total of 2 times (frames will play forward, then play back, then stop)
           <5, 0, 0>, ZERO_ROTATION, 1.0, // Move right 5m in 1 second
           <-5, 0, 0> ZERO_ROTATION, 1.0, // Move left 5m in 1 second
   ],
   TRUE // Animation is performed client-side only

); llSleep(60.0); llSetKeyframedAnimation([COMMAND, PLAY], TRUE); // Play the animation again client-side</lsl>

Either that, or a key-frame constant can be used, with two choices, so that one constant may be used to specify a short-hand keyframe (vector only or rotation only) or a full keyframe.
-- Haravikk (talk|contribs) 12:20, 20 September 2011 (PDT)

TRANSLATE: Regions or Local?

Starting to realize that we also might need an integer to set this Local or not. Any thoughts? --Nacon-tag.jpg 13:18, 4 November 2011 (PDT)

The problem is what happens when you add in KFM_ROTATION? Unless you have sat down and solved the equations for the movement, you won't know where your prim will end up. What you really want is the movement to be local to some starting rotation, not a continuously changing rotation. For the sake of everyones sanity (especially the implementors) there should be a [KFM_SHIFT_ROT, rotation rot] and [KFM_SHIFT_POS, vector pos] flags to allow the user to shift the entire animation, otherwise you have to translate ever single frame in the list if you want to tweak it... not fun. -- Strife (talk|contribs) 16:58, 5 November 2011 (PDT)
Yes, it's not easy but I would personally would want that option. KFM_SHIFT_POS and KFM_SHIFT_ROT sounds like a great idea than adding a integer. --Nacon-tag.jpg 12:47, 8 November 2011 (PST)
I like this idea. Please file a jira feature request and mention this post so it can be assigned to me. I will try to implement it when I have time, but no promises on when that might be. I wonder, though: perhaps a more general method list llTransformList(list pointsAndRotations, vector translation, rotation rot) would be more widely useful at the cost of some script memory?Falcon Linden 12:01, 22 November 2011 (PST)

Ok, I was slightly misunderstanding the Shift suggestion and came to realize that it isn't going to solve most problems for those who wanted absolute coordinates. I honestly wouldn't want shifting the set around by local coordinates, could make LSL writing more complex as it is when making correction due to prim drifting in 45 FPS over time. --Nacon-tag.jpg 13:27, 22 November 2011 (PST)

I must apologize, I have been unable to get in-world to do my own testing. So my knowledge is derived from the documentation and stale first hand experience from over several years of SL experience. After watching Moving Platforms, Carousels (llSetKeyframedMotion) I now have a better understanding of how the function is implemented. I realize now my previous suggestion was not well informed.
I wonder why I didn't see this earlier, by describing the frames as changes in position/rotation over time, drift is inevitable. The problem is that the vectors & rotations are made of floats, the components of positions look like floats but they lack the precision (even if they didn't there are rounding issues with float math). So the translation from change in position to global position results in the rounding to a valid position. Since everything is local to the previous frame, it compounds.
There are three ways to implement this:
  1. Simulator global coordinators
    • Drift is limited to rounding the positions to valid positions, a frame may drift but it won't compound
    • Requires the script to recalibrate the animation when the object is rezzed or risk flying off very quickly.
    • llTransformMotionList gets used during every call.
  2. Describe frames as changes from the previous frame.
    • Drift compounds.
  3. Coordinates local to starting position. (as changes from the starting position)
    • Drift is limited to rounding the positions to valid positions, a frame may drift but it won't compound
    • No recalibration needed when rezzing
    • llTransformMotionList is really only needed to full on edit the animation, not during regular use.
Implementation 3 gives an added bonus: If you decided to write an editor/script that translates Implementation 2 animations into Implementation 3 animations, you can see the drift and correct it.
I hate to say this but rotation drift is going to be a bigger issue than position drift. Quaternion multiplication is not pretty. -- Strife (talk|contribs) 22:43, 26 November 2011 (PST)

Playback speed

[KFM_SPEED, float speed] default value for speed is 1.0, this way you can slow down or speed up the animation. Not sure if this should instead or as well be a feature of llTransformMotionList. Easy to implement, just multiply speed by frame duration. Pretty sure negative speed should not be allowed. Negative speed either means reversing the change in position vectors or playing the animation in reverse, and I don't know which. -- Strife (talk|contribs) 22:43, 26 November 2011 (PST)

s are described by values that are in a set.

Queuing frames on the fly

Lets say you were using this for a train, and you want to be able to flip switches to change which track the train goes down. When you flip the switch you need to update the keyframed motion without stopping the train. What you really want to do is dynamically add frames onto the end of the animation so that when you get close to a switch (llTarget?) you read the switch and add on the extra frames. This usage could be added with a new flag KFM_CMD_QUEUE. Queuing would imply that old frames that have been processed would be discarded at some point, it would be a memory leak otherwise. With queuing you can really only do KFM_FORWARD or KFM_REVERSE, it's too complicated to do either kind of looping. For queuing you really need success value to be returned by the function. Maybe it should be a separate function: integer llQueueKeyframedMotion(...). -- Strife (talk|contribs) 22:43, 26 November 2011 (PST)

external linking?

seems like a bad idea to link to forums threads which are historically unstable in their address... shouldn't we just quote the source and leave it at that?
-- Void (talk|contribs) 20:20, 18 November 2011 (PST)

Is the new forum that hard to link into? -- Strife (talk|contribs) 20:52, 19 November 2011 (PST)

not hard per say, but not exactly stable either. Previous links to the official forums have been broken (as well as much of their script related content), and even in the current software, pathing of links is tied to forum and section names (which have changed majorly at least twice in this software) rather than post ID. my concern is that the information it's supposed to point to will get lost along the way, and in this case, is already duplicated (except for the source, Falcon), which seems to be the point of the link
-- Void (talk|contribs) 21:53, 22 November 2011 (PST)

Normalized rotation

I just noticed the optimization and helpful comment that Strife added to my note regarding normalized rotations on the Rotation page elsewhere in the wiki. This is one of the cases that I had in mind as I wrote that little section. In trying to resolve a question about KFM in the LSL Forum, I discovered that llSetKeyframedMotion sometimes spits out an inscrutable run-time error message unless you feed it normalized rotations. The example here is one such case. Thanks to Strife. I replaced my original user-defined function with the more compact version that he substituted on the Rotations page. Rolig Loon 13:34, 12 February 2012 (PST)

You're welcome :) I've been watching this unfold, sounds annoying. Please keep us up to date on changes to this. -- Strife (talk|contribs) 21:45, 12 February 2012 (PST)
P.S. Once upon a time I put in a feature request for Quaternion-Float multiplication & division operators but it got shelved because it might break existing code (and before that I requested more functions for working with quaternions but that request may be lost to the sands of time... or in the script forum archive, not sure which).

Is this quaternion normalizing related to the Key Framed Motion only or what? I never, NEVER had a runtime error with a quaternion not being normalized with the Key Framed Motion or any other LSL function. Dora Gustafson 10:45, 23 February 2012 (PST)

The example that includes quaternion normalizing will discourage any newcomer and many other good people including myself, because it takes focus away from the subject of the article. If included it should be said under caveats or bugs in my opinion. Dora Gustafson 10:45, 23 February 2012 (PST)

Normalization should only be necessary for math or functions that might return non-normalized ones. so far as I can see, that's direct manipulation of elements, or the functions llAxis2Rot and llRotBetween. all other LSL functions will always return normalized rotations, and math (* or /) on normalized rotations results in normalized rotations. The caveat here should probably only state that it needs normalized rotations, and there should be a caveat on each of the functions or operations that might not return them. The first example shouldn't need normalization since both sources are already normalized.
-- Void (talk|contribs) 14:33, 26 February 2012 (PST)
I, too, am not fond of the way it's sort of alluded that LSL may randomly and uncontrollably wreck rotations, and that everybody should just start using the "magical normalization function" on all rotations. The "some circumstances" should be spelled out clearly. There is the llAxes2Rot on non-orthogonal vectors or the llRotBetween between different magnitudes, but I suspect the primary reason people report seeing it comparatively often is because they read the quaternions from a text representation (such as a notecard), where the components can be rounded off.
Tali Rosca 19:12, 9 May 2012 (PDT)
That is likely the case and they haven't used my Rot2Hex function to perfectly serialize the rotation! Sorry for the shameless plug but serialization is important. -- Strife (talk|contribs) 22:43, 9 May 2012 (PDT)

the function provides a list of displacements in region coordinates rather than positions Sigma Avro 13:39, 5 April 2012 (PDT)

Client-Side Motion?

I think that this function would be particularly useful if it could be used to define client-side motion, as many animations won't necessarily require the object to actually move. This could easily be achieved with a suitable option to make the effect client-side as opposed to server-side only, in which case the object wouldn't physically move, only visually. If it is done, then I'd like to pitch SVC-4897 since it would allow the animation (and potentially loads of other effects) to work better on the viewer side; eliminating the need for messy scripted synchronisation, and avoiding lag-related issues.
-- Haravikk (talk|contribs) 09:18, 11 May 2012 (PDT)

I just wanted to add as well that client-side motion is also particularly important as it would allow the function to be applied to objects that do no use prim-equivalency; since the effect would be client-side only it would not be as demanding, and the viewer can easily reduce the detail of the animation if necessary. I just wanted to ask as well what exactly the state of this is; the function is not recognised by the viewer's LSL editor, though it does compile, at least in LeTigre regions (which my home region belongs to) so I'm curious if it's live yet? If it is a live change then I'll have to look at filing a JIRA issue for client-side integration.
-- Haravikk (talk|contribs) 03:43, 12 May 2012 (PDT)
I wanted to note that I added a proposal under SCR-346 to retroactively add this ability; animation is fine, but the fact is that nearly all things I'd like to use it for could be handled a lot more efficiently within the viewer as I don't really have any need for the objects to physically go anywhere. As noted in the proposal the advantage of the client-side option is that it eliminates all work from the simulator, leaving each viewer to decide how frequently to update the animation. It would also allow animation of non equivalency prims, and child-prims. In the proposal for child-prims I noted that these would occur locally; i.e - everything is relative to the root. This would allow simple environmental animation without generating huge load; things such as moving pistons, and such.
-- Haravikk (talk|contribs) 05:04, 22 July 2012 (PDT)

MINIMAL TIME

Script warming errors indicate that minimal value for time is to be > 0.1 seconds. Not clear what >0.1s means exactly since according to test the minimal value is 0.112 in an empty sim with zero lag.Sigma Avro 12:50, 12 August 2012 (PDT)

Not sure where it becomes 5/45 in the programming, but it was likely originally written as 0.1 and becomes 5/45 due to per-frame rounding. Either that or it was written and always had been 5 frames, and someone thought it was simpler to make the error say '0.1'. Acheron Gloom 14:11, 12 August 2012 (PDT)

Moving linkset while animating

Attempting to modify the any prims of a linkset while it's playing a keyframed motion will result in the following error:

Cannot use a script to move a linkset while it is playing an animation.

I was surprised had not only not been documented, but had no workaround mentioned. In my examination, this function can potentially be used as a sort of "pathfinding lite," or a replacement when dynamic pathfinding is unavailable. As such, it would inevitably used for some critter that needs to play some sort of prim-based animation while sliding along. I've updated the main page with my findings and solutions, but I wanted to mention them in more detail here.

First, the keyframed motion can be paused by calling: <lsl>llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_PAUSE])</lsl> Easy peasy. This also works in a second script, if for some reason you can't call it from the original script. Keyframed motion is like particles and hovertext in that it's a prim property, and any script can modify the prim properties without knowing what other scripts are up to. The empty keyframes list doesn't actually clear the keyframes stored.

Restarting the keyframed motion is done with this command: <lsl>llSetKeyframedMotion([],[KFM_COMMAND,KFM_CMD_PLAY])</lsl> But be careful! If you've previous called the function with two blank lists to "stop" the motion entirely, this will restart it. It looks like two blank lists is merely a shortcut to pausing, not a termination and clearing of the keyframe list.

Second, for the actual "animating" of your critter. You'll want to use llSetLinkPrimitiveParamsFast. Since your goal should be not to interrupt the smooth movement (unless it's not your goal) you should lump all of your prim shifting into one call using PRIM_LINK_TARGET, making one list with all your property changes for all prims. Once the list is compiled, pause the motion, call the llSLPPF function, and restart the motion. In my testing, if this all manages to happen in one frame, the motion will not even be interrupted and remain smooth.

Hopefully this helps someone else who was in a similar spot as me, and found themselves encountering an unexpected error. --Stickman 10:44, 18 June 2013 (PDT)