Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: ControlCam - Control your camera with your movement keys

Azurei Ash
The Sticky!
Join date: 12 Jan 2006
Posts: 38
03-27-2006 21:30
Get the new script here:
/15/8f/96534/1.html

Or in my latest post, older versions kept here for historical reference.

Initial release info below:

What's new:

Added the ability to hold down the left mouse button to multiply the two rates by corresponding factors. For example, while holding down the left mouse button the amount the camera moves/rotates each control event is cut in half for finer movement (by default).

Two new variables for tweaking have been added at the top, LFACTORM and LFACTORS, corresponding to movement and spin rates. While the left mouse button is held down, the rates have been multiplied by their factors. When the left mouse button is released, they are divided by their factors to return to their original value. The default values for each are .5, meaning you move and spin at half the rate while holding down the left mouse button.

The next update will include the ability to let someone else follow your camera.

------------

Initial Release info:

The following script is to be placed in an attachment and will allow you to control your camera with your movement keys.

By default, the script will listen for the following listen triggers on channel 1:

camon: Will turn camera control on (if it isn't already being controlled) and will position the scripted camera about a meter in front of the avatar's head.
camoff: Will turn off the scripted camera and reset everything

Use these commands by saying "/1camon" or "/1camoff", you must be wearing an attachment with this script inside.

While on, movement keys will not affect your avatar, but will be used to move/rotate your camera. The controls are much as you would expect:

Forward (W or Up arrow): moves the camera forward
Back (S or Down arrow): moves the camera backward
Rotate Left (A or Left arrow): rotates the camera to the left
Rotate Right (D or Right arrow): rotates the camera to the right
Left (Shift+A or Shift+Left arrow): moves the camera left
Right (Shift+D or Shift+Right arrow): moves the camera right
Up (E or Page Up): moves the camera upward
Down (C or Page Down): moves the camera downward

At this time, I have not yet been able get the camera to tilt up or down (it almost works, but not really) or otherwise modify the pitch. There is also no way I know of to barrel roll. So as is, the camera is always levelled out.

Entering mouselook while using the scripted camera will return you to your avatar's mouselook view. Control inputs will not affect the scripted camera while in mouselook, so when you hit ESC to get back out of mouselook, you will return to the scripted camera position where you were. You can also Alt+Zoom from your scripted camera position, but pressing a control input will move you back to the scripted camera and move it from where it was before you Alt+Zoomed.

In addition, there are some variables defined at the top of the script that you can use to tweak the behavior, they are explained in the script.

Alt+Zoom impaired users, enjoy!

~Azurei Ash

CODE

// ControlCam script, by Azurei Ash, feel free to use and distribute
// To be used in an attachment, use the commands below to turn on/off camera control

// say these commands on the specified channel to turn the camera on or off
integer CHANNEL=1;
string CAMON="camon";
string CAMOFF="camoff";

// 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=6.0;

// 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;

init()
{
owner=llGetOwner();
llListen(CHANNEL, "", owner, CAMON);
llListen(CHANNEL, "", owner, CAMOFF);
}

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()
{
init();
}

attach(key attachedAgent)
{
if (attachedAgent != NULL_KEY)
{
init();
}
else
{
if(permissions&PERMISSION_CONTROL_CAMERA)
llSetCameraParams([CAMERA_ACTIVE, FALSE]);
llReleaseControls();
}
}

listen(integer channel, string name, key id, string message)
{
if(message == CAMON)
{
llRequestPermissions(owner, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA);
}
else // message == CAMOFF, turn the camera off, release controls, and reset the script to make sure everything is released
{
if(permissions&PERMISSION_CONTROL_CAMERA)
llSetCameraParams([CAMERA_ACTIVE, FALSE]);
llReleaseControls();
llResetScript();
}
}

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 = 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();
}
}
}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
03-28-2006 20:00
/15/8f/96534/1.html
_____________________
i've got nothing. ;)
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
03-29-2006 10:38
Thanks, this is awesome! I've been wanting something like this for a month or two, as I've been building in tight quarters. I didn't connect the new camera controls with the ability to do something like this. Thanks a ton!
Azurei Ash
The Sticky!
Join date: 12 Jan 2006
Posts: 38
03-29-2006 20:38
Thanks, glad someone likes it. :-)

And actually, this was quite awkward to implement using the new camera parameters.

It's a very ego-centric camera control system, the camera always WANTS to be pointed at the avatar (well there can be a focus offset, but that can only go out 10 m). If you just set the focus to a position, it will slide back from that position to the avatar. So to get it to look at something else, you have to set and lock the focus to a position. Likewise, the camera position wants to move to a position CAMERA_DISTANCE from the focus, so I went ahead and locked it as well. Once I figured that out it was easy.

There is some awkward behavior if you try to move underground, it will let you move the position underground, but the camera itself will not actually go underground. This is simple enough to fix and I will fix it in a future version.

