Add flight physics overhaul with Warium/Futurism mixins
- Route Warium and Futurism force queues through smoothed per-substep delivery - Evaluate wing, stabilizer, control surface and air brake forces every physics substep - Add optional improved flight model with angle-of-attack lift and stalls - Add auto trim toggled by a client key and a server packet - Add config options, translations, and mixin plugin version gating - Bump mod version to 0.2.0 and bundle Futurism 0.0.4 as a compile-only dependency
This commit is contained in:
1 parent
01817fbec1
commit
4b7fb0e1e8
37 files changed
+1954
-4
No files matched your search
@@ -0,0 +1,74 @@
|
||||
package dev.lumareth.improvedAerodynamics.flight;
|
||||
|
||||
import dev.lumareth.improvedAerodynamics.Config;
|
||||
import org.joml.Matrix3dc;
|
||||
import org.joml.Quaterniondc;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3dc;
|
||||
|
||||
/**
|
||||
* Auto trim for the pitch control surfaces of one control node: while the pilot gives no pitch input it adds a
|
||||
* pitch offset that brings the flight path back to level and then holds it there, cancelling whatever pitching
|
||||
* moment the craft has (off-center weight, thrust line, speed changes).
|
||||
* <p>
|
||||
* Two loops: the flight path angle sets a gentle target pitch rate, and a PI controller moves the trim to reach it.
|
||||
* The trim's effect is measured every substep (torque per unit of pitch input), which gives the pitch axis and lets
|
||||
* the gains be expressed as angular acceleration, so the same tuning works for any craft, speed and altitude.
|
||||
* The trim holds still while the pilot pitches, when too slow, and when wings stall, so it never fights maneuvers.
|
||||
*/
|
||||
final class AutoTrim {
|
||||
// Target pitch rate per radian of flight path angle, and its limit (rad/s)
|
||||
private static final double PATH_GAIN = 0.8;
|
||||
private static final double MAX_PITCH_RATE = 0.1;
|
||||
// Angular acceleration per rad/s of pitch rate error, and integral gain
|
||||
private static final double PROPORTIONAL_GAIN = 3.0;
|
||||
private static final double INTEGRAL_GAIN = 1.5;
|
||||
// Fastest the trim moves, in input per second
|
||||
private static final double TRIM_RATE = 1.0;
|
||||
private static final double PILOT_DEADBAND = 0.01;
|
||||
|
||||
private AutoTrim() {
|
||||
}
|
||||
|
||||
static void update(AeroState.NodeState state, NodeData node, Vector3dc worldVelocity, Quaterniondc rotation,
|
||||
Matrix3dc inertia, double[] w, double dt, boolean stalled) {
|
||||
if (!node.autoTrim()) {
|
||||
state.trimIntegral = 0.0;
|
||||
state.trimOutput = AeroState.moveTowards(state.trimOutput, 0.0, TRIM_RATE * dt);
|
||||
state.savedTrim = 0.0;
|
||||
return;
|
||||
}
|
||||
double authority = Config.TRIM_AUTHORITY.get();
|
||||
double response = state.pitchResponse.length();
|
||||
double speed = worldVelocity.length();
|
||||
boolean hold = Math.abs(node.pitch()) > PILOT_DEADBAND || speed < Config.TRIM_MIN_SPEED.get() || stalled
|
||||
|| response < 1.0E-6;
|
||||
|
||||
double target = state.trimIntegral;
|
||||
if (!hold) {
|
||||
// Pitch axis in ship axes, oriented so that positive rotation is what more pitch input does
|
||||
Vector3d axis = state.pitchResponse.div(response, new Vector3d());
|
||||
double axisInertia = axis.dot(inertia.transform(axis, new Vector3d()));
|
||||
double pitchRate = axis.x * w[0] + axis.y * w[1] + axis.z * w[2];
|
||||
|
||||
// Does rotating about that axis raise the flight path? Sign of the vertical part of axis x direction
|
||||
Vector3d worldAxis = rotation.transform(axis, new Vector3d());
|
||||
Vector3d direction = worldVelocity.normalize(new Vector3d());
|
||||
double noseUp = Math.signum(worldAxis.cross(direction, new Vector3d()).y);
|
||||
double pathAngle = Math.asin(Math.max(-1.0, Math.min(1.0, direction.y)));
|
||||
|
||||
double targetRate = Math.max(-MAX_PITCH_RATE, Math.min(MAX_PITCH_RATE, -PATH_GAIN * pathAngle * noseUp));
|
||||
double error = targetRate - pitchRate;
|
||||
// Pitch input needed per rad/s² of angular acceleration
|
||||
double gain = axisInertia / response;
|
||||
state.trimIntegral = clamp(state.trimIntegral + INTEGRAL_GAIN * error * dt * gain, authority);
|
||||
target = clamp(state.trimIntegral + PROPORTIONAL_GAIN * error * gain, authority);
|
||||
}
|
||||
state.trimOutput = AeroState.moveTowards(state.trimOutput, target, TRIM_RATE * dt);
|
||||
state.savedTrim = state.trimIntegral;
|
||||
}
|
||||
|
||||
private static double clamp(double value, double limit) {
|
||||
return Math.max(-limit, Math.min(limit, value));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user