PDA

View Full Version : Align an axis to a plane, using other axis?


Malkalypse
02-27-2012, 07:29 PM
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:
http://www.versatileartist.com/temp/normalToPlane01.jpg

rotated y-axis to align x-axis
http://www.versatileartist.com/temp/normalToPlane02.jpg

rotated x-axis to align y-axis
http://www.versatileartist.com/temp/normalToPlane03.jpg

3ak
02-27-2012, 08:20 PM
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

Malkalypse
02-27-2012, 11:12 PM
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.

3ak
02-27-2012, 11:31 PM
Let's say you want to rotate vector N around M to fit in XY plane.
1) 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.)
2) find angle betwen N and projection of N in XY (dot product and acos)
3) now you have angle and axis (M) - construct quaternion
4) rotate object with quat

p.s. zaxis = normalize tm1.row2 - it's M. forgot why i named it Zaxis)

Malkalypse
02-28-2012, 02:47 AM
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?

Dubbie
02-28-2012, 03:21 AM
Why bother with quat rotations? Why not just write the new matrix to the transform?

3ak
02-28-2012, 03:37 AM
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.

Malkalypse
02-28-2012, 03:38 AM
Were you able to take a look at my problem and figure out why I couldn't get it to work?

3ak
02-28-2012, 04:40 AM
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.

Malkalypse
02-28-2012, 05:10 AM
Thanks so much, I'll try it out tomorrow! :)

Malkalypse
02-28-2012, 06:00 PM
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)

3ak
02-28-2012, 07:52 PM
the problem was in side of rotation - rotate to the left or right? cause dot product gives only angle. So we need to add check with help of cross product - result will always point in direction according to right hand rule. So if crossprod of rotated axis and its projection = axis of rotation it means that we should rotate clockwise - so quat should be inverted... and vise versa.

tm1 = $Box001.transform
tm2 = $Plane001.transform

rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rot = acos (dot rotdAxis (normalize axis3))
if rot>90 then rot-=180
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
if (normalize(cross rotdAxis axis3)) == rotAxis then rQuat = inverse rQuat else rQuat
rotate $Box001 rQuat

Hope this will work in all cases=)

Malkalypse
02-28-2012, 08:43 PM
If I'm reading this right, the way it's supposed to work is:

-rotAxis is the axis it is rotating around
-rotdAxis is the axis that is supposed to get aligned to the target plane,
-axis3 is the cross of the rotAxis and the target plane.

Let me know if I'm misinterpreting that. If I'm not, then it still isn't working all the time. Trying all the permutations in my test scene, this is what's happening:


-- This works
rotAxis = normalize tm1.row1
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This doesn't
rotAxis = normalize tm1.row1
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This works
rotAxis = normalize tm1.row1
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row3)

-- This doesn't
rotAxis = normalize tm1.row1
rotdAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This doesn't
rotAxis = normalize tm1.row1
rotDAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This works
rotAxis = normalize tm1.row1
rotdAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row3)

-- This works
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This doesn't
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This doesn't (but works if used a second time)
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row3)

-- This doesn't
rotAxis = normalize tml1.row2
rotdAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This doesn't
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This works
rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row3
axis3 = cross (rotAxis) (normalize tm2.row3)

-- This doesn't
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This doesn't
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This doesn't
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row1
axis3 = cross (rotAxis) (normalize tm2.row3)

-- This doesn't
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row1)

-- This works
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row2)

-- This works
rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row2
axis3 = cross (rotAxis) (normalize tm2.row3)

3ak
02-28-2012, 08:56 PM
its interesting) could you please share your scene where it doesn't work, and what rotations you're after and i'll try it.

3ak
02-28-2012, 09:19 PM
here is 105th version))

tm1 = $Box001.transform
tm2 = $Plane001.transform

rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rot = acos (dot rotdAxis (normalize axis3))
if rot>90 then abs (rot-=180)
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
if (normalize(cross rotdAxis axis3)) == rotAxis then rquat = rquat else rquat = inverse rquat


rotate $Box001 rQuat

