0
\$\begingroup\$

I'm trying to design a space game where the user has 2 types of input:

  • forward and backwards thrust in the current direction
  • change orientation

The game is based on actual physics, for the sake of simplicity we can assume everything is presented as a pointmass.

A pointmass has the following attributes (known by the physics engine):

  • position (vector3)
  • orientation (quaternion)
  • linear_velocity (vector3)
  • angular_velocity (vector3)
  • inverse_mass (float)
  • linear_forces (vector3)
  • angular_forces (vector3)

Given these values, a user clicks a point in space, and commands the spaceship to orient itself in that orientation. As such, we can ignore: position, linear_velocity, linear_forces at that point already. Furthermore we can assume that the maximum angular forces have a set maximum (angular_forces_max >= angular_forces.length()).

My question is now, what is the fastest way to get to the new orientation, given that we also want to have angular velocity set to 0 when we reach this new orientation.

In my thoughts, given these input variables:

  • current orientation: quaternion
  • wanted orientation: quaternion
  • current angular_velocity: vector3
  • wanted angular_velocity: vector3 (nilvector)
  • maximum angular_acceleration: float

And as output:

  • angular_acceleration, vector3 (this will determine the forces how to get to the new orientation)
  • t1 time in seconds how long we will use the positive angular_acceleration forces (speeding up)
  • t2 time in seconds how long we will use the negative angular_acceleration forces (slowing down)

I'm having trouble grasping this concept as a whole, I believe we will need to at least translate the quaternion to a vector + angle, so we can at least add 2 * pi to the angle so we can also calculate it while approaching it from the other side. This due to the fact you can't do a 2 * pi rotation with a quaternion and maintain the same quaternion.


To give an example how this would work in 2D:

w = wanted orientation, angle, in radians
v = wanted angular velocity, in rad/s
w0 = current orientation, angle, in radians
v0 = current angular velocity, in rad/s
a_max = max angular acceleration in rad/(s^2)

w = w0 + v0*t + (a_max/2) * t1_short^2 - (a_max/2) * t2_short^2
v = 0 = v0 + a_max * t1_short - a_max * t2_short
// fill in and substitute the formulas
// store t1_short, t2_short

w + 2*pi = w0 + v0*t + (a_max/2) * t1_long^2 - (a_max/2) * t2_long^2
v = 0 = v0 + a_max * t1_long - a_max * t2_long
// fill in and substitute the formulas
// store t1_long, t2_long

if (t1_short + t2_short) <= (t1_long + t2_long) {
  return (t1_short, t2_short);
} else {
  return (t1_long, t2_long);
}

This gives a deterministic manner of calculating t1 and t2 (acceleration time and deceleration time) in 2D, the forces vector is just a singular element vector here [a_max] (a_max = [a_max].length()).

My question is pretty straightforward, how can we do this in 3D with matrices, vectors, quaternions?

(should this be instead posted to the physics / math department of stack exchange btw?)

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Here's a simple way to handle the case where you have no initial angular velocity. You can transform your start and end quaternions into an angle-axis representation of the desired change in rotation:

Quaternion deltaQuat = endQuat * Quaternion.Inverse(startQuat);

float deltaAngle = Math.Acos(deltaQuat.w) * 2.0f;

Vector3 axis = Vector3.Normalize(new Vector3(deltaQuat.x, deltaQuat.y, deltaQuat.z));

Now you can work in the 2D plane perpendicular to this rotation axis, applying your existing 2D solution to rotate by deltaAngle (let w0 = 0f, w = deltaAngle).

Your resulting angular acceleration will act along the rotation axis: axis * a_max for the accelerating portion and axis * -a_max for the decelerating portion.

The problem of how to extent this to work with arbitrary initial/final angular velocities that might lie out of the plane of rotation between the start and end orientation is more complicated, so I might need to take another stab at that after I've had my coffee, unless someone else can beat me to it. 😁

\$\endgroup\$
3
  • \$\begingroup\$ How would one then calculate the t1 and t2 with those formulas? \$\endgroup\$ Jan 4, 2022 at 21:26
  • 1
    \$\begingroup\$ As I mention in the answer, by "applying your existing 2D solution". We've reduced the problem to rotating in a single plane, so the pseudocode in your question should be all you need from here, for the special case of zero initial and final angular velocity as I mention at the top of the answer. \$\endgroup\$
    – DMGregory
    Jan 4, 2022 at 21:30
  • \$\begingroup\$ I seem to have solved it in 3d even with certain initial velocities, but the major problem I'm still having is that if I have an initial velocity > 0 which is not a velocity on the axis you described, the whole thing just goes crazy and up rotating in seemingly random directions. Code which I currently have: pastebin.com/bhaiKEqV (it's rust but shouldn't hard to understand). If initial velocity is 0, then it works perfectly. \$\endgroup\$ Jan 8, 2022 at 22:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .