How Do I Rotate An Object On a Global Axis?

I have an object and I need to rotate it on the global Z axis, but I can’t figure out how I’m supposed to do it. I have the following example from the Rotate Object node:

q = new Quat();
q.fromEuler(vec.x, vec.y, vec.z);
object.transform.rot.mult(q);

But this rotates the object on the local axis.

Well, I guess one way to do it would be to parent it to an empty and rotate the empty around the local Z, which I will just leave aligned with the global Z. There’s got to be another way to do that though.

Ah I figured it out!

q = new Quat();
q.fromEuler(vec.x, vec.y, vec.z);

var ot = object.transform;
var prevLoc = ot.loc;
ot.loc = new Vec4(0, 0, 0);
ot.multMatrix(Mat4.identity().fromQuat(q));
ot.loc = prevLoc;
object.transform.buildMatrix();

Matrix multiplication is weird. Rotations always happen around the center of the universe, so when I applied the rotation matrix ( Mat4.identity().fromQuat(q) ) to the object with Transform.multMatrix the object would rotate around the world center instead of its own center. The solution was to move the object to the center of the world by setting its loc to the center of the universe, rotating the object, and then setting the object’s location to what it was before the rotation. Yay! Now I’m going to submit a PR so that the Rotate Object node allows you to choose between world or local space rotation. :slight_smile:

1 Like

Ah, OK , it only works half-way. Instead of making rotation relative to the world it makes it relative to the parent. :frowning: Is there such a thing as matrix division? I’m still trying to figure this out. I have to figure out a way to un-transform the object to world-space, rotate it, the transform it back. What is a matrix inverse? I tried multiplying the object by the inverse of it’s world transform, but it doesn’t look like that works.

In logic nodes i used “Rotate Object” to do relative rotation on one axis, perhaps you can look at the code ?

Yeah, I’m actually editing the code for that node, but it uses a function that rotates it relative to the objects own transform.

I can’t figure out why this doesn’t work:

q.fromEuler(vec.x, vec.y, vec.z); // Get a Quat from Euler rotation
var ot = object.transform; // Local object transform
var pt = object.parent.transform.world; // Parent world transform
var rt = Mat4.identity().fromQuat(q); // Rotation matrix from Quat
var lt = object.transform.local.clone(); // Local transform copy

ot.multMatrix(Mat4.identity().getInverse(lt), ot.local); // Undo Local Transform
ot.multMatrix(Mat4.identity().getInverse(pt)); // Undo World Transform
// Object should now be at the world center
ot.multMatrix(rt); // Apply rotation matrix
ot.multMatrix(pt); // Reapply world transform
ot.multMatrix(lt); // Repply local transform

Anyway, I’m just going to use the workaround of parenting it to another object for now. If anybody figures out how to do this, I can add it to the Rotate Object node real quick. I’ve already got it ready, I just can’t figure out the math.

I think straight way is to do it by calculating the offset from z axis, using an inverse matrice and then apply rotation.

I don’t understand exactly. Could you give a code or pseudo-code example?

It’s just a math solution/description I think the simplest/best one.
As you know when we apply a rotation in your example, it’s in local space.

So you can easily imagine that if you move first your object at the origin of z, then when you will rotate it here, it will be around z. Then after this rotation, if you reset your object at the preceeding location, “le tour est joué”.
Thus the best way to do it is by using an inverse matrice. It’s only maths.
The cost I think is,
firstly one matrix multplication for rotation

then
one inverse matrix caculation
plus one matrix multiplication to get the offset

then one matrix multiplication to get the new matrix of your object

1 Like

Thanks @Didier, it pretty much worked, but I still couldn’t figure it out in the end, because there are two transforms that you are working with when you have an object that is parented to another object. It would have worked if I was only dealing with the local transform. I think there is something special and weird about the world transform property that makes it different somehow from other transform matrices. This is as far as I got, but it results in some weird rolling motion.

var rt = Mat4.identity().fromQuat(q); // Rotation matrix
var lt = object.transform.local; // Local transform Matrix ( which is relative to parent transform )
var pwt = object.parent.transform.world; // Parent world transform matrix
var localLoc = Mat4.identity().setLoc(lt.getLoc()); // Translation matrix for local transform
var invLocalLoc = Mat4.identity().getInverse(localLoc); // Inverse translation matrix for local transform
var worldLoc = Mat4.identity().setLoc(pwt.getLoc()); // Translation matrix for parent world transform
var invWorldLoc = Mat4.identity().getInverse(worldLoc); // Inverse translation matrix for parent world transform

lt = lt.multmat(invLocalLoc); // "Undo" local translation - should put it at the center of parent space
lt = lt.multmat(invWorldLoc); // "Undo" parent world translation - should put it at the center of the universe, but for some reason it seems a little off
lt = lt.multmat(rt); // Apply rotation matrix
lt = lt.multmat(worldLoc); // Reapply world translation
lt = lt.multmat(localLoc); // Reapply local translation

// Rebuild components of the armory transform object - not native matrix math
object.transform.decompose();
object.transform.buildMatrix();
2 Likes

If I see well what you mean, you have for example to cancel child bone rotation before.