Malkalypse
02-28-2012, 09:42 PM
I think that actually made it worse... sorry :(

I don't really have a specific scene I am testing this with, just making a box and a plane, and tilting the box off at random angles on x, y, and z...

3ak
02-28-2012, 11:21 PM
I don't know why but:
http://my.jetscreenshot.com/11355/m_20120229-hup7-18kb.jpg (http://my.jetscreenshot.com/11355/20120229-hup7-18kb)

so they are equal but last line return false. Even comparing them as strings returns true.

Malkalypse
02-29-2012, 12:35 AM
Hm, don't know if this will help solve it or not, but I _think_ with that last one, it might sometimes be rotating the right amount but in the wrong direction.

3ak
02-29-2012, 01:26 AM
i know - the main problem is to find which direction to choose)
one more problem is rounding in 3ds max - sometimes it differs in 0.00001 and my test fails)
so i added some range.. I don't like this approach. want to find more convenient way of checking side of rotation.

tm1 = $Box001.transform
tm2 = $Plane001.transform

rotAxis = normalize tm1.row3
rotdAxis = normalize tm1.row2
axis3 = cross (normalize rotAxis) (normalize tm2.row3)
rot = acos (dot rotdAxis (normalize axis3))
if rot>90.0 then abs (rot-=180)
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
test = dot (normalize(cross rotdAxis axis3)) rotAxis
if (test >0.9999) and (test<1.0001) then rQuat = rQuat else rQuat = inverse rquat
rotate $Box001 rQuat


You are way better tester than me, so just ruin another attempt=)

Malkalypse
02-29-2012, 02:16 AM
That works for every single combination I tried! Thank you so much. I know it took a while longer to figure out than you expected it to, and I'm glad you stuck in there till you got it working :)

Malkalypse
02-29-2012, 05:00 PM
Incidentally, instead of using:
if (test >0.9999) and (test<1.0001) then rQuat = rQuat else rQuat = inverse rquat
This seems a bit more succinct:
if abs(test - 1) > .0001 then rQuat = inverse rquat
And yes, rounding in Max can be a real pain. I've had to add tolerances to scripts on more than one occasion when they shouldn't have been necessary.

Malkalypse
02-29-2012, 05:26 PM
In case anyone ever wants a nice, easy to use function:

fn alignAxisToPlane obj tgt:undefined r:"y" a:"z" p:"xy" =
(
tm1 = obj.transform
if tgt == undefined then tm2 = (matrix3 1) else tm2 = tgt.transform

if r == "x" do rotAxis = tm1.row1
if r == "y" do rotAxis = tm1.row2
if r == "z" do rotAxis = tm1.row3

if a == "x" do alignAxis = tm1.row1
if a == "y" do alignAxis = tm1.row2
if a == "z" do alignAxis = tm1.row3

if p == "yz" do tgtPlane = tm2.row1
if p == "xz" do tgtPlane = tm2.row2
if p == "xy" do tgtPlane = tm2.row3

axis3 = cross (normalize rotAxis) (normalize tgtPlane)

rot = acos (dot alignAxis (normalize axis3))
if rot > 90.0 then abs (rot -= 180)
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
test = dot (normalize(cross alignAxis axis3)) rotAxis
if abs(test - 1) > .0001 then rQuat = inverse rquat
rotate obj rQuat
)

-- Sample usage:
alignAxisToPlane $ r:"z" a:"y"

denisT
02-29-2012, 07:10 PM
i don't want to disappoint you but the function is not correct.
it's very easy to check... if you run your function second time with the same arguments the result shouldn't change...

Malkalypse
02-29-2012, 07:21 PM
Yeah, I actually noticed that not long after I posted... Any suggestions for fixing it? :/

(oh, and 3ak: I'm not the one who broke it this time :P )

denisT
02-29-2012, 07:58 PM
here is what i would do:

fn makeRotateMatrix vector angle =
(
x = vector.x
y = vector.y
z = vector.z

cs = angle
sn = sqrt (1 - cs*cs)

row1 = [cs + (1-cs)*x*x, (1-cs)*x*y - sn*z, (1-cs)*x*z + sn*y]
row2 = [(1-cs)*y*x + sn*z, cs + (1-cs)*y*y, (1-cs)*y*z - sn*x]
row3 = [(1-cs)*x*z - sn*y, (1-cs)*y*z + sn*x, cs + (1-cs)*z*z]
matrix3 row1 row2 row3 [0,0,0]
)
fn alignAxisToDir node axis:#z dir:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
tm = node.transform
vec = normalize vec
dir = normalize dir
rtm = makeRotateMatrix (normalize (cross dir vec)) (dot vec dir)
node.transform = translate (rotate (scalematrix tm.scale) (tm*rtm).rotation) tm.pos
)
/*
-- example:
alignAxisToDir <source> axis:#x dir:<target>.transform[3]
*/


