Camera Automation

Ask questions about using viewers to enter worlds, and problems with viewers
Post Reply
User avatar
Shandon Loring
Posts: 1346
Joined: Sat Oct 26, 2013 3:25 am
Has thanked: 972 times
Been thanked: 1586 times
Contact:

Camera Automation

Post by Shandon Loring »

We stream all our storyteller events now Live on our Youtube Channel, as well as being Live inworld here in Kitely and simultaneously Live in SL.

But since the storyteller is unable, practically, to do mcuh camera work, other than switching feeds, while they're presenting we end up with a Live Stream of a fixed camera position, I'd LOVE to have some ability to occasionally pan the camera about the audience and venue and such during the story.

Here is an example similar to what we would like to be able to set up to run automatically during the story.
https://www.youtube.com/watch?v=J01NqexiTzI
(This example was done by a hooman working the camera during the presentation)


Perhaps there are scripts or procedures or something in the Viewer itself that everybody else uses but I just don't know about. LoL! Which is entirely possible!

Thanks for any helps!
These users thanked the author Shandon Loring for the post (total 2):
Ilan TochnerSelby Evans
Graham Mills
Posts: 1314
Joined: Sun Dec 23, 2012 2:26 pm
Has thanked: 1134 times
Been thanked: 1142 times

Re: Camera Automation

Post by Graham Mills »

This isn't mine (apart from a few minor edits) and I forgot to note where I got it from but it may answer part of the request in your sub-thread for the ability to move (if not pan) the camera during a presentation. It assumes the avatar is sitting and uses the right/left cursor keys to move through a list on notecard of camera positions/rotations. Of course it might be more convenient to use a HUD.

Code: Select all

integer listenHandle = -1;
 
list positions;
list rots;
key sitter;
integer gotperms;
integer currentCamera;
 
setCameraLoc() {
    if (!gotperms) return;
    vector savedPos = llList2Vector(positions,currentCamera);
    rotation savedRot = llList2Rot(rots,currentCamera);
    vector pos = llGetPos() + (savedPos * llGetRot());
    rotation rot = savedRot * llGetRot();
    llSetCameraParams([CAMERA_ACTIVE,TRUE,CAMERA_FOCUS_LOCKED,TRUE,CAMERA_POSITION_LOCKED,TRUE,CAMERA_POSITION,pos,CAMERA_FOCUS,pos + (<0.1,0,0>*rot)]);
    llRegionSay(-1928371,(string)pos + "|" + (string)rot);
    llSleep(2.0);
}
 
integer notecardState;
integer notecardSize;
integer notecardLine;
 
