Notifications
Clear all

[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)
)

 3ak

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
1 Reply
(@denist)
Joined: 10 months ago

Posts: 0

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]

 eek

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.

 3ak

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?

3 Replies
(@denist)
Joined: 10 months ago

Posts: 0

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
(@3ak)
Joined: 10 months ago

Posts: 0

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)
Joined: 10 months ago

Posts: 0

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

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:

and TS asked for possibility to choose axis of rotation.

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

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.

Page 4 / 4