if anyone know an easier way how to make the rotation matrix please share :)

3ak
02-29-2012, 08:06 PM
Yeah, I actually noticed that not long after I posted... Any suggestions for fixing it? :/

(oh, and 3ak: I'm not the one who broke it this time :P )

i run my fn on already aligned box and nothing changes. what is incorrect?

denisT
02-29-2012, 08:23 PM
everything is much easier:

fn alignAxisToDir node axis:#z dir:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
tm = node.transform
vec = normalize vec
dir = normalize dir
rtm = angleaxis (acos (dot vec dir)) (normalize (cross dir vec))
node.transform = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)


just needed to think a little more :)

PS. ... and a little more ;)

3ak
02-29-2012, 08:41 PM
here is what i would do:

fn makeRotateMatrix vector angle =
(
x = vector.x
y = vector.y
z = vector.z

cs = angle
sn = sqrt (1 - cs*cs)

row1 = [cs + (1-cs)*x*x, (1-cs)*x*y - sn*z, (1-cs)*x*z + sn*y]
row2 = [(1-cs)*y*x + sn*z, cs + (1-cs)*y*y, (1-cs)*y*z - sn*x]
row3 = [(1-cs)*x*z - sn*y, (1-cs)*y*z + sn*x, cs + (1-cs)*z*z]
matrix3 row1 row2 row3 [0,0,0]
)
fn alignAxisToDir node axis:#z dir:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
tm = node.transform
vec = normalize vec
dir = normalize dir
rtm = makeRotateMatrix (normalize (cross dir vec)) (dot vec dir)
node.transform = translate (rotate (scalematrix tm.scale) (tm*rtm).rotation) tm.pos
)
/*
-- example:
alignAxisToDir <source> axis:#x dir:<target>.transform[3]
*/


if anyone know an easier way how to make the rotation matrix please share :)


fn rotMatrix v a = (quat (v.x*(sin (a/2))) (v.y*(sin (a/2))) (v.z*(sin (a/2))) (cos (a/2))) as matrix3
But it will be clockwise. use inverse quat to counterclockwise rotation.

Something wrong with your makeRotateMatrix - makeRotateMatrix [1,0,0] 0 returns:
(matrix3 [1,0,0] [0,0,-1] [0,1,0] [0,0,0])

UPDATE:
I made align with matrices on 1st page. Could you please help doing it with quat?
I find projection with plane with cross product? then make quat to rotate axis in that projection and decide wich way to rotate using cross product of axis and its projection. if result equals to axis of rotation then don't change quat. if no - inverse it.
But due to rounding errors and some strange things when max returns false on equal values it has too many lines. Maybe you'll find shorter way.

Malkalypse
02-29-2012, 08:47 PM
I'll take a look at some of these new developments a little later on.. for the time being, all the rotating has made me dizzy :D

denisT
02-29-2012, 08:49 PM
i run my fn on already aligned box and nothing changes. what is incorrect?
what axis your function does align?

3ak
02-29-2012, 08:55 PM
what axis your function does align?
You wrote that my func returns different results. i created box, plane, rotated them randomly, run my script. it aligned box to plane (let's say rotate box around Y to align X to XY plane of Plane). then i just run script second time and box didn't rotate. So i can't understand what error did you mention?
if it possible could you share matrix3 values for 2 objects and what axis align to what plane. and i'll try it out.

denisT
02-29-2012, 08:59 PM
You wrote that my func returns different results.
i didn't...

3ak
02-29-2012, 09:06 PM
oops. my bad than)

