LlSetCameraParams Test

From Second Life Wiki
Revision as of 13:04, 5 August 2008 by Dan Linden (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Scripted Camera Test

Specs

Scripted Camera is intended as a way to modify the camera's view of your avatar. The best example of the power of Scripted Camera is as a vehicle camera. Turn on the Scripted Camera when you sit in a vehicle, and set the two lag values to about 0.1, and the behindness angle to 180, and notice the looseness. You can also use Scripted Camera on attachments. One possible use would be to have users put on a special hat when they come into your house, which causes their cameras to lock to a special place on the wall that allows all avatars to be in view, and focuses on the center of the room. Scripted Camera can also be used to flying views. For instance, you can set up a FlyCam which allows you to look down from bird's-eye-view to see the terrain as you fly along.

Expectations

Attachments are automatically granted permissions when you attach them. Hitting escape will revert to the most recently set llSetCameraParams. Detaching the object will revoke permissions. Vehicles are automatically granted permissions when you sit. Hitting escape will revert to the most recently set llSetCameraParams. Standing up will revoke permissions. Stand-alone object must request scripted camera permissions via a dialog. Hitting escape will revert your view to your normal camera view (and revoke permissions?).

The LL Script calls

llRequestPermissions(agent_key, PERMISSION_CONTROL_CAMERA);

Follow by any set of calls to modify the camera. This makes camera control behave like keyboard control, animation control, any other set of "overrides" that a script can perform. Note that the user will automatically cede control of the camera to attachments and objects he is sitting on, so the user experience will be pretty seamless in those cases. PERMISSION_CONTROL_CAMERA permissions are only supported for attachments and vehicles at this time. Accepting permissions via a dialog is not currently implemented.


llClearCameraParams();

Resets all camera values to their default.


llReleaseCamera();

Returns camera to agent.


llSetCameraParams([]);

Sets up the camera movement rules based on the parameter list


CAMERA_ACTIVE (TRUE or FALSE) Default = FALSE

Turns on or off scripting control of Scripted Camera


CAMERA_DISTANCE (0.5 to 10.0 meters) Default = 3.0

Sets how far away the Scripted Camera wants to be from its subject


CAMERA_PITCH (-45.0 to 80.0 degrees) Default = 0.0

Adjusts the angular amount that the Scripted Camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'


CAMERA_FOCUS_OFFSET (<-10,-10,-10> to <10,10,10> meters) Default = <0.0, 0.0, 0.0>

Adjusts the position of the Scripted Camera focus position relative to the subject


CAMERA_POSITION_LAG (0.0 to 3.0 seconds) Default = 0.1

How much the Scripted Camera lags as it tries to move towards its 'ideal' position


CAMERA_FOCUS_LAG (0.0 to 3.0 seconds) Default = 0.1

How much the Scripted Camera lags as it tries to aim towards the subject


CAMERA_BEHINDNESS_ANGLE (0.0 to 180.0 degrees) Default = 10.0

Sets the angle in degrees within which the Scripted Camera is not constrained by changes in subject rotation. 180 effectively turns behindness off.


CAMERA_BEHINDNESS_LAG (0.0 to 3.0 seconds) Default = 0.0

How much the Scripted Camera lags as it tries to stay behind the target if outside of behindness angle

CAMERA_POSITION_THRESHOLD (0.0 to 4.0 meters) Default = 1.0

Sets the radius of a sphere around the Scripted Camera's ideal position within which it is not affected by subject motion


CAMERA_FOCUS_THRESHOLD (0.0 to 4.0 meters) Default = 1.0

Sets the radius of a sphere around the Scripted Camera's subject position within which its focus is not affected by subject motion


CAMERA_POSITION (vector position within the region)

Sets the position of the Scripted Camera


CAMERA_FOCUS (vector position within the region)

Sets the focus position of the Scripted Camera


CAMERA_POSITION_LOCKED (TRUE or FALSE) Default = FALSE

Locks the camera position so it will not move


CAMERA_FOCUS_LOCKED (TRUE or FALSE) Default = FALSE

Locks the camera focus so it will not move


Test

integer CHANNEL; // dialog channel
list MENU_MAIN = ["Default", "Overhead Cam", "Spin Cam", "Trap Toggle", "Spaz Cam", "Drop Cam", "Worm Cam", "Side Cam", "Driving Cam", "More...", "Cam ON", "Cam OFF"]; // the main menu
list MENU_2 = ["More...", "...Back"]; // menu 2
 
integer on = FALSE;
integer flying;
integer falling;
integer spaz = 0;
integer trap = 0;

take_camera_control(key agent)
{
    llOwnerSay("take_camera_control"); // say function name for debugging
    llOwnerSay( (string)agent); 
    llRequestPermissions(agent, PERMISSION_CONTROL_CAMERA);
    llSetCameraParams([CAMERA_ACTIVE, 1]); // 1 is active, 0 is inactive
    on = TRUE;
}

release_camera_control(key agent)
{
    llOwnerSay("release_camera_control"); // say function name for debugging
    llSetCameraParams([CAMERA_ACTIVE, 0]); // 1 is active, 0 is inactive
    llReleaseCamera(agent);
    on = FALSE;
} 

focus_on_me()
{
    llOwnerSay("focus_on_me"); // say function name for debugging
//    llClearCameraParams(); // reset camera to default
    vector here = llGetPos();
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 0.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds
        CAMERA_DISTANCE, 0.0, // ( 0.5 to 10) meters
        CAMERA_FOCUS, here, // region relative position
        CAMERA_FOCUS_LAG, 0.0 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, TRUE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
//        CAMERA_PITCH, 80.0, // (-45 to 80) degrees
        CAMERA_POSITION, here + <4,4,4>, // region relative position
        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, TRUE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, ZERO_VECTOR // <-10,-10,-10> to <10,10,10> meters
    ]);
}

