User:Dora Gustafson/wind motor core
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
Therefore, 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
<syntaxhighlight 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(); }
}</syntaxhighlight> A few boats in world use this core now. Two of mine are "Windy" and "Breezy 9'er"