denisT
02-29-2012, 09:19 PM
i created box, plane, rotated them randomly, run my script. it aligned box to plane (let's say rotate box around Y to align X to XY plane of Plane).

i don't see any axis aligned:

(
delete objects
s = point name:"s" axistripod:on constantscreensize:on isselected:on
t = plane name:"t"

rotate s (eulerangles 33 25 17)

tm1 = s.transform
tm2 = t.transform

rotAxis = normalize tm1.row2
rotdAxis = normalize tm1.row1
axis3 = cross (normalize tm1.row2) (normalize tm2.row3)
rot = acos (dot rotdAxis (normalize axis3))
if rot>90 then rot-=180
rQuat = quat (rotAxis.x * (sin(rot / 2))) (rotAxis.y * (sin(rot / 2))) (rotAxis.z * (sin(rot / 2))) (cos (rot / 2))
if (normalize(cross rotdAxis axis3)) == rotAxis then rQuat = inverse rQuat else rQuat
rotate s rQuat
)

it's why I've asked about that...

denisT
03-01-2012, 12:14 PM
here is how to align an axis to a direction and a plane:

fn alignAxisToDir node axis:#z dir:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
tm = node.transform
vec = normalize vec
dir = normalize dir
rtm = angleaxis (acos (dot vec dir)) (normalize (cross dir vec))
node.transform = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)
fn alignAxisToPlane node axis:#x normal:[0,0,1] =
(
vec = case axis of
(
#x: node.transform[1]
#y: node.transform[2]
#z: node.transform[3]
)
vec = normalize vec
normal = normalize normal
front = normalize (cross vec normal)
alignAxisToDir node axis:axis dir:(cross normal front)
)

3ak
03-01-2012, 01:50 PM
Malkalypse. this should work without dot prod check:

fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
if rotatedAxis != rotationAxis then
(
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat
)
)
rotateToAlign $box001 $box001.transform.row1 $box001.transform.row2 $plane001.transform.row3

eek
03-01-2012, 03:21 PM
From playing with a beet mat :) this might work - basically if your aligning to the XY plane its direction is going to be Z ([0,0,1]) - if its the identity. So lets keep it simple and rotate object A's Y axis about its X so that it lies flat on the XY world plane.

proj = cross a.transform.row1 [0,0,1] -- project onto the XY plane
ang = acos (dot a.transform.row2 proj) -- get the angle of the Y axis relative to the projection

a.rotation.controller[1].value += ang

or

a.rotation.controller[1].value += degToRad ang

That should be it roughly, if you get the cross of the projection and the Y axis you can check its sign to rotate it in the correct direction.

If you wanted to use the axis of the plane in any direction you could use plane.dir to give you its normal. This maybe all wrong as im not next to max.

denisT
03-01-2012, 03:46 PM
Malkalypse. this should work without dot prod check:

fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
if rotatedAxis != rotationAxis then
(
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat
)
)
rotateToAlign $box001 $box001.transform.row1 $box001.transform.row2 $plane001.transform.row3

still not working right... check:

s = point name:"s" axistripod:on constantscreensize:on isselected:on
rotate s (eulerangles 33 25 17)

rotateToAlign s s.transform[1] s.transform[3] [0,0,1]
rotateToAlign s s.transform[3] s.transform[1] [0,0,1]

-- repeat next line several times
rotateToAlign s s.transform[3] s.transform[2] [0,0,1]

3ak
03-01-2012, 04:29 PM
and whts wrong there?)
it alignes to plane perfectly. The reason it rotates is cause planeNormal and axis of rotation are the same and cross prod = [0,0,0]. thx. I should add check.
fn rotateToAlign obj rotatedAxis rotationAxis planeNormal =
(
if rotatedAxis != rotationAxis then
(
if rotationAxis != planeNormal then
(
format "rotationAxis = %\n" rotationAxis
format "planeNormal = %\n" planeNormal
proj = cross (normalize rotationAxis) (normalize planeNormal)
rot = acos (dot rotatedAxis (normalize proj))
) else rot = 0.0
if rot>90.0 then abs (rot-=180)
rotationAxis = normalize(cross rotatedAxis proj)
rQuat = quat (rotationAxis.x * (sin(rot / 2))) (rotationAxis.y * (sin(rot / 2))) (rotationAxis.z * (sin(rot / 2))) (cos (rot / 2))
rotate obj rQuat

)
)

