How to find a torque to rotate an object towards a desired rotation

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By worthing

I have a rigidboy that I’d like to rotate to point towards the player (and towards other orientations) using an applied torque.
Basically what I’m looking for is to:

  1. Create a Quaternion from a vector3 that points in the desired direction while maintaining a desired “up” direction/axis (similar to unity’s Quaternion.LookRotation() Unity - Scripting API: Quaternion.LookRotation)

  2. find a torque vector3 between the objects current rotation and the desired quaternion found in step 1.

Here is my current implementation which kinda works, but it doesn’t maintain an “up direction” as it just outputs torques along the x and y axis.

desired_torque = self.global_transform.basis.xform_inv(vector_to_target.cross(self.global_transform.basis.z)).normalized()

To be clear, I’m not currently concerned about making the object smoothly stop when it reaches the desired rotation. I know I need to create a PID controller for that, and there’s plenty of good sources on that.

Also, if anyone knows a good in depth guide to rotations and quaternions that would be greatly appreciated.
Thanks!

Have you tried locking it to the y-axis?

Ertain | 2021-01-13 01:39

I don’t think that would accomplish what I’m wanting. I don’t want the object to always be upright, I just want it to end it’s rotation upright. And sometimes the goal orientation would have a different “up direction” anyways.

worthing | 2021-01-13 02:00

:bust_in_silhouette: Reply From: Andrea

Create a Quaternion from a vector3 that points in the desired direction while maintaining a desired “up” direction/axis

use looking_at()

var new_transform=old_transform.looking_at(target, up)

Returns a copy of the transform rotated such that its -Z axis points towards the target position.
The transform will first be rotated around the given up vector, and then fully aligned to the target by a further rotation around an axis perpendicular to both the target and up vectors.

find a torque vector3 between the objects current rotation and the desired quaternion found in step 1.

not sure i understood what you mean, you are probably looking for the orthogonal vector to both old_transform.basis.z and new_transform.basis.z, therefore the cross product

var rotating_vector=old_transform.basis.z.cross(new_transform.basis.z)

this is a good starting point for transform understanding, with a few examples as well

i just realized that a simpler way to get the rotating_vector (if i understood what you mean) is to simply doing the cross product between the object facing direction and the object-payer relative position

object.transform.basis.z.cross(object.global_translation-player.global_translation)

Andrea | 2021-01-13 16:03

How did I miss looking_at()? Thank you! That’s exactly what I was looking for, at least in solving the first step.

As far as finding the torque. To clarify, I’m looking to find a torque that when applied to the object, will rotate it towards the desired rotation (the transform found in step one)

The solution you provided seems to be basically the same as I used. The issue is that it only uses vector3’s as the input, so it will output a torque to face towards the desired rotation, but not with respect to the desired up direction.

worthing | 2021-01-13 21:24

:bust_in_silhouette: Reply From: worthing

Found a solution!

Andrea showed me how to find the desired transform and on reddit /u/bacb pointed me to the book Artifical Intelligence for Games to find the rest of the solution. I don’t quite understand all the math yet as I just very quickly implemented it as seen in the book, so I don’t know exactly WHY it works, but it does work!

var desired_rotation = (Quat)enemy.transform.looking_at(player.transform.origin, Vector3.UP).basis)
var quat_change = Quat(enemy.transform.basis).inverse() * desired_rotation)
var angle = 2 * acos(quat_change.w)
var axis
if (angle == 0):
	axis = Vector3.ZERO
else:
	axis = (1 / sin(angle/2)) * Vector3(quat_change.x, quat_change.y, quat_change.z)
var torque = axis.normalized

You can find a uh…“sample” of the book by googling “Artificial Intelligence for Games PDF” and the relevant section is found in 3.9.3

To paraphrase it, first find the rotation required to move from the current rotation to the desired rotation. You then convert that quaternion to an axis and an angle. The axis is the torque. The math can be found in the book.

I’m pretty sure that much of this can be replaced with built in functions, but I haven’t found them yet.