I also have a few other ideas to add to it like letting others have their scripted camera follow yours and the option to hold down the left mouse button while using the movement keys for finer tuning (ie it won't move as much so you can set the position more precisely if you are trying to set up a picture or such).

That and if I could find a good way to get it to tilt.... or barrel rolling would be fun, but I'm pretty sure that's not going to happen. :D

~Azurei Ash
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
03-30-2006 11:32
Hmm, sounds tricky. I haven't had a chance to work with it yet, but I'll see if I like it, and if not, I might mess with it. If so, I'll post changes here.

As to barrel rolling, we can't do that now unless we're in mouselook and sitting in a plane, so I'd be surprised if the new camera system would let us...
Pierce Portocarrero
Registered User
Join date: 20 Mar 2004
Posts: 65
03-30-2006 19:59
Well done,
As a machinima director this is a super cool script. I can already imagine so many uses. Thanks for throwing this out there.
_____________________
"What would a pre-op transexual in an angora sweater fleeing a horde of zombie women in g-strings do, if he backed himself against a cliff near two midget rhinos dancing around a bonfire to The Smiths?"

Hamlet Linden on Pierce Portocarrero's A Scream in the Dark of the Night
Wuvme Karuna
..:: Spicy Latina ::..
Join date: 6 Jun 2004
Posts: 1,669
04-01-2006 17:18
i really love this!

Good job, i wish there was a way when you moved.. it will "go smooth"

since when you move the camera.. it goes kinda roughly, like when you zoom, it kinda goes in frames.

But good job! and ty for sharing!
_____________________
Azurei Ash
The Sticky!
Join date: 12 Jan 2006
Posts: 38
04-06-2006 18:20
Yes, I'm also looking for ways to make things go smoother.

One way to make it smoother is to decrease the amount it moves each control event using the variables, thus making it so there is less difference between the "frames" and so it will look smoother, though you will move slower as well.

The new LFACTOR's can also help, they can let you move slower/smoother while holding down the left mouse button and normally while not (or you could make them do faster instead by tweaking the LFACTOR's to be greater than 1)

I also made it so that it only sets the CAMERA_ACTIVE, CAMERA_FOCUS_LOCKED, and CAMERA_POSITION_LOCKED initially when the camera is turned on. Now each camera update, only the focus and position are modified, so hopefully this will be a little more efficient as well.
Thorne Kaiser
Nice Guy
Join date: 29 Nov 2005
Posts: 132
04-07-2006 06:21
What do I need to change so that the camera is initially facing me, not my view. So I do not have to spin around to see my avatar?
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
04-07-2006 10:15
Another much more complicated way to make it smoother would be to do the actual llSetCameraParams() in a timer() event. The control event would modify a "delta" (ie "change";) variable... so when you press the forward key down, it adds <MOVERATE,0,0> to the delta-position variable, and when you release, it adds <-MOVERATE,0,0>. Then the timer event could move the camera forward by one delta each timer event.

This'd be trickier to get right, and I haven't tried it yet, but it should result in smoother movement... assuming the llSetCameraParams system can actually handle calls that fast.
Logan Bauer
Inept Adept
Join date: 13 Jun 2004
Posts: 2,237
04-30-2006 01:15
It is very true that the camera commands, while useful, seem way geared towards focusing on and being positioned in relation to the AV wearing/riding...

I made a feature proposal that could help this, if anyone's interested.

Optional smoother transition of llSetCameraParams

Was testing out stuff trying to make a remote-control vehicle/bot, and ran quickly into the same sort of problem with the camera jerking from place to place on a greater scale.

Oh, and, cool script, Azurei! ^_^
Talarus Luan
Ancient Archaean Dragon
Join date: 18 Mar 2006
Posts: 4,831
04-30-2006 11:38
Nice script! Works good. :)

I have one question about camera range, though. Seems that it only will move up to a distance of 50m or so away from be before stopping. This is the normal limitation of the camera outside of the script, so I know it has nothing to do with the script. However, one of my friends can move his camera all the way across a sim and to the far side of another, even cause objects to be created there. Is there a way to change the camera range limitation, or is there something else at work here?
Logan Bauer
Inept Adept
Join date: 13 Jun 2004
Posts: 2,237
04-30-2006 12:07
From: Talarus Luan
Nice script! Works good. :)

I have one question about camera range, though. Seems that it only will move up to a distance of 50m or so away from be before stopping. This is the normal limitation of the camera outside of the script, so I know it has nothing to do with the script. However, one of my friends can move his camera all the way across a sim and to the far side of another, even cause objects to be created there. Is there a way to change the camera range limitation, or is there something else at work here?


I have heard that private island owners can move their camera anywhere on their island, this is the only reason I can think of that he would be able to move his camera more than 50 m from himself...
Azurei Ash
The Sticky!
Join date: 12 Jan 2006
Posts: 38
05-13-2006 22:57
From: Talarus Luan
Nice script! Works good. :)

I have one question about camera range, though. Seems that it only will move up to a distance of 50m or so away from be before stopping. This is the normal limitation of the camera outside of the script, so I know it has nothing to do with the script. However, one of my friends can move his camera all the way across a sim and to the far side of another, even cause objects to be created there. Is there a way to change the camera range limitation, or is there something else at work here?


