Unity Version: 2021.3.25f1
I apologize if this has been addressed before in this forum. I looked for a while and found some things that were close but I think my issue is different.
TL;DR: I think my problem can be solved with this question: Does Unity use x = x0 + v0 * t + 0.5 * a * t^2 to calculate rigidbody positions? If not, what does it use?
I am working on a space simulation game. My current objective is to be able to fly around a real-scale solar system with mostly realistic physics. To reduce the complexity of the gravity calculations, the positions of celestial bodies are determined using Keplerian elements, not the physics simulation. I am trying to predict the path of a spacecraft and display it using a LineRenderer.
My tests involve a system with a star, a planet, and a cube. The star is stationary and exerts gravity. The planet has an orbit defined with Keplerian elements and exerts gravity. The cube has a Rigidbody and is affected by gravity*. I am able to set the initial position and velocity of the cube using Keplerian elements. This test system is all within 20 units of the origin, so I shouldn’t need to worry about precision. The gravity on the cube is calculated like so:
public Vector3d GravitationalAcceleration(Vector3d position)
{
Vector3d acc = Vector3d.Zero();
foreach (var body in celestialBodies)
{
if(body.exertsGravity)
{
Vector3d r = (Vector3d)body.transform.position - position;
Vector3d dir = r.Normalized();
acc += G * body.mass / r.SquareMagnitude() * dir;
}
}
return acc;
}
(Vector3d functions like Vector3 but uses doubles to combat precision issues down the line) I then use AddForce(acc, ForceMode.Acceleration) in FixedUpdate() to apply the acceleration to the cube. That all functions as expected.
To predict the path of the cube and show it to the player, I create a Vector6d array. Vector6d is a data type that lets me store a position and velocity. The first point is found using the position and velocity values of the rigidbody. The rest of the points are found using the following procedure:
0. The timestep is 0.01, which is the fixed timestep in the project settings.
- The acceleration due to gravity (vector a) at the previous point’s position (vector x_(n-1)) and expected positions of celestial bodies.
- The new position vector x_n and velocity vector v_n are calculated by: x_n = x_(n-1) + v_(n-1) * timestep + 0.5 * a * (timestep^2); v_n = v_(n-1) + a * timestep;
- The procedure then repeats until the array is full.
I then make a Vector3 array from the Vector6d array to set the positions of the LineRenderer.
Because the prediction timestep matches the fixed timestep, I would expect the prediction to match the simulation exactly. But it doesn’t. It is really close, but the path keeps changing over time. It shouldn’t do that if it was working properly.
I am testing with 1000 points, which according to the profiler is taking about 2ms to calculate on my machine. So I don’t think it’s performance or framerate related. Using debug statements, I can see that the predicted acceleration due to gravity does not match the simulated gravity at the same point in time:
Both are at 20s since the simulation started, but there is a small difference between the two accelerations.
My best guess is that Unity’s physics does not use the classic x = x0 + v * t + 0.5 * a * t^2 equation for rigidbodies, but I couldn’t find any information about what it might actually use. Does anyone have any idea what could be the problem?
*My custom gravity code, not Unity’s built-in gravity.