Difference between revisions of "User:Dora Gustafson/wind motor core"
Jump to navigation
Jump to search
(Created page with " == Wind motor core == ==== For use in virtual sailboats in SL ==== This wind motor uses four '''vectors''' to calculate boat velocity: # '''''v''''': boat velocity # '''''win...") |
|||
(One intermediate revision by the same user not shown) | |||
Line 16: | Line 16: | ||
# The magnitude of '''''wind''''' is the wind speed | # The magnitude of '''''wind''''' is the wind speed | ||
# The magnitude of '''''v''''' is the boat speed | # The magnitude of '''''v''''' is the boat speed | ||
==== A working LSL script based on this core ==== | |||
<source lang="lsl2"> | |||
// 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(); } | |||
}</source> | |||
A few boats in world use this core now. Two of mine are "Windy" and "Breezy 9'er" | |||
{{LSLC|Library}} |
Latest revision as of 10:56, 10 December 2016
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"