User:Dora Gustafson/wind motor core
Jump to navigation
Jump to search
Wind motor core
For use in virtual sailboats in SL
This wind motor uses four vectors to calculate boat velocity:
- v: boat velocity
- wind: wind velocity, direction at wind's eye
- head: boat heading, normalized vector
- n: sail normal, normalized vector. It doesn't matter which one of two normals is used
- v = head∙(-n∙(v + wind)*n)*head
The tricky thing in a wind motor is that v is a function of v and it can not be isolated
Therefor v is calculated by iteration, i.e. repeated calculations using the previous result
Notes
- head and n are normalized vectors
- It does not matter if the positive or negative sail normal n is used in the equation
- wind is pointing the wind's eye so the wind blows opposite. Thus the minus sign in the equation
- The magnitude of wind is the wind speed
- The magnitude of v is the boat speed
A working LSL script based on this core
// wind motor core, minimal sailboat script by Dora Gustafson, Studio Dora 2016
// use a two prim object: root prim for hull and child prim for sail
// enter this script, rez on water, sit and sail
// up, down arrows for setting sail
// left, right arrows for steering
vector windVector = <.0, 9.0, .0>; // wind from north, 9 m/S
float WindFactor = 12.0; // m/S
float heelFactor = .3;
float threeDEG = 0.052360; // 3°
float MAXSAIL = 1.48353; // 85°
float MINSAIL = 0.174533; // 10°
float sailAngle;
vector linear_motor;
vector angular_motor;
integer sailPrim = 2;
integer hullPrim = 1;
float time = 4.0;
vector blue = <0.0, 0.455, 0.851>;
vector green = <0.18, 0.8, 0.251>;
vector yellow = <1.0, 0.863, 0.0>;
vector red = <1.0, 0.255, 0.212>;
default
{
state_entry()
{
llSetVehicleType(VEHICLE_TYPE_BOAT);
llSetVehicleFloatParam( VEHICLE_HOVER_HEIGHT, 0.001 );
llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 0.0 );
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, .75); // default 4
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1); // default 0.5
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_TIMESCALE, .5); // default 3
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0); // default 0.5
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, .5); // default 5
llSitTarget( <-1.5, .0, 1.25>, ZERO_ROTATION);
sailAngle = MAXSAIL;
}
changed(integer change)
{
if (change & CHANGED_LINK)
{
key sitter = llAvatarOnSitTarget() ;
if(sitter != NULL_KEY)
{
llSetStatus( STATUS_PHYSICS, TRUE);
llRequestPermissions( sitter, PERMISSION_TAKE_CONTROLS);
llSetTimerEvent( time);
}
else
{
llSetStatus( STATUS_PHYSICS, FALSE);
llReleaseControls();
llSetTimerEvent( .0);
}
}
}
run_time_permissions(integer perm)
{
if ( perm & PERMISSION_TAKE_CONTROLS ) llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
}
control(key id, integer level, integer edge)
{
if ( edge & level & ( CONTROL_FWD | CONTROL_BACK) )
{
if ( edge & level & CONTROL_FWD )
{
if ( sailAngle + threeDEG < MAXSAIL ) sailAngle += threeDEG;
}
else if ( edge & level & CONTROL_BACK)
{
if ( sailAngle - threeDEG > MINSAIL ) sailAngle -= threeDEG;
}
llSetTimerEvent( 0.05);
}
else
{
if ( level & (CONTROL_ROT_RIGHT)) angular_motor.z = 0.8;
else if ( level & (CONTROL_ROT_LEFT)) angular_motor.z = -0.8;
else angular_motor.z = 0.0;
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, angular_motor);
}
}
timer()
{
if ( llGetStatus( STATUS_PHYSICS) )
{
// vector capture
rotation sailRot = llGetRot();
vector heading = llRot2Fwd( sailRot);
vector left = llRot2Left( sailRot);
vector velocity = llGetVel();
float speed = llVecMag( velocity);
vector Aw = windVector + velocity;
Aw.z = 0.0;
vector nAw = llVecNorm( Aw);
vector axs = heading%nAw; // up or down axis to turn sail around
float AwAngle = llAcos( heading*nAw); // apparent wind, local angle [0;PI]
// setting sail
float setsail = AwAngle;
if ( setsail > sailAngle ) setsail = sailAngle;
sailRot = llAxisAngle2Rot( axs, setsail);
vector sailnormal = llRot2Left( sailRot)*llGetRot(); // Global
llSetLinkPrimitiveParamsFast( sailPrim, [PRIM_ROT_LOCAL, sailRot'er]);
// Linear and Angular Motors
vector action = ZERO_VECTOR;
if ( llFabs( sailnormal*nAw) > MINSAIL ) action = -(sailnormal*Aw)*sailnormal;
linear_motor.x = WindFactor*action*heading;
llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, linear_motor);
// heel by wind
angular_motor.x = -heelFactor*action*left;
llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, angular_motor);
llSetTimerEvent( time);
// optional signal color
vector color = red;
if ( sailAngle < 0.435*AwAngle ) color = blue;
else if ( sailAngle < 0.565*AwAngle ) color = green;
else if ( sailAngle < 0.825*AwAngle ) color = yellow;
llSetLinkColor( sailPrim, color, ALL_SIDES);
}
else
{
llSetTimerEvent( 0.0);
}
}
on_rez( integer p) { llResetScript(); }
}
A few boats in world use this core now. Two of mine are "Windy" and "Breezy 9'er"