default_cam()
{
//    llOwnerSay("default_cam"); // say function name for debugging
    llClearCameraParams(); // reset camera to default
    llSetCameraParams([CAMERA_ACTIVE, 1]);
}


driving_cam()
{
    llOwnerSay("driving_cam"); // say function name for debugging
    default_cam();
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 45.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.5, // (0 to 3) seconds
        CAMERA_DISTANCE, 8.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.05 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_PITCH, 20.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.1, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <3,0,2> // <-10,-10,-10> to <10,10,10> meters
    ]);
}


side_cam()
{
    llOwnerSay("side_cam"); // say function name for debugging
    llClearCameraParams(); // reset camera to default
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 0.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds
        CAMERA_DISTANCE, 0.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.0 , // (0 to 3) seconds
//        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
//        CAMERA_PITCH, 80.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
//        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0,3,0> // <-10,-10,-10> to <10,10,10> meters
    ]);
}

rearview_cam()
{
    llOwnerSay("rearview_cam"); // say function name for debugging
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 180.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds
//        CAMERA_DISTANCE, 10.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 3.0 , // (0 to 3) seconds
//        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
//        CAMERA_PITCH, 80.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
//        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
//        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <5,2,-2> // <-10,-10,-10> to <10,10,10> meters
    ]);
}

overhead_cam()
{
    llOwnerSay("overhead_cam"); // say function name for debugging
    default_cam();
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 180.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.5, // (0 to 3) seconds
        CAMERA_DISTANCE, 10.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.05 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_PITCH, 80.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0,0,0> // <-10,-10,-10> to <10,10,10> meters
    ]);
}

drop_camera_5_seconds()
{
    llOwnerSay("drop_camera_5_seconds"); // say function name for debugging
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 0.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.5, // (0 to 3) seconds
        CAMERA_DISTANCE, 3.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 2.0, // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_PITCH, 0.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.05, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, TRUE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0,0,0> // <-10,-10,-10> to <10,10,10> meters
    ]);
    llSleep(5);
    default_cam();
}



worm_cam()
{
    llOwnerSay("worm_cam"); // say function name for debugging
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 180.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds
        CAMERA_DISTANCE, 8.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.0 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 4.0, // (0 to 4) meters
        CAMERA_PITCH, -45.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 1.0, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 1.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0,0,0> // <-10,-10,-10> to <10,10,10> meters
    ]);
}

spaz_cam()
{
    llOwnerSay("spaz_cam for 5 seconds"); // say function name for debugging
    float i;
    for (i=0; i< 50; i+=1)
    {
        vector xyz = llGetPos() + <llFrand(80) - 40, llFrand(80) - 40, llFrand(10)>;
//        llOwnerSay((string)xyz);
        vector xyz2 = llGetPos() + <llFrand(80) - 40, llFrand(80) - 40, llFrand(10)>;
        llSetCameraParams([
            CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
            CAMERA_BEHINDNESS_ANGLE, 180.0, // (0 to 180) degrees
            CAMERA_BEHINDNESS_LAG, llFrand(3), // (0 to 3) seconds
            CAMERA_DISTANCE, llFrand(10), // ( 0.5 to 10) meters
            //CAMERA_FOCUS, xyz, // region relative position
            CAMERA_FOCUS_LAG, llFrand(3), // (0 to 3) seconds
            CAMERA_FOCUS_LOCKED, TRUE, // (TRUE or FALSE)
            CAMERA_FOCUS_THRESHOLD, llFrand(4), // (0 to 4) meters
            CAMERA_PITCH, llFrand(125) - 45, // (-45 to 80) degrees
            CAMERA_POSITION, xyz2, // region relative position
            CAMERA_POSITION_LAG, llFrand(3), // (0 to 3) seconds
            CAMERA_POSITION_LOCKED, TRUE, // (TRUE or FALSE)
            CAMERA_POSITION_THRESHOLD, llFrand(4), // (0 to 4) meters
            CAMERA_FOCUS_OFFSET, <llFrand(20) - 10, llFrand(20) - 10, llFrand(20) - 10> // <-10,-10,-10> to <10,10,10> meters
            ]);
            llSleep(0.1);
    }
    default_cam();
}