But new problem arises - it prints out [0,0,1] [0,0,1] for both axises and dot prod gives us 90 angle for zero vector. But it shouldn't be cause "if" condition should execute else part in this case.
I just can't get why 3ds max behave like this.

and where can i choose axis of rotation in your fn?

denisT
03-01-2012, 04:38 PM
and where can i choose axis of rotation in your fn?
my method doesn't need a axis of rotation. it aligns using the shortest way. I calculate the axis of rotation inside the function...

3ak
03-01-2012, 04:44 PM
my method doesn't need a axis of rotation. it aligns using the shortest way. I calculate the axis of rotation inside the function...

but task is to align to plane rotating around given axis. you can align X axis to plane XY of second object rotating around both of the remaining axises of the first object. and you leave no choice.

denisT
03-01-2012, 10:25 PM
but task is to align to plane rotating around given axis. you can align X axis to plane XY of second object rotating around both of the remaining axises of the first object. and you leave no choice.
the task was set incorrectly. there are two things - align and rotate. doing both at the same time doesn't make sense. but just for practicing in math it's easy to change my function to support the pole-vector to rotate about...

3ak
03-01-2012, 11:23 PM
Why incorrectly? Rotating X around Z to align X to plane results in different vector than rotating X around Y to align with the same plane:
http://my.jetscreenshot.com/11355/m_20120302-vidw-12kb.jpg (http://my.jetscreenshot.com/11355/20120302-vidw-12kb)

and TS asked for possibility to choose axis of rotation.

denisT
03-01-2012, 11:46 PM
the nice picture by the way... :)
well... you see a sense of the aligning using a pole-vector. fine!
how is about to move an object to some place using rotations only? it's doable, but does it make sense?

3ak
03-01-2012, 11:57 PM
thx)
i don't know how TS will use it so maybe it has sense)

a bit offtopic: do you know why sometimes the only way to compare values is as strings? I had two vectors which are the same and checking this in if-then-else block executes the code which should run only if vectors differ (i printed out values and they are the same)? so i had to do as string comparison.

denisT
03-01-2012, 11:58 PM
Malkalypse has a gift... :)
his questions keep me in fighting trim all the time :)
that's the best one http://forums.cgsociety.org/showthread.php?f=98&t=893959
solving the task i've made one of my coolest tools. thanks a lot! :beer:

Malkalypse
03-02-2012, 08:34 PM
Denis: Thanks, that had me laughing quite hard... it really made my day :D

I think a useful guideline for most things is "If it's easy, do it yourself. If it's hard, find an expert."

3ak: In general terms it's good for anything that requires aligning an edge to a surface. And being able to choose the "pole vector" is definitely helpful. (Also, I agree with what Denis said, that is an awesome picture... how did you happen to make it?)
As for your question... I'm guessing the values you are trying to compare are array or matrix elements? Let me quote Bobo himself on this one:

Matrices [and] Arrays, are compound values where the comparison only looks to see if the two variables point at the same memory (in other words, if they are instances) ... you cannot compare the CONTENT of the value as it does not do a component by component comparison, only a top-level test.

If your values are something else... then no clue!

denisT
03-03-2012, 02:08 PM
In general terms it's good for anything that requires aligning an edge to a surface. And being able to choose the "pole vector" is definitely helpful.

well... here is a version where you can optionally choose the "pole-vector":

fn alignAxisToPlane node axis:#x pole: normal:[0,0,1] =
(
tm = node.transform

vec = case axis of
(
#x: tm[1]
#y: tm[2]
#z: tm[3]
)
vec = normalize vec
normal = normalize normal

if abs (dot vec normal) > 0.0 do
(
rot = if iskindof pole Point3 and abs (dot vec pole) < 1.0 then
(
pole = normalize pole
normalize (cross pole normal)
) else vec

front = normalize (cross rot normal)
side = normalize (cross normal front)
if (dot vec side) < 0.0 do side = -side

rtm = angleaxis (acos (dot vec side)) (normalize (cross side vec))
node.transform = tm = translate (rotate (scalematrix tm.scale) (tm.rotation*rtm)) tm.pos
)
tm
)


the function aligns always using the shortest way.

CGTalk Moderation
03-03-2012, 02:08 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.