llSetVehicleFlags(); VEHICLE_FLAG_CAMERA_DECOUPLED does not work
complete
Tactical UwU
When applying VEHICLE_FLAG_CAMERA_DECOUPLED to any object, the camera is still locked to the vehicle rotation. For most vehicles, this isn't an issue and the coupled camera works as documented. However, for vehicles with high velocities, turn radius, or are intended to be driven over rough terrain, this makes them extremely nauseating and in some cases borderline impossible to control.
A fix for this feature, or an alternative solution, should be considered.
Log In
SL Feedback
Merged in a post from Infrared Starlight:
Title: Link Camera Decoupling
Details: There is a little bit of an oversight with the vehicle flags; you can do VEHICLE_FLAG_CAMERA_DECOUPLED specifically
with
VEHICLE_FLAG_MOUSELOOK_STEER/BANK, but you cannot use that functionality without also declaring those flags. There are many circumstances wherein you would desire this behaviour: tanks, helicopters (probably), mechs, and any other circumstance wherein the user would not want the camera to be affected by rotation. It would additionally be nice if instead of affecting all
links, it would be able to be set per
link.For example, a helicopter pilot might want the coupled behaviour to affect them, so that they may fly in relative motion as normally expected by MOUSELOOK_STEER. However, a gunner might want the decoupled behaviour so that they may accurately track a target, effectively adding a form of "gyrostabilization" by way of not externally influencing their point of aim.
Maestro Linden
complete
This issue was addressed by Leviathan's wiki edit to clarify the scope of VEHICLE_FLAG_CAMERA_DECOUPLED :
Maestro Linden
under review
Maestro Linden
Thanks for sharing the test script. I took a look at the script and flew the vehicle around. I see what you mean about the angular velocity becoming unwieldy when in mouselook mode and rotating the camera ~90 degrees from the vehicle's forward axis - I believe that's because the strength of
llRotLookAt
is proportional to the angle between the current and target rotations.As far as I know, the https://wiki.secondlife.com/wiki/VEHICLE_FLAG_CAMERA_DECOUPLED flag
only
applies to mouselook steering using the LSL vehicle API (i.e. using either VEHICLE_FLAG_MOUSELOOK_STEER or VEHICLE_FLAG_MOUSELOOK_BANK). Since your vehicle is being rotated in by llRotLookAt(llGetCameraRot(),1.0,0.5)
in mouselook mode, the LSL vehicle flags, including VEHICLE_FLAG_CAMERA_DECOUPLED, would not directly come into play.I think that if you want to continue using llRotLookAt for mouselook steering, the script needs some logic to alter the parameters to clamp the its force when the angle between the vehicle and camera forward axes exceeds a certain threshold.
I'm leaving this open for now so that other Lindens can review.
Maestro Linden
needs info
Tactical UwU can you share a basic repro script and specific repro steps? My own test vehicle exhibits very different behavior when VEHICLE_FLAG_CAMERA_DECOUPLED is enabled vs disabled. Here's what I did:
- Rez a default box
- Add the vehicle script shown below to the box. Note that it sets the VEHICLE_FLAG_MOUSELOOK_STEERandVEHICLE_FLAG_CAMERA_DECOUPLED` flags by default.
- Sit on the vehicle
- Enter mouselook mode, and look 45 degrees to the right
- Note the vehicle's steering behavior
- Stand up from the vehicle.
- Edit line 47 of the script, and set integer flags = VEHICLE_FLAG_MOUSELOOK_STEER;(removing the VEHICLE_FLAG_CAMERA_DECOUPLED flag)
- Sit on the vehicle, and try the same mouselook steering as in step (4)
The results I see are:
* In step (4), with VEHICLE_FLAG_CAMERA_DECOUPLED
enabled
, the vehicle steers itself to face the same direction as the mouselook camera, in an underdamped oscillating manner. The vehicle has some overshot as it gets steered in the direction of the mouselook camera, but eventually converges to the direction the mouselook reticle points at.* In step (8), with VEHICLE_FLAG_CAMERA_DECOUPLED
disabled
, the vehicle continuously steers itself in the a constant direction at high speed. This is because the vehicle is being steered according to the mouselook camera's rotation relative to the vehicle, which remains unchanged until the user moves their mouse.* Video showing the difference: https://youtu.be/vaKRwSqoknU
key avatar;
default
{
state_entry()
{
llSay(0, "let's go");
llSetScale(<4,2.5,1>);
llSitTarget(<-1,0.05,0>, ZERO_ROTATION); // have the agent sit back a bit so we can read floating text
llSetVehicleType(4);
// most friction for left-right, least for up-down
llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <2, 2, 2> );
// no angular friction
llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, <2, 2, 2 >);
// linear motor wins after about a second, decays after about a minute
llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0> );
llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE, 1 );
llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 60 );
// agular motor wins after a second, decays in less time than that
llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, <0, 0, 0> );
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, 1 );
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 0.8 );
// no hover
llSetVehicleFloatParam( VEHICLE_HOVER_HEIGHT, 0 );
llSetVehicleFloatParam( VEHICLE_HOVER_EFFICIENCY, 0 );
llSetVehicleFloatParam( VEHICLE_HOVER_TIMESCALE, 10 );
llSetVehicleFloatParam( VEHICLE_BUOYANCY, 1 );
// maximum linear deflection with timescale of 2 seconds
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1 );
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 2 );
// no angular deflection
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0 );
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 10 );
// critically damped vertical attractor
llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0 );
llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 10 );
// weak negative critically damped banking
llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 0.0 );
// llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 1 );
llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 1000 );
// default rotation of local frame
llSetVehicleRotationParam( VEHICLE_REFERENCE_FRAME, <0, 0, 0, 0> );
// remove these flags
llRemoveVehicleFlags(VEHICLE_FLAG_LIMIT_MOTOR_UP | VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_LIMIT_ROLL_ONLY | VEHICLE_FLAG_MOUSELOOK_STEER | VEHICLE_FLAG_CAMERA_DECOUPLED);
integer flags = VEHICLE_FLAG_MOUSELOOK_STEER | VEHICLE_FLAG_CAMERA_DECOUPLED;
llSetVehicleFlags(flags);
}
changed(integer change)
{
if(change & CHANGED_LINK)
{
key agent = llAvatarOnSitTarget();
if (agent)
{
llRequestPermissions(agent, PERMISSION_TAKE_CONTROLS | PERMISSION_TRACK_CAMERA);
llSetStatus(STATUS_PHYSICS, TRUE);
llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, TRUE);
}
else
{
llSetTimerEvent(0);
}
}
}
run_time_permissions(integer perm)
{
if (perm)
{
//llStartAnimation("SpeedbuildPose1");
llTakeControls (CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE);
llSetTimerEvent(0.1);
}
}
control(key id, integer held, integer change)
{
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <5.0, 5.0, 5.0>);
}
timer()
{
rotation agent_cam_rot = llGetCameraRot();
rotation vehicle_rot = llGetRot(); // this script should be in the root prim
llSetText("cam rot: " + (string)agent_cam_rot + "\nvehicle rot: " + (string)llGetRot()
+ "\nangle between (deg):" + (string)(llAngleBetween(agent_cam_rot, vehicle_rot)*RAD_TO_DEG),
<1,1,1>, 1);
}
}
Tactical UwU
Maestro Linden My method is a little different since the vehicle I'm working on is for LLCS, so there's 2 moving parts.
However, I was able to reproduce the issue using the script here: https://github.com/MalefactorIX/SLMC-Script-Starter-Kit/blob/master/Other/Jet.lsl
In the case of the former, I only defined the vehicle type and flags - no other params are defined.
In both instances, llRotLookAt is used as the goal is to have the vehicle rotate behind the camera as opposed to 1-to-1 movement and only on a specific axis. However, when doing so, the camera remains coupled to the object being sat upon. This remains true even when using angular_motor to steer the vehicle.
After using the code you provided, I can confirm it replicates the results you demonstrated. It would appear this only works with rotations achieved through VEHICLE_MOUSELOOK_STEER, and that caveat not documented so I assumed it was a bug.
Leviathan Linden
Tactical UwU: I examined the code and verified: the VEHICLE_FLAG_CAMERA_DECOUPLED only has an effect when either VEHICLE_FLAG_MOUSELOOK_STEER or VEHICLE_FLAG_MOUSELOOK_BANK are also set. In fact, the flag is completely ignored server-side, except to set a bit in the flags field of the ObjectUpdate message sent to the client. The SL client then uses that flag to decide how to compute the mouselook camera's final world-frame orientation... whether it is relative to the vehicle's orientation (coupled) or not (decoupled).
I updated the wiki in an attempt to make this more clear.
Tactical UwU
Leviathan Linden Thank you! With this information, I was able to develop a workaround by using _STEER and locking undesired axis via llSetStatus.