Modules / Physics & movement

flight3dplugin

A fixed-wing aeroplane as forces and moments, with a stalling lift polar, drawn from its model.

Putting it in a scene

List it after loader and before render3d. The scene's sim lists the flight3d kind from #plugins/flight3d/flight3d.sim.ts, and every plane is one flight3d row. The browser half draws every row of the kinds listed, from the loader model its plane names. A child scene inherits world.flight3d from the manager scene.

"world": {
  "loader": { "assets": { "camel": { "type": "model", "url": "/games/mygame/assets/camel.glb", "preload": true } } },
  "flight3d": {
    "gravity": 9.81,
    "air": { "density": 1.225, "scaleHeight": 8500, "calm": 1 },
    "materials": { "engineDensity": 40, "wingDensity": 8, "structureDrag": 0.002 },
    "planes": {
      "camel": {
        "airframe": {…},
        "gear": { "wheels": [{ "at": [-0.8, -1.1, -0.3], "radius": 0.35, "spring": 60000, "damper": 4000, "roll": 0.03, "grip": 0.9, "brake": true, "steer": 0 }],
                  "brakeGrip": 0.5, "sink": 4, "touch": [[0, 1.2, 0.4]], "retract": 0, "drag": 0.1 },
        "look": { "model": "camel", "spin": 120, "airbrake": 0.6, "gear": 1.2 }
      }
    },
    "overspeed": 1.2,
    "sweep": 5,
    "mods": { "ground": "terrain3d" }
  }
},
"prefabs": {
  "flight3d": { "type": "camel", "pos": [0, 300, 0], "rot": [0, 0, 0, 1], "vel": [0, 0, -40], "spin": [0, 0, 0],
                "pitch": 0, "roll": 0, "yaw": 0, "throttle": 0.6, "throttling": 0, "airbrake": 0, "brake": 0, "gear": 1, "gearDown": true }
}

World space is x and z across the ground and y up, in metres. The plane's body frame has +X along the right wing, +Y up and −Z along the nose.

Properties

Read from world.flight3d.

.gravity : number

m/s², downward.

.air : { density, scaleHeight, calm }

density is kg/m³ at y = 0. scaleHeight is metres: the density at height y is density · exp(−y / scaleHeight). calm is the speed in m/s below which there is no relative wind to fly on.

.materials : { engineDensity, wingDensity, structureDrag }

What an airframe's mass is priced from. engineDensity is newtons of thrust per kg of engine, wingDensity is kg per m² of wing, and structureDrag is m² of drag area per kg of structure. A plane's mass is structureMass + maxThrust / engineDensity + wingArea · wingDensity, and its structure casts a drag area of structureMass · structureDrag, so structure is never free.

.planes : { [name]: { airframe, gear, look } }

The planes there are, by name. airframe is the sheet, what was bought, with no mass on it, since the mass is the parts'. gear is its wheels and what else of it may touch the ground. look says how the page draws it.

.overspeed : number

The cap on speed, as a multiple of the sheet's top speed at y = 0. A dive rides the cap, with the direction untouched, instead of chattering on it.

.sweep : number

Metres. The path a step flies is checked against the ground this often along it, so a plane at 300 m/s cannot pass through a ridge between two steps.

.mods : { ground }

The plugin that provides the ground (see Mods).

.kinds : string[]

The kinds whose rows are planes. ["flight3d"] when left out. A game whose seat flies its own player row lists player here, and that kind's rule flies the row with step, so a page that runs the scene ahead draws the seat's plane from its copy.

The airframe sheet

Every key is required. Angles are radians. Stability derivatives are written in the aviation frame, x forward, y right, z down, with rates p (roll right), q (nose up) and r (nose right), and keep a textbook's signs.