default {
    state_entry() {
        if (llGetInventoryType("Camera List") != INVENTORY_NOTECARD) {
          llOwnerSay("Notecard missing! Script can't start.  Click to try again.");
          return;
        }
        positions = [];
        rots = [];
        rotation sitrot = llEuler2Rot(<0.0, 0.0, 180.0> * DEG_TO_RAD);
        llSitTarget(<-0.4,0.25,0.6>,sitrot);
        llOwnerSay("Setting up..");
        notecardState = 0;
        llGetNumberOfNotecardLines("Camera List");
    }
 
    changed(integer thechange) {
        if (llAvatarOnSitTarget() != NULL_KEY) {
            llUnSit(llAvatarOnSitTarget());
            llOwnerSay("Sorry, still setting up!..");
        }
    }
 
 
    dataserver(key request, string response) {
        if (notecardState == 0) {
            notecardSize = (integer)response;
            if (notecardSize == 0) {
                llOwnerSay("Notecard is empty!  Script can't start.  Click to try again.");
                return;
            }
            notecardState = 1;
            notecardLine = 0;
            llGetNotecardLine("Camera List",0);
            return;
        }
        if (notecardState == 1) {
            list bits = llParseString2List(response,["|"],[]);
            if (llGetListLength(bits) != 2) {
                llOwnerSay("Bad notecard line " + (string)(notecardLine+1)+"! (" + response + ")  Script can't start.  Click to try again.");
                return;
            }
            positions += [(vector)llList2String(bits,0)];
            rots += [(rotation)llList2String(bits,1)];
            notecardLine++;
 
            if (notecardLine >= (notecardSize-1)) {
                state run;
            } else {
                llGetNotecardLine("Camera List",notecardLine);
            }
        }
    }
 
    on_rez(integer junk) {
        llResetScript();
    }
    touch_start(integer count) {
        if (llDetectedKey(0) != llGetOwner()) return;
        llResetScript();
    }
}
 
 
state run
{
    state_entry() {
        llOwnerSay("Ready!");
        llRegionSay(-1928371,(string)llGetPos() + "|" + (string)llGetRot());  
    }
 
    on_rez(integer junk) {
        llResetScript();
    }
 
 
    changed(integer thechange) {
        if (llAvatarOnSitTarget() != NULL_KEY) {
            sitter = llAvatarOnSitTarget();
            //if (sitter != llGetOwner()) {
            //    llOwnerSay("Sorry, only the owner can view the cameras.");
            //    llUnSit(sitter);
            //    sitter = NULL_KEY;
            //    return;
           // }
            gotperms = FALSE;
            llRequestPermissions(sitter,PERMISSION_TRACK_CAMERA | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA);
        } else {
            sitter = NULL_KEY;     
            llReleaseControls();
            llRegionSay(-1928371,(string)llGetPos() + "|" + (string)llGetRot());
            gotperms = FALSE;
            if (listenHandle != -1) {
                llListenRemove(listenHandle);
                listenHandle = -1;
            }
        }
    }
 
    run_time_permissions(integer newperms) {
        if ((newperms & (PERMISSION_TRACK_CAMERA | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA)) > 0) {
            gotperms = TRUE;
            llTakeControls(CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT, TRUE, FALSE);
            currentCamera = 0;
            listenHandle = llListen(-1928372,"",NULL_KEY,"");
            if (llGetListLength(positions) == 0) {
                llSay(0,"No camera positions set up!");
            } else {
                setCameraLoc();
            }
 
        } else {
            llSay(0,"Error: SL denied me camera permission for some reason. Camera movement will not work.  Sit back down to try again.");
        }
    }

 
    listen(integer channel, string name, key speaker, string message) {
        if (llGetOwnerKey(speaker) != llGetOwner()) return;
        string target = llGetSubString(message,0,35);
        if (target != (string)sitter) return;
        string rest = llGetSubString(message,36,-1);
        if (rest == "+") {
            currentCamera++;
            if (currentCamera >= llGetListLength(positions)) currentCamera = 0;
            setCameraLoc();
        }
        if (rest == "-") {
            currentCamera--;
            if (currentCamera < 0) currentCamera = (llGetListLength(positions)-1);
            setCameraLoc();
        }
    }
 
    control(key junk, integer down, integer edge) {
        integer pressed = down & edge;
        if (pressed & CONTROL_ROT_LEFT) {
            currentCamera--;
            if (currentCamera < 0) currentCamera = (llGetListLength(positions)-1);
            setCameraLoc();
        }
        if (pressed & CONTROL_ROT_RIGHT) {
            currentCamera++;
            if (currentCamera >= llGetListLength(positions)) currentCamera = 0;
            setCameraLoc();
        }
    }
 
}
I use a cube prim (with face 2 coloured) as the camera (lens) proxy and containing the following script to generate the pos/rot data on touch. The avatar sit position in region coords is the value of the variable seat.

Code: Select all

default
{
    state_entry()
    {
        llSay(0, "Script running");
    }
    
    touch_start(integer n)
    {
        vector seat = <285.33099, 381.91382, 28.49560>;
        llOwnerSay((string)(llGetPos()-seat)+"|"+(string)llGetRot());
    }
}
Example notecard (with a couple fields added for other purposes)

Code: Select all

