Rotation keyframe assignment via script is screwy and inconsistent

Rotation keyframe assignment via script is screwy and inconsistent

Anonymous
Not applicable
1,931 Views
6 Replies
Message 1 of 7

Rotation keyframe assignment via script is screwy and inconsistent

Anonymous
Not applicable

This code captures the problem

 

obj1 = Box pos:[100, 100, 100]
obj2 = Box pos:[200, 100, 100]
obj3 = Box pos:[300, 100, 100]

set animate on
for t = 1 to 101 by 10 do (

at time t obj1.rotation.Y_rotation = 5*t

at time t obj2.rotation.Y_rotation = 5*t
at time t obj2.rotation.Y_rotation = 5*t

at time t obj3.rotation.Y_rotation = 5*t
at time t obj3.rotation.Y_rotation = 5*t
at time t obj3.rotation.Y_rotation = 5*t
)
animate off

I'd expect all three Boxes to have identical animation, and for their y-rotations to increase continuously at a steady rate over 101 frames.

 

Instead, all three box rotations reverse rotation direction after frames 21 and 91. Moreover, while obj1 and obj3 behave the same screwy way, obj2 differs at frames 21, 41, and 91 because apparently multiple assignments to the same value sometimes has the effect of toggling between two values.

 

 

For completeness here's a table for the full results I got, weird numbers in red, and bolded red where obj2 doesn't match obj1, obj3.

Frame               |  1  11  21  31  41  51  61  71  81  91 101
Expected Y-rotation | 5 55 105 155 205 255 305 355 405 455 505
obj1, obj3 actual | 5 55 105 25 205 285 305 355 405 455 395
obj2 actual | 5 55 75 25 335 285 305 355 405 445 395

 

What's causing this? If it's something weird with the EulerXYZ controller I can't find any mention in the documentation or in the forums. I notice some of the wrong values add with the correct ones in such a way that the sum is a multiple of 180 but I don't know what to make of this.

 

For what I'm doing I only need this one axis of rotation. The other two axes are completely untouched, as in my example code.

 

Edit: I'm using 3ds Max 2017 on Windows 10

 

 

 

 

0 Likes
Accepted solutions (1)
1,932 Views
6 Replies
Replies (6)
Message 2 of 7

blakestone
Collaborator
Collaborator

That is a weird result.
Maybe try "angleaxis" which will rotate the box (t * 5 degrees) each rotation.

(
	local obj1 = Box pos:[100, 100, 100]
	local obj2 = Box pos:[200, 100, 100]
	local obj3 = Box pos:[300, 100, 100]

	set animate on
	for t = 1 to 101 by 10 do (
		at time t rotate obj1 (angleaxis (t * 5) [0,1,0])
		at time t rotate obj1 (angleaxis (t * 5) [0,1,0])

		at time t rotate obj2 (angleaxis (t * 5) [0,1,0])
		at time t rotate obj2 (angleaxis (t * 5) [0,1,0])

		at time t rotate obj3 (angleaxis (t * 5) [0,1,0])
		at time t rotate obj3 (angleaxis (t * 5) [0,1,0])
		at time t rotate obj3 (angleaxis (t * 5) [0,1,0])
	)
	set animate off
)
0 Likes
Message 3 of 7

Anonymous
Not applicable

Using the angleaxis wasn't working for me. To set it to an absolute angle (rather than rotate by an amount) I tried computing the existing angle and rotate by the amount desired_angle - current_angle, but this was all over the place too. It seems there are different angle systems used between obj.rotation.Y_rotation and rotate obj (angleaxis angle [0,1,0]).

 

But your idea was the jumping off point for looking into directly changing the keyframe values, and it looks like the following works exactly as I want:

 

obj1 = Box pos:[100, 100, 100]
obj2 = Box pos:[200, 100, 100]
obj3 = Box pos:[300, 100, 100]

fn aarotate obj tf ang = (
	
	addNewKey obj.rotation.Y_rotation.controller tf
	ki = getKeyIndex obj.rotation.Y_rotation.controller tf
	obj.rotation.Y_rotation.keys[ki].value = ang
)

set animate on
for t = 1 to 101 by 10 do (
	aarotate obj1 t (5*t)
	
	aarotate obj2 t (5*t)
	aarotate obj2 t (5*t)
	
	aarotate obj3 t (5*t)
	aarotate obj3 t (5*t)
	aarotate obj3 t (5*t)
)
animate off

I'd still like to know what was going on with the obj.rotation.Y_rotation keyframing, if anyone knows.

0 Likes
Message 4 of 7

blakestone
Collaborator
Collaborator

Well done with your solution!

I have run into issues like this not only in 3dsMax but in other applications where a rotational calculation will go past 360 degrees so it resets back to 0 and then it throws out a calculation or animation etc. I think this may be what was happening here. It was setting a rotation to the correct calculation but it doesn't know what direction to turn the object to get there.

0 Likes
Message 5 of 7

leeminardi
Mentor
Mentor
Accepted solution

The primary problem with your script is that you are trying to input angles greater than 180° to an Euler rotational controller. You must use a TCB controller for angles greater than 180° AND you must have the Rotation Windup option checked.  If an Euler controller is used or if a TCB controller is used without Rotation Windup checked, angles greater than 180 are changed to a value that is the remainder of the value divided by 180.

cn2.JPG
I think the following code does what you want.  You may also want to set the TCB tension to 50 if you want a linear transition between keyframes.

 

obj1 = Box pos:[100, 100, 100]
obj1.rotation.controller = tcb_rotation ()
obj1.rotation.controller.rotWindup = True
obj2 = Box pos:[200, 100, 100]
obj2.rotation.controller = tcb_rotation ()
obj2.rotation.controller.rotWindup = True
obj3 = Box pos:[300, 100, 100]
obj3.rotation.controller = tcb_rotation ()
obj3.rotation.controller.rotWindup = True
set animate on
for t = 1 to 101 by 10 do (

at time t rotate obj1 (angleAxis (5*t ) [0, 1, 0] )

at time t rotate obj2 (angleAxis (5*t ) [0, 1, 0] )
at time t rotate obj2 (angleAxis (5*t ) [0, 1, 0] )

at time t rotate obj3 (angleAxis (5*t ) [0, 1, 0] )
at time t rotate obj3 (angleAxis (5*t ) [0, 1, 0] )
at time t rotate obj3 (angleAxis (5*t ) [0, 1, 0] )

)
animate off

 

lee.minardi
0 Likes
Message 6 of 7

Anonymous
Not applicable

Wow thanks! I didn't know the TCB controller still let you set individual axes like that. It works for me. Even the obj1.rotation.Y_rotation for setting values still works. Probably TCB is the better option for programming rotations, so long as you don't need the UI or graph editor.

0 Likes
Message 7 of 7

ads_royje
Alumni
Alumni

An other option, if you'd like to keep Euler rotations, would be to set a value to the key instead of using the Rotate function.

You could have something like :

 

 

obj_all = #(
obj1 = (Box pos:[100, 100, 100]),
obj2 = (Box pos:[200, 100, 100]),
obj3 = (Box pos:[300, 100, 100])
)

for t = 1 to 101 by 10 do (
	for obj in obj_all do (
	addNewKey obj.rotation.controller.Y_Rotation.controller t
	keyIdx =(getKeyIndex obj.rotation.controller.Y_Rotation.controller t)
	obj.rotation.controller.Y_Rotation.controller.keys[keyIdx].value = 5*t 
	)
)

 

 

By setting the Key value, you get the highest level of control and consistency on the resulting animation.

 

 

(sorry for intrusion or interference)

 

 

0 Likes