Ich benutze Unity3D und schreibe C#
Alle Werte sind die realen Werte / 100, da ich die Dinge verkleinere. (z. B. Gravitationskonstante war 6,67408e-11 / 11 = 6,67408e-15.
Hier ist der Code...
void Gravity(Gravity body) {
float dSquared = (body.transform.position - transform.position).sqrMagnitude;
float force = (body.G * shipMass * body.planetMass) / dSquared;
Vector3 forceDirection = (body.transform.position - transform.position).normalized;
Vector3 forceVector = (forceDirection * force);
shipVelocity += forceVector * Time.deltaTime;
transform.position += shipVelocity * Time.deltaTime;
}
Damit dies funktioniert, muss ich die Gravitationskonstante auf 1,59508e-21 einstellen
Hier ist ein Bild der Umlaufbahn, die rosa Linie ist der vergangene, nicht der zukünftige Pfad (die angezeigten berechneten Umlaufbahnelemente sind höchstwahrscheinlich falsch):
Hier ist ein Bild der Umlaufbahn, nachdem ich die Zeit beschleunigt habe:
Bearbeiten 1:
Mit dieser Beschleunigungsformel und dem ersten Teil von Russell Borogoves Antwort konnte ich mit diesen Werten eine kreisförmige Umlaufbahn erreichen:
und dieser Code:
void Gravity(Gravity body) {
float dSquared = (body.transform.position - transform.position).sqrMagnitude;
float M = body.planetMass;
Vector3 forceDirection = (body.transform.position - transform.position).normalized;
float g = G * M / dSquared;
Vector3 forceVector = (forceDirection * g);
shipVelocity += forceVector * Time.deltaTime;
}
Bearbeiten 2: Gravitationsberechnungen mit Russell Borogoves Akkumulator-Skript unten hinzugefügt ...
void Update() {
Gravity(orbitee);
ApplyForce();
}
void ApplyForce() {
transform.position += shipVelocity * Time.deltaTime;
transform.Rotate(transform.forward * shipTorque * Time.deltaTime);
}
void Gravity(Gravity body) {
accumulator += Time.deltaTime;
while (accumulator > 0.0f) {
float dSquared = (body.transform.position - transform.position).sqrMagnitude;
float M = body.planetMass;
Vector3 forceDirection = (body.transform.position - transform.position).normalized;
float g = G * M / dSquared;
Vector3 forceVector = (forceDirection * g);
shipVelocity += forceVector * simtime;
accumulator -= simtime;
}
}
Bearbeiten 3: Aktualisiertes Skript für Orbitalelemente (wahrscheinlich nicht 100% korrekt)
//Mass of satellite
float m1 = shipMass;
//Mass of planet
float m2 = orbiting.planetMass;
float M = m2;
//Relative Position Vector
Vector3 r = FindRelativePosition(orbitee.transform.position, transform);
//Relative Velocity Vector
Vector3 v = shipCurVel;
//#!# add relative to planet velocity
//Specific Angular Momentum
Vector3 h = Vector3.Cross(r, v);
//Standard Gravitational Parameter
float µ = G * (m1 + m2);
//float µ = G * M;
//Eccentricity Vector
Vector3 evec = (Vector3.Cross(v, h) / µ) - (r / Vector3.Magnitude(r));
//Eccentricity
float e = Vector3.Magnitude(evec);
//Vector to Ascending Node #!#
Vector3 n = Vector3.Cross(new Vector3(0, 0, 1), h);
//True Anomaly
float t = Mathf.Acos((Vector3.Dot(evec, r)) / (e * Vector3.Magnitude(r)));
if (Vector3.Dot(r, v) < 0)
t = (2 * Mathf.PI) - t;
//Eccentric Anomaly
float E = 2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)));
//Longitude of Ascending Node (2D)
float Ω = 0;
//Inclination (2D)
float i = 0;
//Argument of Periapsis
float ω = Mathf.Atan2(evec.y, evec.x);
float ωdegrees = ω * (180 / Mathf.PI);
//float ω = Mathf.Acos((Vector3.Dot(n, evec)) / (e * Vector3.Magnitude(n)));
//Mean Anomaly
float MA = E - (e * Mathf.Sin(E));
//Semi-Major Axis
float a = 1 / ((2 / Vector3.Magnitude(r)) - (Mathf.Pow(Vector3.Magnitude(v), 2) / µ));
//Apoapsis
float ap = a * (1 + e);
//Periapsis
float pe = a * (1 - e);
//Orbital Period
float T = (2 * Mathf.PI) * Mathf.Sqrt(Mathf.Pow(a, 3) / µ)/60;
Letzte Änderung: Problem behoben, das ich mit falscher Exzentrizität hatte - die relative Position wurde falsch berechnet.
Großes G ist 6,67408e-11 m 3 kg -1 s - 2 .
Wenn Sie also einheitlich 100-km-Einheiten anstelle von m-Einheiten verwenden, sind das 5 Größenordnungen unterschiedlich, also muss sich G um 15 Größenordnungen ändern, da die lineare Dimension dreifach ist.
Masseneinheiten sind 100 kg, G verwendet -1 davon, also geht G um 2 Größenordnungen in die andere Richtung.
Ich habe keine Ahnung, was du mit Sekunden machst. Wenn Sekunden Sekunden sind (und es 90 Minuten dauert, um eine Umlaufbahn zu absolvieren), ändert sich G nicht. Wenn Sie einen anderen Umrechnungsfaktor verwenden, verdoppeln Sie die Anzahl der Nullen, um die Sie Sekunden verschieben, um G zu ändern.
Die Instabilität ist unvermeidlich, wenn Sie Zeitschrittsimulationen kontinuierlicher Funktionen durchführen. Sie können Ihre Unity Update-Zeitscheibe in ein kleines festes Quantum aufteilen und Ihre Simulationsfunktion mehrmals für jeden Spielrahmen ausführen:
float accumulator = 0.0f;
float simtime = 0.001f;
void Update( void )
{
accumulator += Time.deltaTime;
while (accumulator > 0.0f)
{
SimulateGravityForTime( simtime );
accumulator -= simtime;
}
}
Dadurch wird Ihr Sim einmal für jede im Frame verstrichene Millisekunde ausgeführt. Das sollte die Dinge ziemlich stabil halten. Der Akkumulator dient dazu, Bruchteile von Millisekunden von Frame zu Frame zu speichern. Sie verbringen mehr CPU-Zeit mit wiederholten Berechnungen, aber ein moderner Computer sollte sich das problemlos leisten können.
In Bezug auf die Einheiten würde ich an Ihrer Stelle die Ansicht (basierend auf Unity-Transformationen) vom Modell (der Physiksimulation) trennen. Auf diese Weise könnten Sie die Simulation vollständig in Standardeinheiten ausführen, wodurch viel Verwirrung vermieden und die Wahrscheinlichkeit von Fehlern verringert wird. Innerhalb des Physikmodells würden Sie immer m/kg/s-Einheiten verwenden und Positionen in Vektoren verfolgen, die nicht Teil von Unity-Transformationen sind. Einmal pro Frame würden Sie sorgfältig in Unity-Einheiten konvertieren und die Positionen der Transformationen festlegen.
Mathf.Atan2(Mathf.Tan(t / 2), Mathf.Sqrt((1 + e) / (1 - e)))
oder2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)))
v = v / 100
oder v /= 100
nachdem ich die Geschwindigkeit v gefunden habe , kommt der AP richtig heraus, also ist irgendwo noch etwas um eine Größenordnung daneben?2
in Atan2
in mathematischen Computerbibliotheken bezieht sich auf zwei Argumente, die nicht mit 2 multipliziert werden. Ein Argument Atan
kann den Unterschied zwischen ( + / + ) und ( - / - ) Eingaben nicht erkennen, was in einigen Trig-Anwendungen wichtig ist - ich weiß es nicht weiß nicht, ob das einer von ihnen ist. Die zweite Ihrer Optionen sieht richtig aus, die erste benötigt eine 2 *
. Wenn Ihre Ergebnisse für die Hälfte des Orbits vernünftig und für die andere Hälfte verrückt sind, benötigen Sie Atan2
.
Russell Borogove
Waffel
Russell Borogove
Waffel
Russell Borogove