<-21.263638, 12.592039, 5.241079>|<0.684392, -0.092609, -0.226402, 0.686857>|on|null
<-21.263638, 0.086180, 5.241079>|<0.687102, 0.069718, -0.059802, 0.720732>|on|null
<-21.263638, -11.349947, 5.241079>|<0.673483, 0.152935, 0.028479, 0.722648>|on|null
<18.669010, -5.504640, 5.241079>|<-0.033662, 0.689809, 0.716614, 0.097440>|on|null
<19.574314, -10.411653, 5.219137>|<0.701158, -0.072244, -0.706231, 0.066305>|on|null
<19.574314, -9.468355, 1.849931>|<0.664290, -0.240951, -0.667775, 0.233961>|on|null
<46.369755, -20.111757, 5.219137>|<0.707598, 0.007904, 0.005143, 0.706552>|on|null
<22.160160, -36.719667, 6.954656>|<0.709598, -0.022756, 0.017281, 0.704027>|on|null
<273.705414, 376.207001, 33.736679>|<0.017709, 0.155429, 0.842143, 0.516066>|on|null
If I find the source I'll add it later.

For completeness, here is a single perspective capture/release script by Dora Gustafson whose Bezier curve script I'm also currently playing with.

https://wiki.secondlife.com/wiki/User:D ... CameraView
Graham Mills
Posts: 1314
Joined: Sun Dec 23, 2012 2:26 pm
Has thanked: 1134 times
Been thanked: 1142 times

Re: Camera Automation

Post by Graham Mills »

In similar vein, this works as a HUD script, ie sitting optional. Touching the HUD grabs the avatar camera, the position of which is then controlled by cursor keys/numeric keypad. Max distance 50 m apparently (at least in SL). Touch HUD again to release the camera. If you didn't want the HUD visible I guess you could make it transparent and control it via a listen event.

One assignment glitch corrected so it compiles/runs in opensim.

https://github.com/Fabber181/camera_con ... script.lsl

Code: Select all

// :CATEGORY:Camera
// :NAME:ControlCam
// :AUTHOR:Azurei Ash
// :CREATED:2010-01-10 05:20:56.000
// :EDITED:2013-09-18 15:38:51
// :ID:203
// :NUM:277
// :REV:1.0
// :WORLD:Second Life
// :DESCRIPTION:
// ControlCam.lsl
// :CODE:


// ControlCam script, by Azurei Ash, feel free to use and distribute
// To be used as a HUD attachment, touch to turn on, touch again to turn off
// HUD toggle by Ariane Brodie

// Initial camera position relative to avatar
// <1,0,.75> = 1 meter forward, 0 meters left, .75 meters up
vector CAMOFFSET=<1,0,.75>;

// camera is moved MOVERATE meters each control event for movement
// used by these controls: forward, back, left, right, up, down
// lower is slower/smoother, higher is faster/jumpier
float MOVERATE=0.5;

// camera is rotated SPINRATE degrees each control event for rotation
// used by these controls: rotate left, rotate right
// lower is slower/smoother, higher is faster/jumpier
// also a good idea to have this number divide 360 evenly
float SPINRATE=0.2;

// The above MOVERATE/SPINRATE will be multiplied by their corresponding
// LFACTOR while the left mouse button is held down
// LFACTORM corresponds to MOVERATE
// LFACTORS corresponds to SPINRATE
float LFACTORM=0.5;
float LFACTORS=0.5;

// maximum distance the camera can move away from the user, currently (SL1.9) this is 50m
float MAXDIST=50.0;

// ==================== SCRIPTERS ONLY BELOW THIS POINT! ;) ==================== //

integer permissions=FALSE;
key owner;

vector position;
rotation facing;


updateCamera()
{
    vector focus=position+llRot2Fwd(facing);
    // The camera was turned on earlier, the position and focus also locked
    llSetCameraParams([
        CAMERA_FOCUS, focus, // region relative position
        CAMERA_POSITION, position // region relative position
    ]);
}

