- Home /
Calculating trajectory of elliptical orbit?
Hey, yesterday I did a basic script what draws trajectory of an Object in future. Here's a part what actually calculate all that. (I already asked simillar question but there was no answer at all and now I actually understand what I need).
for(i = 0; i < 30; i++)
{
x = rigidbody.velocity.x * i;
z = rigidbody.velocity.z * i;
y = rigidbody.velocity.y * i + (Physics.gravity.y)/2 * Mathf.Pow(i, 2);
var pos = Vector3(x,y,z);
lineRenderer.SetPosition(i,transform.position + pos);
//y = yvo * t * g/2 * i^2;
}
And It look like this(look at attachment with red trajectory)
Now I want to modify it so it will draw orbit of satellite what orbits planet so It will look somewhat like this(look at attachment with planet and satellite)
Here's a script what I use to simulate Gravity (attached to object with rigidbody what doesn't use gravity).
var other : GameObject; //planet
var gravity : float = 10;
var dist : float;
var distSqr : float;
var force : float;
var dir : Vector3;
function FixedUpdate()
{
AddGravity();
}
function AddGravity()
{
dir = (other.transform.position - transform.position); //force direction
dist = Vector3.Distance(other.transform.position, transform.position); //calculate distance between object and planet
distSqr = dist * dist; //distance^2
force = gravity / distSqr; //calculate force
rigidbody.AddForce(dir.normalized * force, ForceMode.Acceleration); //add force
}
If you have any idea how can I achieve that please let me know :).
A few things I can think of, I'm guessing your second script just results in your object falling toward the orbit centre? This is probably because you have no motion perpendicular to the dir of gravity to cause an orbit, You can find the maths to calculate this by searching for $$anonymous$$epler's second law of planetary motion, alternatively and probably easier, if you make sure that your rigidbody has no drag forces, you could simply give the planet an initial perpedicular force or push, and the physics engine ~should~ produce an orbit (given the initial value is within some range based on distance and mass of you central object).
The other little thing you should change is calculating your distSqr value, calculating distance and then squaring is not very efficient as finding the distance uses an algorithm that squareroots a number which is not a very efficient algorithm. doing distSqr = dir.sqr$$anonymous$$agnitude;
would be far more efficient!
Yeah that script may not be the most efficient but that's not the problem. Satellite is orbiting the planet the way it should(just adding a push with another script in function Start() ). $$anonymous$$y problem is how do I calculate where the satellite will be in next sec, 2sec and so on; so I can predict the whole orbit.
Answer by Scribe · Oct 09, 2014 at 09:50 PM
Hi again, sorry for the delay!
So when writing that comment I hadn't understood the question, my suggestion would be to basically run a fast simulation of what your satellite would do and track the positions it hits. The way I do this is by defining a point and then running a loop which saves the point, the recalculates it's position as it would appear one physics time step later, saves that position and so on. This appears to work nicely apart unless you have your object going very close to the planet with very high gravity, at which point there are so errors caused by the fact that large amounts of distance are covered in the small time step, but I expect these errors might occur with your actual object too. If you need to fix that, try reducing the dt variable!
var other : GameObject;
var gravity : float = 100;
var startingVelocity : Vector3 = Vector3.up;
private var distSqr : float;
private var force : float;
private var dir : Vector3;
private var orbitPoints : Vector3[];
var maxCount : int = 10000;
var simplify : int = 5;
private var privateMaxCount : int;
var lineRenderer : LineRenderer;
function Start () {
privateMaxCount = maxCount;
orbitPoints = new Vector3[privateMaxCount];
lineRenderer = gameObject.AddComponent(LineRenderer);
lineRenderer.SetWidth(0.2,0.2);
ComputeTrajectory();
}
function ComputeTrajectory () {
dir = (other.transform.position - transform.position);
var angle : float = 0;
var dt : float = Time.fixedDeltaTime;
var s : Vector3 = transform.position - other.transform.position;
var lastS : Vector3 = s;
var v : Vector3 = startingVelocity;
var a : Vector3 = dir.normalized*gravity/dir.sqrMagnitude;
var d : Vector3 = dir;
var tempAngleSum : float = 0;
var step : int = 0;
while(angle < 360 && step < privateMaxCount*simplify){
if(step % simplify == 0){
orbitPoints[step/simplify] = s+other.transform.position;
angle += tempAngleSum;
tempAngleSum = 0;
}
d = -s;
a = d.normalized*gravity/d.sqrMagnitude;
v += a*dt;
s += v*dt;
tempAngleSum += Mathf.Abs(Vector3.Angle(s, lastS));
lastS = s;
step ++;
}
lineRenderer.SetVertexCount(step/simplify);
for(var i : int = 0; i < step/simplify; i++){
lineRenderer.SetPosition(i, orbitPoints[i]);
}
}
Hopefully your satellites are (mostly) on fixed orbit paths as this code is quite inefficient and should be called as little as possible!
Hope that helps,
Scribe
EDIT:
var gravityObjects : GravityObject[];
var startingVelocity : Vector3 = Vector3.up;
private var dir : Vector3;
private var orbitPoints : Vector3[];
var maxCount : int = 10000;
var simplify : int = 5;
private var privateMaxCount : int;
private var lineRenderer : LineRenderer;
function Start () {
privateMaxCount = maxCount;
orbitPoints = new Vector3[privateMaxCount];
lineRenderer = gameObject.AddComponent(LineRenderer);
lineRenderer.SetWidth(0.2,0.2);
ComputeTrajectory();
}
function Update(){
if(Input.GetKeyDown(KeyCode.W)){
ComputeTrajectory();
}
}
function ComputeTrajectory () {
var angle : float = 0;
var dt : float = Time.fixedDeltaTime;
var s : Vector3 = transform.position;
var lastS : Vector3 = s;
var v : Vector3 = startingVelocity;
var a : Vector3 = AccelerationCalc(gravityObjects, s);
var tempAngleSum : float = 0;
var step : int = 0;
while(angle < 360 && step < privateMaxCount*simplify){
if(step % simplify == 0){
orbitPoints[step/simplify] = s;
angle += tempAngleSum;
tempAngleSum = 0;
}
a = AccelerationCalc(gravityObjects, s);
v += a*dt;
s += v*dt;
if(gravityObjects.Length == 1){
tempAngleSum += Mathf.Abs(Vector3.Angle(s, lastS));
}
lastS = s;
step ++;
}
lineRenderer.SetVertexCount(step/simplify);
for(var i : int = 0; i < step/simplify; i++){
lineRenderer.SetPosition(i, orbitPoints[i]);
}
}
function AccelerationCalc(goArray : GravityObject[], simPos : Vector3){
var a : Vector3 = Vector3.zero;
for(var i : int = 0; i < goArray.Length; i++){
dir = goArray[i].trans.position - simPos;
gravity = goArray[i].g;
a += dir.normalized*gravity/dir.sqrMagnitude;
}
return a;
}
class GravityObject{
var trans : Transform;
var g : float;
function GravityObject(some_Transform : Transform, grav : float){
trans = some_Transform;
g = grav;
}
}
so here I have set up a new class called GravityObject which just saves the transform and gravity strength of an instance, then I have a new variable which is a list of these GravityObjects and then the acceleration of your satellite is calculated based on each element in the list!
Wow I don't know how you did it, but it works :) Actually it works even better than i expected, now I have to understand what you did there a little better so I'll know exactly how it works :) Thank you! Btw. I'll actually have to edit it a little more on my own so i can use it as Update but at least I have great reference to base on.
To make it better for running from Update, you could increase the dt variable, increase 'simplify' (for large orbits you can make this very large ~100) and merging the second for loop where I actually set the linrenderer positions into the while loop would help a lot as well! If you have any questions about what I've done or having trouble understanding stuff, feel free to ask :)
Yeah I noticed that. Btw do you think theres a way to draw orbit while theres more than one soruce of gravity? Like let's say there are 2 planets close to each other and they are influenting satallite?
You definitely can, though making that efficient enough to work from Update will be quite a challenge, unless you plan to have nothing else in your scene! The other problem is that unless you have some very nice starting conditions, 3 body gravity movements are very erratic and strange, normally ending with your object flying off at infinite speed into space! But check my edit anyway, it should help :)
Haha this is perfect! :)
You are genius my friend, now ill just have to figure it out so it will also work with moving objects :P And I guess that's not a big deal. But seriously, are you physicist or something? I could never fighure that out on my own; Thanks again.
Answer by sorcerer_supreme · Feb 07, 2017 at 01:42 PM
@Scribe Thanks a lot. This post is like 2 years old now. I implemented this trajectory function just like you did, i just kept acceleration constant so that I didn't have to compute it every frame. But the main problem I faced was too many calculations per frame. It never struck me that its not necessary to calculate it in a single frame. This countperFrame trick works like a charm. You are awesome..!!!