KeyMeaning
structureMassKilograms of hull.
maxThrust, throttleRateNewtons at full throttle at y = 0, and the lever travel a second while it is pushed. Thrust is maxThrust times the lever, falling with the air's density. A propeller's also falls as propSpeed / speed above propSpeed, so it is power, not force, that runs out.
wingArea, spanm² and metres.
incidenceRadians the wing's zero-lift line is set nose up from the body's −Z (its rigging plus its aerofoil's camber). The angle the wing lifts on is the angle of attack plus this.
clAlpha, clPostStall, alphaStall, stallBlendThe lift polar. Lift is linear in the angle until the flow lets go, then a flat plate's: clAlpha times the angle (per radian), and past the stall clPostStall times sin 2·angle. alphaStall is the angle where it lets go, and stallBlend the half-width of the blend from one to the other. It keys on the angle's size, so the wing stalls the same upside down.
cd0, oswald, cdFlatPlate, brakeCdDrag: the parasite coefficient, the span efficiency of the induced drag, the extra drag after the stall as a flat plate, and the extra drag at full airbrake.
cyBetaSide force per radian of sideslip.
clDeltaA, clPRoll moment from the ailerons and from the roll rate.
cm0, cmAlpha, cmQ, cmDeltaEPitch moment: at zero angle of attack, from angle of attack, from the pitch rate, and from the elevator.
cnBeta, cnR, cnDeltaRYaw moment from sideslip, from the yaw rate, and from the rudder.
maxAileron, maxElevator, maxRudderRadians each surface turns at a full stick.
aileronRate, elevatorRate, rudderRaterad/s each surface moves toward the stick.
rGyrRoll, rGyrPitch, rGyrYawRadii of gyration in metres. The moment of inertia about each axis is the mass times this squared.
propSpeedm/s above which a propeller's thrust falls as propSpeed / speed. 0 for a jet.
engineTorqueN·m the engine puts back on the airframe against its turn, at full throttle.
engineInertia, engineSpinThe spinning engine's inertia in kg·m² and its speed at full throttle in rad/s, positive clockwise seen from the cockpit. Its angular momentum lies along the nose, and turning the airframe turns it, so the engine pushes back. A clockwise engine rolls the plane left under power, drops the nose in a right turn and raises it in a left, and yaws it right in a pull.

gear

KeyMeaning
wheelsA list of wheels, each { at, radius, spring, damper, roll, grip, brake, steer }. at is the axle in the body frame. Where the ground comes nearer the axle than radius, the wheel is pressed in by the difference and pushes back along the ground's normal, as a spring of spring N/m and a damper of damper N·s/m, never pulling. That push buys friction at the tyre: along its rolling direction roll times the push, and brakeGrip times the push times the plane's brake more on a wheel with brake true; across it up to grip times the push. Friction grows over the first 0.5 m/s of slip, so a plane at rest does not chatter. A wheel with steer rolls steer times the yaw stick, in radians, off the nose.
brakeGripThe extra rolling friction coefficient at full brake.
sinkm/s: the plane crashes when a wheel meets the ground faster than this.
touchPoints in the body frame, such as a wingtip, the prop's tip or the tail. The plane crashes when any is below the ground.
retractSeconds the gear takes to travel from one end to the other. Above 0 the gear retracts: gear travels toward gearDown, and is held down while any wheel bears weight. At 0 it is fixed down.
dragm² of drag area the gear adds, times how far it is down.

Only gear locked down (gear 1) has wheels. Below that the plane meets the ground on its touch points, and a landing with the gear up is a crash. A plane also crashes when a wheel is pressed in past its radius, and when the path its centre flies in a step meets the ground. A crashed plane lies where it hit.

look

KeyMeaning
modelThe loader catalogue's model entry the plane is drawn from. It is asked for the first time a row of the plane is seen, and a plane is drawn from the first frame its model has landed.
spinThe propeller's rad/s at full throttle on the page's clock, positive clockwise seen from the cockpit. The page's clock counts a frame as at most a tenth of a second.
airbrakeRadians the airbrake nodes turn at full brake.
gearRadians the gear legs fold away when fully up.

The model is in the body frame, with a node for each moving part on its hinge, its local axes turned so the hinge is the axis it turns about. Each frame every part is turned from its pose in the model by the angle on the row. Every mesh casts and takes shadows, with its material dressed by render3d.

NodeTurns
aileron_left…, aileron_right…About its local X by aileron for the left, by −aileron for the right. A name beginning with either counts. A positive aileron rolls right, the right one's back edge rising and the left's falling.
elevatorAbout X by −elevator. A positive elevator pitches the nose up, the back edge rising.
rudderAbout Y by rudder. A positive rudder yaws the nose right, the back edge swinging right.
airbrake…About X by −airbrake times look.airbrake.
gear_<n>About X by look.gear times how far the gear is up, 1 − gear: leg n folding away, its wheel and steer node with it.
propAbout Z, turning look.spin rad/s at full throttle.
steer_<n>About Y by −steer times the yaw stick, for wheel n of the gear.
wheel_<n>About X by the distance it has rolled over its radius while it is pressed into the ground, at the plane's own forward speed. In the air it spins down over a second and a half. The wheel, or the steer node holding it, is drawn up its leg by how far it is pressed in.

The row

A rule writes type when it makes the plane, and the stick, throttling, airbrake, brake and gearDown. The plugin writes the rest. How fast the plane flies, its angle of attack, its sideslip and how stalled it is are not on the row. They follow from vel and rot, and windAngles and aero hand them to whatever shows them.

FieldMeaning
typeThe name of the plane's entry in .planes.
pos, rot, vel, spinWhere it is in metres, its attitude as a quaternion [x, y, z, w] from body to world, its velocity in m/s in the world frame, and its angular velocity in rad/s in the body frame.
aileron, elevator, rudderThe surfaces' angles in radians, each chasing the stick at its rate.
pitch, roll, yawThe stick, each −1 to 1. Positive pitch is nose up, positive roll is right wing down, and positive yaw is nose right and, on the ground, turns the steered wheels right.
throttleThe lever, 0 to 1.
throttlingWhich way the lever is being pushed, −1 to 1. It moves at the sheet's throttleRate times this.
airbrake, brake0 to 1. brake is the wheel brakes.
gearHow far the gear is down, 0 up to 1 locked down.
gearDownThe gear lever: true down, false up.
pressHow far each wheel of its gear is pressed in, in metres, 0 off the ground. Written every step for the page to draw.
crashedTrue once it has met the ground other than on its wheels.

Methods

From #plugins/flight3d/flight3d.sim.ts. f is world.flight3d. A Quat is [x, y, z, w] and a Vec3 is [x, y, z].

step( p, f, dt, ground? ) : Aero

Steps a plane's row p once, in place, over ground, a function (x, z) => height. With none, the plane has nothing to touch or hit. The surfaces move toward the stick, the lever moves, the forces and moments of the air, the engine and the gear are worked out, the angular velocity and then the attitude are stepped, and then the velocity and then the position, semi-implicitly, which keeps a circling turn from spiralling out at a fixed step. Returns the flight picture of the step.

aero( p, stick, f, airframe, dt ) : Aero

The whole flight picture for one step, without stepping anything, so that a HUD, a panel or a test can read it. stick is { pitch, roll, yaw, airbrake }. airframe is a priced sheet. It returns aoa, slip, speed, qd (dynamic pressure), cl, cd, lift, drag, side, thrust and weight (newtons), stall (0 attached, 1 fully separated), surfaces ({ aileron, elevator, rudder } after moving toward the stick), force (world, newtons) and torque (body, N·m).

windAngles( p, air ) : { aoa, slip, speed }

Speed in m/s, angle of attack in radians (air from below is positive) and sideslip in radians (velocity to the right is positive), from the plane's vel and rot. Below the calm speed both angles are 0.

price( sheet, materials ) : Airframe

A sheet priced: the sheet plus its mass and structureDragArea, both derived. airframeOf(f, type) is plane type's airframe, priced, and modelOf(f, type) is its catalogue entry. massOf(sheet, materials) and dragShadowOf(sheet, materials) are the two numbers alone.

topSpeed( airframe, rho ) : number

The top speed in m/s where full thrust meets parasite drag at density rho. For a jet it is √(thrust / k), and for a propeller past propSpeed it is ∛(thrust · propSpeed / k), where k is half the density times the total parasite drag area, wingArea · cd0 plus the structure's.

stallSpeed( airframe, gravity, rho ) : number

The speed in m/s below which the wing cannot hold the plane up in level flight at density rho.

thrustOf( sheet, throttle, rho, rho0, speed ) : number

Thrust in newtons at a lever, an air density (of rho0 at y = 0) and a speed.

densityAt( air, y ) : number

The air's density at height y.

contact( p, gear, ground ) : { force, torque, press, crash }

What the ground does to a plane on its gear this step: the force (world) and moment (body) of every wheel pressed into it, how far each is pressed, and whether it has crashed. It steps nothing.

impact( ground, a, b, sweep ) : Vec3 | undefined

Where the path from a to b first meets the ground, checked every sweep metres along it and at its end, or undefined when it stays above.

normalOf( ground, x, z ) : Vec3

The ground's unit normal under x, z, its slope read off ground itself 0.5 m either side.

groundOf( w ) : ((x, z) => number) | undefined

The scene's ground, off its ground mod, as a height under x, z. Undefined when the scene names none.

rotate( q, v ) / unrotate( q, v ) : Vec3

A vector turned by the attitude q, body to world, and a world vector in the body frame.

fromHeading( heading ) / fromAttitude( heading, pitch ) : Quat

Attitudes for placing a plane. fromHeading is wings level with the nose heading radians clockwise from −Z seen from above. fromAttitude also puts the nose pitch radians up from level.

noseOf( heading ) : Vec3

The nose's direction for a heading, as fromHeading turns it.

Mods

Name them in world.flight3d.mods.

  • terrain3d
    ground: ground(w, x, z) hands back the height of the ground under a world x, z. With no ground mod the plane flies over nothing, never touches down and never crashes.

In the guide