Estoy usando Unity3D y escribiendo C#
Todos los valores son los valores de la vida real / 100, ya que estoy reduciendo las cosas. (por ejemplo, la constante gravitacional fue 6.67408e-11 / 11 = 6.67408e-15.
Aquí está el código...
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;
}
Para que esto funcione, necesito establecer la constante gravitacional en: 1.59508e-21
Aquí hay una imagen de la órbita, la línea rosa es pasada, no futura (los elementos orbitales calculados que se muestran probablemente sean incorrectos):
Aquí hay una imagen de la órbita después de acelerar el tiempo:
Edición 1:
Usando esta fórmula para la aceleración y la primera parte de la respuesta de Russell Borogove, pude lograr una órbita circular usando estos valores:
y este código:
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;
}
Edición 2: Se agregaron cálculos de gravedad usando el script del acumulador de Russell Borogove a continuación...
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;
}
}
Edición 3: Script de elementos orbitales actualizado (probablemente no 100% correcto)
//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;
Edición más reciente: se solucionó el problema que tenía con la excentricidad incorrecta: estaba calculando incorrectamente la posición relativa.
Gran G es 6.67408e-11 m 3 kg -1 seg - 2 .
Entonces, si usa unidades de 100 km de manera uniforme en lugar de unidades de m, eso es 5 magnitudes diferentes, por lo que G tiene que cambiar en 15 magnitudes porque la dimensión lineal está al cubo.
Las unidades de masa son 100 kg, G usa -1 de esas, por lo que G va en sentido contrario en 2 magnitudes.
No tengo idea de lo que estás haciendo con los segundos. Si los segundos son segundos (y se necesitan 90 minutos para completar una órbita), entonces no hay cambio en G. Si está usando algún otro factor de conversión, entonces duplique la cantidad de ceros por los que está cambiando los segundos para cambiar G.
En cuanto a la inestabilidad, eso es inevitable cuando haces simulaciones de pasos de tiempo de funciones continuas. Puedes dividir tu intervalo de tiempo de actualización de Unity en una pequeña cantidad fija y ejecutar tu función de simulación varias veces para cada cuadro de juego:
float accumulator = 0.0f;
float simtime = 0.001f;
void Update( void )
{
accumulator += Time.deltaTime;
while (accumulator > 0.0f)
{
SimulateGravityForTime( simtime );
accumulator -= simtime;
}
}
Esto ejecuta su sim una vez por cada milisegundo de tiempo transcurrido en el cuadro. Eso debería mantener las cosas bastante estables. El acumulador está ahí para retener fracciones de milisegundos de cuadro a cuadro. Pasará más tiempo de CPU haciendo cálculos repetidos, pero una computadora moderna debería poder permitírselo fácilmente.
Con respecto a las unidades, si estuviera en su lugar, separaría la vista (basada en las transformaciones de Unity) del modelo (la simulación física). Esto le permitiría ejecutar la simulación completamente en unidades estándar, eliminando mucha confusión y reduciendo la probabilidad de errores. Dentro del modelo de física, siempre usaría unidades m/kg/s y realizaría un seguimiento de las posiciones en vectores que no forman parte de las transformaciones de Unity. Una vez por cuadro, convertiría cuidadosamente a unidades de Unity y establecería las posiciones de las transformaciones.
Mathf.Atan2(Mathf.Tan(t / 2), Mathf.Sqrt((1 + e) / (1 - e)))
o2 * Mathf.Atan(Mathf.Tan(t / 2) / Mathf.Sqrt((1 + e) / (1 - e)))
v = v / 100
o v /= 100
después de encontrar la velocidad v , el AP sale correcto, ¿entonces algo todavía está mal por un orden de magnitud en alguna parte?2
en Atan2
las bibliotecas matemáticas informáticas se refiere a dos argumentos, sin multiplicar por 2. Un argumento Atan
no puede diferenciar entre ( + / + ) y ( - / - ) entradas, lo cual es importante en algunas aplicaciones trigonométricas. No sé si este es uno de ellos. La segunda de sus opciones se ve bien, la primera necesita un archivo 2 *
. Si sus resultados son cuerdos para la mitad de la órbita y locos para la otra mitad, necesita Atan2
.
russell borogove
Oblea
russell borogove
Oblea
russell borogove