spin_cam()
{
    llSetCameraParams([
        CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
        CAMERA_BEHINDNESS_ANGLE, 180.0, // (0 to 180) degrees
        CAMERA_BEHINDNESS_LAG, 0.5, // (0 to 3) seconds
        //CAMERA_DISTANCE, 10.0, // ( 0.5 to 10) meters
        //CAMERA_FOCUS, <0,0,5>, // region relative position
        CAMERA_FOCUS_LAG, 0.05 , // (0 to 3) seconds
        CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_PITCH, 30.0, // (-45 to 80) degrees
        //CAMERA_POSITION, <0,0,0>, // region relative position
        CAMERA_POSITION_LAG, 0.0, // (0 to 3) seconds
        CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
        CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
        CAMERA_FOCUS_OFFSET, <0,0,0> // <-10,-10,-10> to <10,10,10> meters
    ]);
    
    float i;
    vector camera_position;
    for (i=0; i< 2*TWO_PI; i+=.05)
    {
        camera_position = llGetPos() + <0, 4, 0> * llEuler2Rot(<0,0,i>);
        llSetCameraParams([CAMERA_POSITION, camera_position]);
    }
    default_cam();
}

setup_listen()
{
    llListenRemove(1);
    CHANNEL = llRound(llFrand(1) * 100000);
    integer x = llListen(CHANNEL, "", "", ""); // listen for dialog answers
}

