Difference between revisions of "LlSetKeyframedMotion"

From Second Life Wiki
Jump to navigation Jump to search
m (fixed a typo)
(37 intermediate revisions by 16 users not shown)
Line 1: Line 1:
{{Issues/SCR-345}}{{Issues/SCR-346}}{{Issues/SVC-7796}}{{Issues/SCR-373}}{{LSL_Function
{{LSL_Function
|inject-2={{Issues/SCR-345}}{{Issues/SCR-346}}{{Issues/SVC-7796}}{{Issues/BUG-7743}}{{Issues/BUG-7767}}{{Issues/BUG-7882}}
|func=llSetKeyframedMotion
|func=llSetKeyframedMotion
|func_id=?
|func_id=?
|func_desc=Specify a list of times, positions, and orientations to be followed by an object. The object will be smoothly moved between keyframes by the simulator. Collisions with other nonphysical or keyframed objects will be ignored (no script events will fire and collision processing will not occur). Collisions with physical objects will be computed and reported, but the keyframed object will be unaffected by those collisions. (The physical object will be affected, however.)  
|func_desc=Specify a list of times, positions, and orientations to be followed by an object. The object will be smoothly moved between keyframes by the simulator. Collisions with other nonphysical or keyframed objects will be ignored (no script events will fire and collision processing will not occur). Collisions with physical objects will be computed and reported, but the keyframed object will be unaffected by those collisions. (The physical object will be affected, however.)  
|func_sleep
|func_sleep
|func_energy
|func_energy
|func_footnote
|func_footnote
|p1_type=list|p1_name=keyframes|p1_hover=Strided keyframe list of the form: [vector position, rotation orientation, float time]
|p1_type=list|p1_name=keyframes|p1_hover=Strided keyframe list of the form: [vector position, rotation orientation, float time]
|p1_desc=Strided keyframe list of the form:
|p1_desc=Strided keyframe list of the form:
* ''vector'' position (optional via KFM_TRANSLATION and KFM_DATA)
* ''vector'' position (optional via [[KFM_TRANSLATION]] and [[KFM_DATA]])
* ''rotation'' orientation (optional via KFM_ROTATION and KFM_DATA)
* ''rotation'' orientation (optional via [[KFM_ROTATION]] and [[KFM_DATA]])
* ''float'' time
* ''float'' time


Line 18: Line 17:
Linear and angular velocities will be clamped to limits set by the simulator (values TBD).
Linear and angular velocities will be clamped to limits set by the simulator (values TBD).
An empty list will terminate any keyframed animation currently playing.  
An empty list will terminate any keyframed animation currently playing.  
 
|p2_type=list|p2_subtype=instructions|p2_name=options|p2_desc=modifiers and future options  
|p2_type=list|p2_name=options|p2_desc=modifiers and future options  
 
|spec=
|spec=
The following flags will be supported within the ''options'' list:
The following flags will be supported within the ''options'' list:
*KFM_MODE followed by one of: KFM_LOOP, KFM_REVERSE, KFM_FORWARD, or KFM_PING_PONG will specify the playback mode. Defaults to KFM_FORWARD. Must be specified when the keyframe list is provided.
*[[KFM_MODE]] followed by one of: [[KFM_LOOP]], [[KFM_REVERSE]], [[KFM_FORWARD]], or [[KFM_PING_PONG]] will specify the playback mode. Defaults to [[KFM_FORWARD]]. Must be specified when the keyframe list is provided.
*KFM_DATA followed by a bitwise combination of: KFM_TRANSLATION and KFM_ROTATION. By default both rotations and translations must be provided. If you specify one or the other, you should only include translations or rotations in your keyframe list. Must be specified at the time the keyframe list is provided.
*[[KFM_DATA]] followed by a bitwise combination of: [[KFM_TRANSLATION]] and [[KFM_ROTATION]]. By default both rotations and translations must be provided. If you specify one or the other, you should only include translations or rotations in your keyframe list. Must be specified at the time the keyframe list is provided.
*KFM_COMMAND followed by one of: KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. STOP will pause the animation AND reset it to the beginning. PAUSE will pause the animation without resetting. PLAY will resume a paused or stopped animation.  
*[[KFM_COMMAND]] followed by one of: [[KFM_CMD_STOP]], [[KFM_CMD_PLAY]], [[KFM_CMD_PAUSE]]. STOP will pause the animation AND reset it to the beginning. PAUSE will pause the animation without resetting. PLAY will resume a paused or stopped animation.  
Note that if KFM_COMMAND is provided in the options list, it must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list.
Note that if [[KFM_COMMAND]] is provided in the options list, it must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list.


Inter-region are supported.
Inter-region movement is supported; simply specify a target keyframe that would place the object outside the sim boundaries and it will cross over. This seems to provide the same effect as pausing the animation when it is in limbo between the two regions, but the viewer continues to interpolate its movement. It will jump back to the sim border and continue on the same speed, although the time between waypoints will be increased due to the sim crossing. Make sure you factor this into your system.
This is '''not verified''' on the contrary. See the [http://community.secondlife.com/t5/LSL-Scripting/llSetKeyframedMotion-loses-power-crossing-sim-border/m-p/1558737 LSL scripting forum]


Since keyframed motion is a prim property rather than restricted to the script that called it, you can use multiple scripts to control, pause, or restart the same keyframed motion without passing the original keyframe list provided. Just pass an empty list for keyframes list, and the [[KFM_COMMAND]] followed by the command in the options list.
|constants={{LSL Constants/KeyframedMotion|set|table=*}}
|caveats=
|caveats=
*This function does not work in attachments.
*This function does not work in attachments.
*This function can only be called on NON-physical objects. In the future it could be extended to support physical objects, but this is more complicated as collisions could prevent the object from reaching its goal positions on time.
*This function can only be called on NON-physical objects. In the future it could be extended to support physical objects, but this is more complicated as collisions could prevent the object from reaching its goal positions on time.
*You cannot use scripts to move any prim in the linkset while the keyframed motion is active. If you must, first pause and restart it with [[KFM_CMD_PLAY]] when done. [[#Pause-Play|#Example]]
*Collisions with avatars affect the angular movement of the object and it may not reach the final rotation.
*Collisions with avatars affect the angular movement of the object and it may not reach the final rotation.
*This function can only be called on the root prim of a linkset.
*This function can only be called on the root prim of a linkset.
*This function requires the linkset to use the Prim Equivalency system. However, it keyframed objects will not receive the dynamics penalty and can have a physics weight of up to 64.
*This function requires the linkset to use the Prim Equivalency system. However, it keyframed objects will not receive the dynamics penalty and can have a physics weight of up to 64.
*llSetKeyframedMotion is implemented in terms of frames and not real time. To avoid a drift from the expected positions and rotations, use times which are integer multiples of 1/45, e.g. 20.0/45.0, 40.0/45.0, 90.0/45.0, etc. [http://community.secondlife.com/t5/LSL-Scripting/llSetKeyframedMotion-turning-a-corner/td-p/1225219 Forum Thread]
*llSetKeyframedMotion is implemented in terms of frames and not real time. To avoid a drift from the expected positions and rotations, use times which are integer multiples of 1/45, e.g. 20.0/45.0, 40.0/45.0, 90.0/45.0, etc. [http://community.secondlife.com/t5/LSL-Scripting/llSetKeyframedMotion-turning-a-corner/td-p/1225219 Forum Thread] KFM claims delta times must be larger than 0.1 seconds; in practice, however, delta times slightly over 0.1 will produce an error on DEBUG_CHANNEL. Testing shows a minimum delta time is about 6/45 (.13333) seconds.
**Natural drift can still occur; for best results use [[moving_end]] to determine when the animation has ended and confirm the target position with [[llSetPos]].  Or you can use [[at_target]] or [[at_rot_target]].
*There are a few bugs in the avatar animation system that may cause strange looking animations to play when standing on a moving platform (e.g., walking in place, feet-at-pelvis). We hope to fix these in the future, but doing so is out of scope for this feature.
*There are a few bugs in the avatar animation system that may cause strange looking animations to play when standing on a moving platform (e.g., walking in place, feet-at-pelvis). We hope to fix these in the future, but doing so is out of scope for this feature.
*As with dynamic objects, objects moving using this function are paused when they are selected by an avatar with adequate permissions (object owner, passenger, etc). When such an avatar deselects the object, motion resumes, even if the object had been paused using KFM_CMD_PAUSE.
*As with dynamic objects, objects moving using this function are paused when they are selected by an avatar with adequate permissions (object owner, passenger, etc). When such an avatar deselects the object, motion resumes, even if the object had been paused using [[KFM_CMD_PAUSE]].
*A Key Framed Motion is a '''prim property''' in some respect. When a KFM_LOOP or KFM_PING_PONG is initiated not only '''the motion''' but also the '''prim position''' is '''preserved after the script is removed'''. I.E. The prim will continue what motion it had and it will snap back when moving is attempted. It will not survive take and copy. It will survive server restart sometimes.
*A Key Framed Motion is a '''prim property''' in some respect. When a [[KFM_LOOP]] or [[KFM_PING_PONG]] is initiated the '''the motion''' is '''preserved after the script is removed'''. I.E. The prim will continue what motion it had. It will survive take and copy. It will survive server restart.
*Inter region movement is far from perfect. Crossing from sim 1 to sim 2 using a Key Frame list with numerous frames on a curved path will pick up conspicuous errors on the crossing and when reversed by [ [[KFM_MODE]], [[KFM_REVERSE]] ] the object will stay in sim 2 and never return to sim 1
|examples=
|examples=
<lsl>
<source lang="lsl2">
// If your client is not mesh-aware use the following line:
// If your client is not mesh-aware use the following line:


llSetLinkPrimitiveParamsFast(LINK_THIS,
llSetLinkPrimitiveParamsFast(LINK_THIS,
     [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
     [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
</lsl>
</source>
<lsl>
<source lang="lsl2">
llSetKeyframedMotion(
llSetKeyframedMotion(
     [<0.0, 0.0, 10.0>, ZERO_VECTOR, 5,
     [<0.0, 0.0, 10.0>, 5,
         <0.0, 0.0, -10.0>, ZERO_VECTOR, 5],
         <0.0, 0.0, -10.0>, 5],
     [KFM_DATA, KFM_TRANSLATION, KFM_MODE, KFM_PING_PONG]);
     [KFM_DATA, KFM_TRANSLATION, KFM_MODE, KFM_PING_PONG]);
</lsl>
</source>
<lsl>
<source lang="lsl2">
llSetKeyframedMotion(
llSetKeyframedMotion(
     [<0.0, 0.0, 10.0>, llEuler2Rot(<90, 45, 180> * DEG_TO_RAD), 5,
     [<0.0, 0.0, 10.0>, llEuler2Rot(<90, 45, 180> * DEG_TO_RAD), 5,
         <0.0, 0.0, -10.0>, llEuler2Rot(<270, 225, 360> * DEG_TO_RAD), 5],
         <0.0, 0.0, -10.0>, llEuler2Rot(<270, 225, 360> * DEG_TO_RAD), 5],
     [KFM_MODE, KFM_REVERSE]);
     [KFM_MODE, KFM_REVERSE]);
</lsl>
</source>
==Sample Script==
=== Pause-Play ===
<source lang="lsl2">llSetKeyframedMotion([],[KFM_COMMAND, KFM_CMD_PAUSE]);
//modify prim positions here
llSetKeyframedMotion([],[KFM_COMMAND, KFM_CMD_PLAY]);</source>
===Sample Script - Key Framed Follower===
Under some circumstances, rotations will generate a run-time error unless they are normalized.  This script illustrates a way to use llKeyframedMotion to create a follower -- think, for example, of a cart behind a vehicle -- using normalized target rotation.
Under some circumstances, rotations will generate a run-time error unless they are normalized.  This script illustrates a way to use llKeyframedMotion to create a follower -- think, for example, of a cart behind a vehicle -- using normalized target rotation.
<lsl>rotation NormRot(rotation Q)
<source lang="lsl2">
integer isSensorRepeatOn;
 
rotation NormRot(rotation Q)
{
{
     float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);
     float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);
     return <Q.x/MagQ, Q.y/MagQ, Q.z/MagQ, Q.s/MagQ>;
 
     return
        <Q.x/MagQ, Q.y/MagQ, Q.z/MagQ, Q.s/MagQ>;
}
}
   
 
integer gON;
default
default
{
{
     state_entry()
     state_entry()
     {
     {
         llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);  
         llSetLinkPrimitiveParamsFast(LINK_ROOT,
                [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX,
            PRIM_LINK_TARGET, LINK_ALL_CHILDREN,
                PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
     }
     }
   
 
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
         gON = !gON; //Toggle device on/off
         isSensorRepeatOn = !isSensorRepeatOn;
         if (gON)
 
         if (isSensorRepeatOn)
         {
         {
             llSay(0,"Switch ON!");
        //  PUBLIC_CHANNEL has the integer value 0
             llSensorRepeat("","91b39b5b-13b1-2517-273a-67360b842c02",SCRIPTED,10.0,PI,0.1); //Following my scripted vehicle
             llSay(PUBLIC_CHANNEL, "Sensor repeat switched on!");
 
             llSensorRepeat("", "91b39b5b-13b1-2517-273a-67360b842c02", SCRIPTED, 10.0, PI, 0.1);
         }
         }
         else
         else
        {
//      {
             llSensorRemove();
             llSensorRemove();
        }
//      }
     }
     }
   
 
     sensor(integer num)
     sensor(integer num_detected)
     {
     {
         llSetKeyframedMotion([(llDetectedPos(0) - llGetPos()) + <-1.0,0.0,0.2>*llDetectedRot(0), NormRot(llDetectedRot(0)/llGetRot()),0.12],[]);
         vector ownPosition = llGetPos();
        rotation ownRotation = llGetRot();
        vector detectedPosition = llDetectedPos(0);
        rotation detectedRotation = llDetectedRot(0);
 
        llSetKeyframedMotion(
            [(detectedPosition - ownPosition) + <-1.0, 0.0, 0.2>*detectedRotation,
            NormRot(detectedRotation/ownRotation), 0.12],
            []);
     }
     }
}</lsl>
}
==Universal Hinged Motion in 8 Key Frames==
</source>
===Universal Hinged Motion in 8 Key Frames===
The script will turn a box prim around one edge parallel to the prim's Y-axis<br>
The script will turn a box prim around one edge parallel to the prim's Y-axis<br>
The script will work for any prim orientation<br>
The script will work for any prim orientation<br>
Note that the smallest accepted time per frame is 1/9S=0.11111111S and NOT 0.1S<br>
Note that the smallest accepted time per frame is 1/9S=0.11111111S and NOT 0.1S<br>
<lsl>
<source lang="lsl2">
float angleEnd=PI_BY_TWO;
float angleEnd=PI_BY_TWO;
float speed=0.2; // m/S
float speed=0.2; // m/S
Line 151: Line 175:
     on_rez( integer n) { llResetScript(); }
     on_rez( integer n) { llResetScript(); }
}
}
</lsl>
</source>
After editing prim position, rotation and/or size the script should be reset in order to update the motion
After editing prim position, rotation and/or size the script should be reset in order to update the motion
==More Examples==
===Continuous Spin===
# [https://wiki.secondlife.com/wiki/User:Dora_Gustafson/Pendulum_motion Pendulum motion] Simple Pendulum Motion in 24 Key Frames, a good motion for a swing
The following example does the same thing as using llTargetOmega(<0.0,0.0,1.0>,PI,1.0) to make a prim rotate continuously around its Z-axis, assuming that the prim is set to convex hull and is non-physical.
# [https://wiki.secondlife.com/wiki/User:Dora_Gustafson/Harmonic_Oscillator_motion Oscillator motion] Motion in 12 Key Frames
<source lang="lsl2">
integer gON;
 
default
{
    touch_start(integer total_number)
    {
        gON = !gON;
        if (gON)
        {
            // Make repeated rotations of PI/2 radians, each taking 0.5 seconds
            llSetKeyframedMotion([llEuler2Rot(<0.0,0.0,PI/2>), 0.5],[KFM_DATA,KFM_ROTATION, KFM_MODE,KFM_LOOP]);
        }
        else
        {
            llSetKeyframedMotion([],[]);
        }
    }
}
</source>
===More Examples===
* [[User:Tapple_Gao/3D_Spinning_Pendulum_Motion|3D Spinning Pendulum Motion]], Suitable for spinning tops, swings, tire swings. Highly configurable
* [[User:Dora_Gustafson/Harmonic_Oscillator_motion|Oscillator Motion in 12 Key Frames]]
* [[User:Dora_Gustafson/Pendulum_motion|Simple Pendulum Motion in 24 Key Frames]], a good motion for a swing
|notes=
|notes=
Potential Use Cases:
Potential Use Cases:
Line 167: Line 214:
* Say: a rotate around the X-axis will rotate the object around it's local, prim X-axis no matter the object's rotation
* Say: a rotate around the X-axis will rotate the object around it's local, prim X-axis no matter the object's rotation
* When the object is not rotated in the global system you won't notice the difference
* When the object is not rotated in the global system you won't notice the difference
|signature=
{{LSL Const/Signature|KFM_MODE|integer}}
{{LSL Const/Signature|KFM_LOOP|integer}}
{{LSL Const/Signature|KFM_REVERSE|integer}}
{{LSL Const/Signature|KFM_FORWARD|integer}}
{{LSL Const/Signature|KFM_PING_PONG|integer}}
{{LSL Const/Signature|KFM_DATA|integer}}
{{LSL Const/Signature|KFM_TRANSLATION|integer}}
{{LSL Const/Signature|KFM_ROTATION|integer}}
{{LSL Const/Signature|KFM_COMMAND|integer}}
{{LSL Const/Signature|KFM_CMD_STOP|integer}}
{{LSL Const/Signature|KFM_CMD_PLAY|integer}}
{{LSL Const/Signature|KFM_CMD_PAUSE|integer}}
|cat1=Physics
|cat1=Physics
|cat2=Movement
|cat2=Movement
|cat3
|cat3
|cat4
|cat4
|haiku={{Haiku|author={{User|Progenitor Resident}}|This is how they move,|Non-phys life for my critters|Smooth, no collisions.}}
|history = Date of Release  [[ Release_Notes/Second_Life_Server/11#11.11.09.244706 | 09/11/2011 ]]
}}
}}

Revision as of 16:24, 11 September 2018

Summary

Function: llSetKeyframedMotion( list keyframes, list options );

Specify a list of times, positions, and orientations to be followed by an object. The object will be smoothly moved between keyframes by the simulator. Collisions with other nonphysical or keyframed objects will be ignored (no script events will fire and collision processing will not occur). Collisions with physical objects will be computed and reported, but the keyframed object will be unaffected by those collisions. (The physical object will be affected, however.)

• list keyframes Strided keyframe list of the form:

Each keyframe is interpreted relative to the previous transform of the object. For example, consider the following list of keyframes: [<0, 0, 10>, ZERO_ROTATION, 5, <0, 0, 0>, ZERO_ROTATION, 5, <0, 0, -10>, ZERO_ROTATION, 5]. This would cause the object to move up 10m over the course of 5s. It would then remain at the location for 5s before moving down 10m over the course of another 5s. Time values must be 1/9s. or greater. Linear and angular velocities will be clamped to limits set by the simulator (values TBD). An empty list will terminate any keyframed animation currently playing.

• list options modifiers and future options

Specification

The following flags will be supported within the options list:

  • KFM_MODE followed by one of: KFM_LOOP, KFM_REVERSE, KFM_FORWARD, or KFM_PING_PONG will specify the playback mode. Defaults to KFM_FORWARD. Must be specified when the keyframe list is provided.
  • KFM_DATA followed by a bitwise combination of: KFM_TRANSLATION and KFM_ROTATION. By default both rotations and translations must be provided. If you specify one or the other, you should only include translations or rotations in your keyframe list. Must be specified at the time the keyframe list is provided.
  • KFM_COMMAND followed by one of: KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. STOP will pause the animation AND reset it to the beginning. PAUSE will pause the animation without resetting. PLAY will resume a paused or stopped animation.

Note that if KFM_COMMAND is provided in the options list, it must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list.

Inter-region movement is supported; simply specify a target keyframe that would place the object outside the sim boundaries and it will cross over. This seems to provide the same effect as pausing the animation when it is in limbo between the two regions, but the viewer continues to interpolate its movement. It will jump back to the sim border and continue on the same speed, although the time between waypoints will be increased due to the sim crossing. Make sure you factor this into your system.

Since keyframed motion is a prim property rather than restricted to the script that called it, you can use multiple scripts to control, pause, or restart the same keyframed motion without passing the original keyframe list provided. Just pass an empty list for keyframes list, and the KFM_COMMAND followed by the command in the options list.

options flags Additional Parameters Description
KFM_COMMAND ] 0 [ integer command ] Sets the command
KFM_CMD_PLAY 0 ?
KFM_CMD_STOP 1 ?
KFM_CMD_PAUSE 2 ?
KFM_MODE ] 1 [ integer mode ] Sets the playback modeDefaults to KFM_FORWARD
KFM_FORWARD 0 ?
KFM_LOOP 1 ?
KFM_PING_PONG 2 ?
KFM_REVERSE 3 ?
KFM_DATA ] 2 [ integer fields ] Sets what data the keyframes containDefaults to (KFM_ROTATION | KFM_TRANSLATION)
KFM_ROTATION 0x1 ?
KFM_TRANSLATION 0x2 ?

Caveats

  • This function does not work in attachments.
  • This function can only be called on NON-physical objects. In the future it could be extended to support physical objects, but this is more complicated as collisions could prevent the object from reaching its goal positions on time.
  • You cannot use scripts to move any prim in the linkset while the keyframed motion is active. If you must, first pause and restart it with KFM_CMD_PLAY when done. #Example
  • Collisions with avatars affect the angular movement of the object and it may not reach the final rotation.
  • This function can only be called on the root prim of a linkset.
  • This function requires the linkset to use the Prim Equivalency system. However, it keyframed objects will not receive the dynamics penalty and can have a physics weight of up to 64.
  • llSetKeyframedMotion is implemented in terms of frames and not real time. To avoid a drift from the expected positions and rotations, use times which are integer multiples of 1/45, e.g. 20.0/45.0, 40.0/45.0, 90.0/45.0, etc. Forum Thread KFM claims delta times must be larger than 0.1 seconds; in practice, however, delta times slightly over 0.1 will produce an error on DEBUG_CHANNEL. Testing shows a minimum delta time is about 6/45 (.13333) seconds.
  • There are a few bugs in the avatar animation system that may cause strange looking animations to play when standing on a moving platform (e.g., walking in place, feet-at-pelvis). We hope to fix these in the future, but doing so is out of scope for this feature.
  • As with dynamic objects, objects moving using this function are paused when they are selected by an avatar with adequate permissions (object owner, passenger, etc). When such an avatar deselects the object, motion resumes, even if the object had been paused using KFM_CMD_PAUSE.
  • A Key Framed Motion is a prim property in some respect. When a KFM_LOOP or KFM_PING_PONG is initiated the the motion is preserved after the script is removed. I.E. The prim will continue what motion it had. It will survive take and copy. It will survive server restart.
  • Inter region movement is far from perfect. Crossing from sim 1 to sim 2 using a Key Frame list with numerous frames on a curved path will pick up conspicuous errors on the crossing and when reversed by [ KFM_MODE, KFM_REVERSE ] the object will stay in sim 2 and never return to sim 1
All Issues ~ Search JIRA for related Bugs

Examples

// If your client is not mesh-aware use the following line:

llSetLinkPrimitiveParamsFast(LINK_THIS,
    [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
llSetKeyframedMotion(
    [<0.0, 0.0, 10.0>,  5,
        <0.0, 0.0, -10.0>,  5],
    [KFM_DATA, KFM_TRANSLATION, KFM_MODE, KFM_PING_PONG]);
llSetKeyframedMotion(
    [<0.0, 0.0, 10.0>, llEuler2Rot(<90, 45, 180> * DEG_TO_RAD), 5,
        <0.0, 0.0, -10.0>, llEuler2Rot(<270, 225, 360> * DEG_TO_RAD), 5],
    [KFM_MODE, KFM_REVERSE]);

Pause-Play

llSetKeyframedMotion([],[KFM_COMMAND, KFM_CMD_PAUSE]);
//modify prim positions here
llSetKeyframedMotion([],[KFM_COMMAND, KFM_CMD_PLAY]);

Sample Script - Key Framed Follower

Under some circumstances, rotations will generate a run-time error unless they are normalized. This script illustrates a way to use llKeyframedMotion to create a follower -- think, for example, of a cart behind a vehicle -- using normalized target rotation.

integer isSensorRepeatOn;

rotation NormRot(rotation Q)
{
    float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);

    return
        <Q.x/MagQ, Q.y/MagQ, Q.z/MagQ, Q.s/MagQ>;
}

default
{
    state_entry()
    {
        llSetLinkPrimitiveParamsFast(LINK_ROOT,
                [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX,
            PRIM_LINK_TARGET, LINK_ALL_CHILDREN,
                PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
    }

    touch_start(integer total_number)
    {
        isSensorRepeatOn = !isSensorRepeatOn;

        if (isSensorRepeatOn)
        {
        //  PUBLIC_CHANNEL has the integer value 0
            llSay(PUBLIC_CHANNEL, "Sensor repeat switched on!");

            llSensorRepeat("", "91b39b5b-13b1-2517-273a-67360b842c02", SCRIPTED, 10.0, PI, 0.1);
        }
        else
//      {
            llSensorRemove();
//      }
    }

    sensor(integer num_detected)
    {
        vector ownPosition = llGetPos();
        rotation ownRotation = llGetRot();
        vector detectedPosition = llDetectedPos(0);
        rotation detectedRotation = llDetectedRot(0);

        llSetKeyframedMotion(
            [(detectedPosition - ownPosition) + <-1.0, 0.0, 0.2>*detectedRotation,
            NormRot(detectedRotation/ownRotation), 0.12],
            []);
    }
}

Universal Hinged Motion in 8 Key Frames

The script will turn a box prim around one edge parallel to the prim's Y-axis
The script will work for any prim orientation
Note that the smallest accepted time per frame is 1/9S=0.11111111S and NOT 0.1S

float angleEnd=PI_BY_TWO;
float speed=0.2; // m/S
float steps=8.0; // number of Key Frames
float step=0.0;
list KFMlist=[];
vector V;
integer open=TRUE;
vector basePos;
rotation baseRot;

float motion_time( float mt)
{
    mt = llRound(45.0*mt)/45.0;
    if ( mt > 0.11111111 ) return mt;
    else return 0.11111111;
}

default
{
    state_entry()
    {
        llSetMemoryLimit(0x2000);
        llSetPrimitiveParams([PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
        basePos = llGetPos();
        baseRot = llGetRot();
        vector v1 = 0.5*llGetScale()*llGetRot();
        rotation deltaRot = llEuler2Rot(< 0.0, angleEnd/steps, 0.0>);
        while ( step < steps )
        {
            V = v1*llAxisAngle2Rot(llRot2Left(llGetRot()), angleEnd*step/steps);
            V = v1*llAxisAngle2Rot(llRot2Left(llGetRot()), angleEnd*(step+1.0)/steps) - V;
            KFMlist += [V, deltaRot, motion_time(llVecMag(V)/speed)];
            step += 1.0;
        }
    }
    touch_end( integer n)
    {
        llSetKeyframedMotion( [], []);
        if ( open )
        {
            llSetPrimitiveParams([PRIM_POSITION, basePos, PRIM_ROTATION, baseRot]);
            llSetKeyframedMotion( KFMlist, []);
        }
        else
        {
            llSetKeyframedMotion( KFMlist, [KFM_MODE, KFM_REVERSE]);
        }
        open = !open;
    }
    on_rez( integer n) { llResetScript(); }
}

After editing prim position, rotation and/or size the script should be reset in order to update the motion

Continuous Spin

The following example does the same thing as using llTargetOmega(<0.0,0.0,1.0>,PI,1.0) to make a prim rotate continuously around its Z-axis, assuming that the prim is set to convex hull and is non-physical.

integer gON;

default
{
    touch_start(integer total_number)
    {
        gON = !gON;
        if (gON)
        {
            // Make repeated rotations of PI/2 radians, each taking 0.5 seconds
            llSetKeyframedMotion([llEuler2Rot(<0.0,0.0,PI/2>), 0.5],[KFM_DATA,KFM_ROTATION, KFM_MODE,KFM_LOOP]);
        }
        else
        {
            llSetKeyframedMotion([],[]);
        }
    }
}

More Examples

Notes

Potential Use Cases:

  • Elevators
  • Moving platforms
  • Trains/Fixed-Track Vehicles
  • Moving doors/walls/gates
  • Windmills and other machines

Targeted coordinate systems: The Translation is in Global coordinates, the Rotation in Local coordinates

  • Say: a move on the X-axis will move the object along the global, region X-axis no matter how the object is rotated
  • Say: a rotate around the X-axis will rotate the object around it's local, prim X-axis no matter the object's rotation
  • When the object is not rotated in the global system you won't notice the difference

Deep Notes

History

Date of Release 09/11/2011

All Issues

~ Search JIRA for related Issues
   llSetKeyframedMotion() does not support inter-region motion
   Option for viewer-only llSetKeyframedMotion() functionality
   Curve Interpolation for llSetKeyframedMotion()
   Bezier Curve Support for llSetKeyframedMotion()
   KFM_STRICT_TIMING for llSetKeyframedMotion()
   KFM_SYNC_TIME - Synchronised Timing for llSetKeyframedMotion()

Signature

function void llSetKeyframedMotion( list keyframes, list options );

Haiku

This is how they move,
Non-phys life for my critters
Smooth, no collisions.
Progenitor Resident