I’m trying to come up with a better LERP or SLERP. In playing Orbiter (*) (space flight sim), when you use the autopilot to change orientations to face prograde, retrograde, normal or anti-normal, the ship spins in unnecessary directions. The rotations are simple 90/180 degree rotations. (** page 62) I thought that if you sort the rotations by the amount of change, the longest rotation would start first and the others start later making rotations on the x and z axis (I think y is up), in this case, unnecessary. For example, if you have the space shuttles belly facing the Earth (Note: the Enterprise pulls up to a planet with the port side facing the planet) and you want to change from prograde to Orbit Normal (+) to change the plane of your orbit, it’s a simple 90 deg rotation around only the y axis. But, LERP and SLERP start rolling on all axis.
Better Update of Rotational Properties (BURP) tries to fix that. It subtracts the prograde rotation from the current rotation, finds the shortest path (rather than just using whatever the difference is even if it takes the long way around), finds the longest of the x, y, z angles, and then uses the inverse of the time (1 – t) to calculate which axis to rotate and how much change to make. Note: it only does the heavy calculations on the first pass through and saves the results for later iterations.
Does anyone have a library that can give the prograde, retrograde, etc. orientations for the current orbit? All I can find is orbital velocity but, it doesn’t tell which direction it faces.
I’m no mathematician. Can anyone add the spherical part with sin and cos?
Also, can anyone explain how normalizing works in a quaternion, since the w component should be between 0 and 1 but, when you normalize it, it gets normalized with the other components. Or, are the other components clobbered and get clipped to 0 and 1 instead of going from –PI to PI.
From experience, I’ve learned that if I skip a detail, someone will ask me about it so, I’ll try to include everything here. See code below.
Also, I doubt anyone hangs out on the other sites I hang out on, but, I’m posting this or Orbiter and JMonkeyEngine and maybe some astrophysics site, too. I hope this is interesting to someone.
** BURPTest/Orbiter.pdf at master · Mipada/BURPTest · GitHub
On Github is the full Quaternion file. It is borrowed from JMonkeyEngine - with disclaimer attached!
You can play with it or use my test app, BURPTest on github.
If anyone is good at math and can add the sin and cos to make it SLERPish, that would be appreciated.
[code]
//Basic Update of Rotation Properties
//still need to convert to slerp (with sin/cos)
float PI2f = (float)Math.PI * 2f;
float PIf = (float)Math.PI;
Quaternion diff = null;
Vector4f r = new Vector4f();
float max = 0.0f;
public Quaternion burp(Quaternion q0, Quaternion q1, float t){
return burp(q0, q1, t, false);
}
public Quaternion burp(Quaternion q0, Quaternion q1, float t, boolean initialize){
boolean debug = true;
//q0.normalizeLocal();//q0 = q0.normalize()
//q1.normalizeLocal();//q1 = q1.normalize()
if (q0.x == q1.x && q0.y == q1.y && q0.z == q1.z && q0.w == q1.w) {
if (debug) System.out.println("BRUP.Ship.update() q0 = q1");
this.set(q1);
return this;
}
//set diff, max
if (initialize){
if (debug) System.out.println("BRUP.Ship.update() initializing");
if (debug) System.out.println("q0=" + q0);
if (debug) System.out.println("q1=" + q1);
//not the result but the value of diff
if (diff == null) diff = new Quaternion();
diff = q1.subtract(q0);
if (diff.x > PIf){
diff.x = diff.x - PI2f;
}
else if (diff.x < -PIf){
diff.x = diff.x - PI2f;
}
if (diff.y > PIf){
diff.y = diff.y - PI2f;
}
else if (diff.y < -PIf){
diff.y = diff.y - PI2f;
}
if (diff.z > PIf){
diff.z = diff.z - PI2f;
}
else if (diff.z < -PIf){
diff.z = diff.z - PI2f;
}
if (diff.w > PIf){
diff.w = diff.w - PI2f;
}
else if (diff.w < -PIf){
diff.w = diff.w - PI2f;
}
if (debug) System.out.println("diff=" + diff);
//find max
max = 0.0f;
if (debug) System.out.println("abs of x=" + Math.abs(diff.getX()) + ", max=" + max);
max = Math.abs(diff.x);
if (debug) System.out.println("set max to x's max (" + max + ")");
if (debug) System.out.println("abs of y=" + Math.abs(diff.getY()) + ", max=" + max);
if (Math.abs(diff.y) > max){
max = Math.abs(diff.y);
if (debug) System.out.println("set max to y's max (" + max + ")");
}
if (debug) System.out.println("abs of z=" + Math.abs(diff.getZ()) + ", max=" + max);
if (Math.abs(diff.z) > max){
max = Math.abs(diff.z);
if (debug) System.out.println("set max to z's max (" + max + ")");
}
//if (debug) System.out.println("abs of w=" + Math.abs(diff.getW()) + ", max=" + max);
//if (Math.abs(diff.getW()) > max){
// max = Math.abs(diff.getW());
// System.out.println("set max to w's max (" + max + ")");
//}
}//end init
r.x = q0.getX();
r.y = q0.getY();
r.z = q0.getZ();
r.w = q0.getW();
//BURP
if ((float)Math.abs(diff.getX())/max > (1f - t)){//inverse of time
if (debug) System.out.print("x, ");
r.x = q0.getX() + t * diff.getX();
}
if ((float)Math.abs(diff.getY())/max > (1f - t)){
if (debug) System.out.print("y, ");
r.y = q0.getY() + t * diff.getY();
}
if ((float)Math.abs(diff.getZ())/max > (1f - t)){
if (debug) System.out.print("z, ");
r.z = q0.getZ() + t * diff.getZ();
}
//if ((float)Math.abs(diff.getW())/max > (1f - t)){
// System.out.print("w, ");
// r.w = q0.getW() + t * diff.getW();
//}
//noralize/clip
if (r.x > PIf) r.x -= PI2f;
else if (r.x < -PIf) r.x += PI2f;
if (r.y > PIf) r.y -= PI2f;
else if (r.y < -PIf) r.y += PI2f;
if (r.z > PIf) r.z -= PI2f;
else if (r.z < -PIf) r.z += PI2f;
//if (r.w > PIf) r.w -= PI2f;
//else if (r.w < -PIf) r.w += PI2f;
//set
set(r.x, r.y, r.z, r.w);
return this;
}
[\code]