default
{
    state_entry()
    {
        setup_listen();
        llSetTimerEvent(2);
        llSitTarget(<-0.2, 0.0, 0.5>, <0.00000, -0.25882, 0.00000, 0.96593>);
        llSetCameraEyeOffset(<-6.0, 0.0, 2.00>);
        llSetCameraAtOffset(<0.0, 0.0, 1.0>);
    }
    
    touch_start(integer total_number) 
    {
integer perm = llGetPermissions();
if (perm & PERMISSION_DEBIT)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_DEBIT perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_TAKE_CONTROLS)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_TAKE_CONTROLS perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_TRIGGER_ANIMATION)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_TRIGGER_ANIMATION perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_ATTACH)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_ATTACH perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_CHANGE_LINKS)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_CHANGE_LINKS perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_TRACK_CAMERA)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_TRACK_CAMERA perms for "+(string)llGetPermissionsKey()); }
if (perm & PERMISSION_CONTROL_CAMERA)
{ llOwnerSay(llGetScriptName() + " has PERMISSION_CONTROL_CAMERA perms for "+(string)llGetPermissionsKey()); }
if (perm == 0)
{ llOwnerSay(llGetScriptName() + " has NO perms for "+(string)llGetPermissionsKey()); }

        llDialog(llDetectedKey(0), "What do you want to do?", MENU_MAIN, CHANNEL); // present dialog on click
    }
    
    listen(integer channel, string name, key id, string message) 
    {
        if (llListFindList(MENU_MAIN + MENU_2, [message]) != -1)  // verify dialog choice
//        if (llListFindList(MENU_MAIN, [message]) != -1)  // verify dialog choice
        {
//            llOwnerSay(name + " picked the option '" + message + "'."); // output the answer
            if (message == "More...") 
                llDialog(id, "Pick an option!", MENU_2, CHANNEL); // present submenu on request
            else if (message == "...Back") 
                llDialog(id, "What do you want to do?", MENU_MAIN, CHANNEL); // present main menu on request to go back

            
    else if (message == "Cam ON")
    {
        take_camera_control(id);
    }

    else if (message == "Cam OFF") 
    {
        release_camera_control(id);
    }

    else if (message == "Default") 
    {
        default_cam();
    }

    else if (message == "Driving Cam") 
    {
        driving_cam();
    }

    else if (message == "Worm Cam") 
    {
        worm_cam();
    }

    else if (message == "Overhead Cam") 
    {
        overhead_cam();
    }

    else if (message == "Spaz Cam") 
    {
        spaz_cam();
    }

    else if (message == "Side Cam") 
    {
        side_cam();
    }

    else if (message == "Drop Cam") 
    {
        drop_camera_5_seconds();
    }

    else if (message == "Trap Toggle")
    {
        trap = !trap;
        if (trap == 1) {
            llOwnerSay("trap is on");
        }
        else {
            llOwnerSay("trap is off");
        }        
    }

    else if (message == "Spin Cam") 
    {
        spin_cam();
    }

        } else 
            llOwnerSay(name + " picked invalid option '" + llToLower(message) + "'."); // not a valid dialog choice
    }

    run_time_permissions(integer perm) {
        if ((perm & PERMISSION_CONTROL_CAMERA) == PERMISSION_CONTROL_CAMERA) {
            llSetCameraParams([CAMERA_ACTIVE, 1]); // 1 is active, 0 is inactive
            llOwnerSay("Camera permissions have been taken");
        }
    }
    
    changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
            key agent = llAvatarOnSitTarget();
            if (agent)
            {
                setup_listen();
                llRequestPermissions(agent, PERMISSION_CONTROL_CAMERA);
            }
        }
    }
    
    attach(key agent)
    {
        if (agent != NULL_KEY)
        {
            setup_listen();
            llRequestPermissions(agent, PERMISSION_CONTROL_CAMERA);
        }
    }
    
    timer()
    {
        if (trap == 1)
        {
            focus_on_me();
        }        
    }
    
}
  • Put the above script in a box.
  • Click the box to open a dialog whereby you can control it.
  • Test -45 pitch camera (Driving Cam)
    • Set pitch to -45 and walk aroung the world. See if it acts in a predictable manner.
    • Put the preceding script on a box.
    • Attach the box, click the box and choose Worm Cam.
    • Walk around and see if it acts in a predictable manner.


  • Test transitions
    • Put the preceding script on a 4 x 4 x 0.5m box. Let's call it a vehicle.
    • get in and out of a vehicle multiple times and see how the transitions work.
  • Scripted Cameras stack
    • Get in a vehicle with one Scripted Camera setting, put on an attachment with another Scripted Camera setting, and then take off the attachment. Make sure the Scripted Camera pops back to the correct vehicle settings.


  • Scripted Cameras stack, part 2
    • Wear 2 Scripted Camera attachments that have different Camera settings. Relog and verify your camera still has the same view as before you logged. (I don't think this test if valid Dan Linden 12:47, 5 August 2008 (PDT))


  • Taking off scripted Camera attachments changes camera view to default
    • Wear a Scripted Camera attachment, relog, detach the attachment and verify your view is the default walking camera.


  • Objects drop permissions after derez/rez from inventory
    • Make an attachment that tries to take change your camera view every 2 seconds - "Trap Toggle" on the script above. Detach it to inventory, then rez to world and verify it does not control your camera.
    • Verify it doesn't spam you with permissions errors in main chat.
  • Objects don't spam you
    • Make an attachment that tries to take change your camera view every 2 seconds - "Trap Toggle" on the script above. Wear it, then drop it on the ground and verify it does not control your camera.
    • Verify it doesn't spam you with permissions errors in main chat.
  • Escape reverts to most recent Scripted Camera view
    • get in a vehicle with one Scripted Camera setting, put on an attachment with another Scripted Camera setting. Alt-zoom on the ground, then click escape. Make sure the your view reverts to using the attachment's Scripted Camera setting.


  • Set thresholds to 0 and lags to 0, and behindnessForce to 1, and explore varying behindnessAngle. Make sure it works as expected. (TODO: This needs to be a setting added to the script)


  • Set Focus threshold and Position threshold as large as possible and see what happens. (TODO: This needs to be a setting added to the script)


  • Lock position, and leave focus unlocked. Make sure the camera keeps focusing on avatar. (TODO: This needs to be a setting added to the script)


  • Make focus lag and position lag as high as possible. Make sure it works as expected. (TODO: This needs to be a setting added to the script)


  • Test how Scripted Cameras interact with llSetCameraAtOffset and llSetCameraEyeOffset. (TODO: This needs to be a setting added to the script)


  • Test how Scripted Cameras interact with mouse steering?
    • Apparently we can poll llGetAgentInfo to see if user is in mouselook, and if so, set the angular motor's z to 1 or some constant.


  • Test constraints on CAMERA_POSITION and CAMERA_FOCUS. Should not move your camera farther away than you can in edit mode. (TODO: This needs specific numbers and a setting added to the script)


  • Test with multiple avatars on a vehicle. (TODO: This needs to be a setting added to the script)