[Closed] Align an axis to a plane, using other axis?
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)
)
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]
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.
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 = %
" rotationAxis
format "planeNormal = %
" 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?
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.
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…
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?
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.
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!
Denis: Thanks, that had me laughing quite hard… it really made my day
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!
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.