Elsewhere, I discussed how to use the Napier equations to rotate the aircraft object (in a display) and the flight path (in a flight simulation). Because of the way three.js handles 3D objects, you can use linked 3D objects to correctly rotate your aircraft and perform these calculations. This is especially useful when attempting to compute yaw.
You can start by assigning variables:
// Inputs: let ACBDif = 0; // Bank let PPPDif = 0; // Pitch (along Pitch plane) let YawDif = 0; // Yaw (along Yaw plane) // Aircraft Rotation (Relative to Surface) let ACBank = 0; // Bank let ACPtch = 0; // Pitch let ACHead = 0; // Heading // Useful Constants const PieVal = Math.PI; // PI const DegRad = PieVal / 180; // Convert Degrees to Radians const RadDeg = 180 / PieVal; // Convert Radians to Degrees
You can then create the linked parent/child objects. The parent object (AirAxe) contains the current position of the aircraft. The child object (AirPBY) is linked to AirAxe so that AirPBY rotation is determined by the rotation of the AirAxe object. This provides the correct framework for making subsequent pitch, bank and yaw changes. The quaternion is used to temporarily store the combined rotation of AirAxe and AirPBY.
const AirAxe = new THREE.Object3D(); AirAxe.rotation.order = "YXZ"; scene.add(AirAxe); const AirPBY = new THREE.Object3D(); AirPBY.rotation.order = "YXZ"; AirAxe.add(AirPBY); var quaternion = new THREE.Quaternion(); // Enter Starting Values in AirAxe AirAxe.rotation.z = Mod360(360-ACBank) * DegRad; AirAxe.rotation.x = Mod360(ACPtch) * DegRad; AirAxe.rotation.y = Mod360(-ACHead) * DegRad;
Here is the subroutine for making the changes:
function roteAirObj() { // Make Bank, Pitch and Yaw Changes to AirPBY AirPBY.rotation.z = -ACBDif*DegRad; AirPBY.rotation.x = PPPDif*DegRad; AirPBY.rotation.y = -YawDif*DegRad; // Transfer Combined Rotation to AirAxe AirPBY.getWorldQuaternion(quaternion); AirAxe.setRotationFromQuaternion(quaternion); // Zero Out AirObj Rotations (so changes not doubled) AirPBY.rotation.z = 0; AirPBY.rotation.x = 0; AirPBY.rotation.y = 0; // Load Resulting Values into Variables (for display) ACBank = Mod360(-AirAxe.rotation.z*RadDeg); ACPtch = AirAxe.rotation.x*RadDeg; // Update AirAxe Heading for Bank (updated later) ACHead = Mod360(-AirAxe.rotation.y*RadDeg); ACHead = Mod360(ACHead+ACHSpd); AirAxe.rotation.y = -ACHead*DegRad; }
Changes that affect only AirAxe are made after the update. This is because changes to the parent object will not be made until the next cycle. In the static display version (shown above), this includes the estimated change in Heading due to ACBank. In the flight simulation version (ACflytEZ), this includes the subsequent adjustment to ACPtch due to gravity which is used to compute the change in Heading.
In Full View, use the Arrow Keys to move Ailerons and Elevator and Z/X Keys to move Rudder.