[Closed] Align an axis to a plane, using other axis?
Okay, I have a puzzle for any of the matrix rotation experts out there. Say I have two objects at arbitrary rotations. For demonstration purposes, I’ll use a box and a plane.
I want a script to rotate the box in local coordinate space, on an axis of my choosing, to the point where one of its other axes is flat to the plane. (I.e. rotate the x axis to align the y axis, or rotate the y axis to align the x axis). What steps would be involved in doing this?
original state:
rotated y-axis to align x-axis
rotated x-axis to align y-axis
Let’s say you have 2 objects (o1 and o2) – with transform matrices tm1 and tm2 respectively.
And want to rotate o1 around Y axis so that Z axis is in XY plane of o2
Then:
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rota =acos (dot (normalize tm1.row3) (normalize axis3))
zaxis = normalize tm1.row2
qrot = quat (zaxis.x*sin(rota/2)) (zaxis.y*sin(rota/2)) (zaxis.z*sin(rota/2)) (cos(rota/2))
rotate $o1 qrot
Okay, awesome! That works for the Z axis! But… since I don’t really understand HOW it works, I don’t know how to get it to work for X or Y.
Looking at this zaxis = normalize tm1.row2 … I would think that the z axis would be row 3, no? So, I’m a bit confused by what I would need to change for the other axes.
Let’s say you want to rotate vector N around M to fit in XY plane.
- first you need to find projection of N in XY – cross prod of the M and third vector from XYZ (XY is your plane so you need Z, if you want to rotate in XZ – Y etc.)
- find angle betwen N and projection of N in XY (dot product and acos)
- now you have angle and axis (M) – construct quaternion
- rotate object with quat
p.s. zaxis = normalize tm1.row2 – it’s M. forgot why i named it Zaxis)
Okay, I think I’m really close to understanding this now. I’m able to rotate the x around the y by substituting in…
rota = acos (dot (normalize tm1.row1) (normalize axis3))
…and I’m able to rotate the z around the x by by substituting in…
theAxis = normalize tm1.row1
but when I try to change both (i.e. rotate the y or the z around the x) like so…
theAxis = normalize tm1.row1
--theAxis = normalize tm1.row3
axis3 = cross (theAxis) (normalize tm2.row3)
rota = acos (dot (normalize tm1.row2) (normalize axis3))
qRot = quat (theAxis.x * sin(rota/2)) (theAxis.y * sin(rota/2)) (theAxis.z * sin(rota/2)) (cos(rota/2))
rotate $Box01 qRot
…it doesn’t work. What am I doing wrong?
Why bother with quat rotations? Why not just write the new matrix to the transform?
because its shorter. and its even shorter if object-offset matrix of the first object is not 1. And with quats all you need is change transform to objecttransform.
Were you able to take a look at my problem and figure out why I couldn’t get it to work?
it seems i forgot that 3ds max quat rotates in different side)
you need to add inverse in last line. and to ensure you’re rotating the shortest angle add check:
tm1 = $o1.transform
tm2 = $o2.transform
axis3 = cross (normalize tm1.row2) (normalize tm2.row1)
rota = acos (dot (normalize tm1.row3) (normalize axis3))
if (rota > 90) then (rota = rota - 180)
rotaxis = normalize tm1.row2
rquat = quat (rotaxis.x*(sin(rota/2))) (rotaxis.y*(sin(rota/2))) (rotaxis.z*(sin(rota/2))) (cos (rota/2))
rotate $o1 (inverse rquat)
or you can construct new transformation matrix as suggested instead of rotation (to rotate Z around Y to fit in YZ of obj2):
tm1 = $o1.transform
tm2 = $o2.transform
axis3 = cross (normalize tm1.row2) (normalize tm2.row1)
tm1 = scale (matrix3 (normalize (cross tm1.row2 axis3)) (normalize tm1.row2) (normalize axis3) tm1.row4) tm1.scalepart
$o1.transform = tm1
but there is no check for shortest possible rotation in this method.
The second one works (though as you said it can’t find the shortest rotation), but I’m still having problems with the first one, where it sometimes works and sometimes doesn’t.
Is there any reason why this shouldn’t work? Because it doesn’t…
tm1 = $Box01.transform
tm2 = $Plane01.transform
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rot = acos (dot (normalize tm1.row1) (normalize axis3))
if (rot > 90) then (rot = rot - 180)
rotAxis = (normalize tm1.row2)
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate $Box01 (inverse rQuat)