There's a variable near the top:

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

Up that to change the limitation the script imposes, you will still have SL's limitations. I didn't know that private island owners can move their camera farther on their island, though that is nice.

Sorry I haven't looked at this thread or updated the script in a while. XD

~Azurei
Azurei Ash
The Sticky!
Join date: 12 Jan 2006
Posts: 38
11-17-2006 06:32
Long past time for an update, sorry.

I have updated, here is the new info/script:
What's new in Version 1.2:

I have now removed the distance limit since you can disable your camera contraints from the Client debug menu. (Press Ctrl+Alt+d to enable debug menus at the top of your screen, then Client -> Disable Camera Constraints)

Note that you may be able to crash your client if you move your camera too far away from yourself too rapidly. I had my LFACTORM set to 10 (moving 10 times as fast as normal) when I did some testing. Once you get outside your draw limit, you will only see the terrain, but I was zooming so fast the terrain drawing couldn't keep up and I crashed.

So I would recommend not going beyond the terrain drawing. You can spill over into an adjacent sim fine and maybe even the next one, but probably not farther.

Importante New Update!

The UP and DOWN controls (E and C keys or Page Up and Page Down) will now tilt your camera up and down instead of moving up and down. I figured out that I was multiplying in the wrong order when I tried this before.

It will allow you to tilt past the point where you flip over, but your camera will not turn upside down, instead you will find yourself facing the other direction, only now your tilt controls will be reversed. So if you prefer inverted controls for this, just flip yourself over once. ;)

I have also added a camera resume command. By default you can use "/1camresume" and it will turn control of your camera on, resuming from your previous position. If you have not used the script before, this command will probably put you at the origin point of your sim (fun!).

Also, the CAMON command (use "/1camon" by default) will now take control of your camera at its current position (plus a small bump forward to show you it is on, but this doesn't always seem to work). The script now tracks your camera too so that it can do this. So if you move your camera somewhere normally, it will pick up there when you activate ControlCam. Also, while using ControlCam, you may Alt+Zoom just as you have in the past. Moving will cause the camera to shift back to where it was, but now you can prevent this if you would like by tapping the left mouse button. So now you can move around with ControlCam, then do some Alt+Zooming, then click, and continue using ControlCam from your Alt+Zoomed camera position!

I think that's about it for this (long overdo) update! Expect more updates soon!

~Azurei Ash

CODE

// ControlCam script, by Azurei Ash, feel free to use and distribute
// To be used in an attachment, use the commands below to turn on/off camera control

// say these commands on the specified channel to turn the camera on or off
integer CHANNEL=1;
string CAMON="camon";
string CAMOFF="camoff";
string CAMRESUME="camresume";

// 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=6.0;

// 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;

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

vector position;
rotation facing;

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

default
{
attach(key attachedAgent)
{
llResetScript();
}

state_entry()
{
position=ZERO_VECTOR;
facing=ZERO_ROTATION;
owner=llGetOwner();
llListen(CHANNEL, "", owner, CAMON);
llListen(CHANNEL, "", owner, CAMOFF);
llListen(CHANNEL, "", owner, CAMRESUME);
llRequestPermissions(owner, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA|PERMISSION_TRACK_CAMERA);
}

listen(integer channel, string name, key id, string message)
{
if(message == CAMON)
{
llClearCameraParams();
facing=llGetCameraRot();
position=llGetCameraPos()+MOVERATE*llRot2Fwd(facing);
message = CAMRESUME;
}
if(message == CAMRESUME)
{
// 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)
]);

updateCamera();

llTakeControls(CONTROL_LBUTTON|CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_UP|CONTROL_DOWN|CONTROL_LEFT|CONTROL_RIGHT, TRUE, FALSE);
}
else // message == CAMOFF, turn the camera off, release controls
{
llSetCameraParams([CAMERA_ACTIVE, FALSE]);
llReleaseControls();
// re-request permissions for next time
llRequestPermissions(owner, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA|PERMISSION_TRACK_CAMERA);
}
}

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
{
vector p=llGetCameraPos();
if(p!=position)
{
position=p;
facing=llGetCameraRot();
}
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))
{
// 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_UP)
{
facing = llAxisAngle2Rot(<0,1,0>, -SPINRATE*DEG_TO_RAD)*facing;
}
if(held&CONTROL_DOWN)
{
facing = llAxisAngle2Rot(<0,1,0>, SPINRATE*DEG_TO_RAD)*facing;
}
if(held&CONTROL_FWD)
{
position += MOVERATE*llRot2Fwd(facing);
}
if(held&CONTROL_BACK)
{
position -= MOVERATE*llRot2Fwd(facing);
}
if(held&CONTROL_LEFT)
{
position += MOVERATE*llRot2Left(facing);
}
if(held&CONTROL_RIGHT)
{
position -= MOVERATE*llRot2Left(facing);
}

updateCamera();
}
}
}