default
{
    state_entry()
    {
        llSetPrimitiveParams([
        PRIM_TEXTURE, ALL_SIDES, "05e736d6-fc50-cc61-ea97-51993ec47c24",
        <0.4,0.1,0>, <0.2,0.41,0>, 0.0]);
    
        if(permissions&PERMISSION_CONTROL_CAMERA)
            llSetCameraParams([CAMERA_ACTIVE, FALSE]);
            llReleaseControls();
    }
    
    touch_start(integer n)
    {
        state cam_on;
    }
}
    
state cam_on
{
    state_entry()
    {
        llSetPrimitiveParams([
            PRIM_TEXTURE, ALL_SIDES, "91a0e647-a69e-f13c-ed93-9bb84d7e790d",
            <0.4,0.1,0>, <0.2,0.41,0>, 0.0]);
        llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA);
    }
    
    touch_start(integer n)
    {
        state default;
    }

    run_time_permissions(integer perm)
    {
        permissions=perm;
        if(permissions)
        {
            llClearCameraParams();
            // These camera parameters will be constant, so set them only once
            llSetCameraParams([
                CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
                CAMERA_FOCUS_LOCKED, TRUE, // (TRUE or FALSE)
                CAMERA_POSITION_LOCKED, TRUE // (TRUE or FALSE)
            ]);

            // level out their rotation
            vector rot=llRot2Euler(llGetRot());
            rot.x = 0;
            rot.y = 0;
            facing = llEuler2Rot(rot);

            // offset and update the camera position
            position = llGetPos()+CAMOFFSET*facing;
            updateCamera();
            llTakeControls(CONTROL_LBUTTON|CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_UP|CONTROL_DOWN|CONTROL_LEFT|CONTROL_RIGHT, TRUE, FALSE);
        }
    }

    control(key id, integer held, integer change)
    {
        // adjust the LFACTORs in response to changes in LBUTTON
        if(change&CONTROL_LBUTTON)
        {
            if(held&CONTROL_LBUTTON) // LBUTTON pressed
            {
                MOVERATE *= LFACTORM;
                SPINRATE *= LFACTORS;
            }
            else // LBUTTON released
            {
                MOVERATE /= LFACTORM;
                SPINRATE /= LFACTORS;
            }
        }

        // Only continue if some key is held, other than the left mouse button
        // Mouselook will override the scripted camera, so don't move the camera if in mouselook
        if((held&~CONTROL_LBUTTON) && !(llGetAgentInfo(owner)&AGENT_MOUSELOOK))
        {
            // Temporary position used, updated position may be out of range
            vector pos=position;
    
            // react to any held controls
            if(held&CONTROL_ROT_LEFT)
            {
                facing *= llAxisAngle2Rot(<0,0,1>, SPINRATE*DEG_TO_RAD);
            }
            if(held&CONTROL_ROT_RIGHT)
            {
                facing *= llAxisAngle2Rot(<0,0,1>, -SPINRATE*DEG_TO_RAD);
            }
            if(held&CONTROL_FWD)
            {
                pos += MOVERATE*llRot2Fwd(facing);
            }
            if(held&CONTROL_BACK)
            {
                pos -= MOVERATE*llRot2Fwd(facing);
            }
            if(held&CONTROL_UP)
            {
                pos += MOVERATE*llRot2Up(facing);
            }
            if(held&CONTROL_DOWN)
            {
                pos -= MOVERATE*llRot2Up(facing);
            }
            if(held&CONTROL_LEFT)
            {
                pos += MOVERATE*llRot2Left(facing);
            }
            if(held&CONTROL_RIGHT)
            {
                pos -= MOVERATE*llRot2Left(facing);
            }
    
            // only update position with the new one if it is in range
            if(llVecDist(pos, llGetPos()) <= MAXDIST)
                position = pos;
    
            updateCamera();
        }
    }
}     // end 
Post Reply