MaxPlus scripting animation on position controller

Hi all,

Pretty new to 3ds max scripting coming from Maya/python. I’m trying to figure out how to script setting keys on a different position controller called ‘Zero_Pos_XYZ’. I have some objects who have their positions frozen through a position list so their zero’d out location is not 0 in the world (like Freeze Transforms in Maya). When I animate them through a script, it still affects them via their actual world position. Here’s the testing script I’ve been playing around with:

import MaxPlus

nodes = MaxPlus.SelectionManager.Nodes
# test data (frame, [x, y, z])
anim_data = [(1, [0, 0, -150]), (14, [0, 0, 0]), (30, [0, 0, -150])]

for node in nodes:
	MaxPlus.Animation.SetAnimateButtonState(True)

	for data in anim_data:
		MaxPlus.Animation.SetTime(data[0] * 160)	# ticks		
		node.Position = MaxPlus.Point3(data[1][0], data[1][1], data[1][2])
			
	MaxPlus.Animation.SetAnimateButtonState(False)

I imagine the issue is something with the node.Position needing to be set to the Zero_Pos_XYZ controller but nothing I’ve tried seems to work. Thanks in advance for any help.

I’ve found a workaround using node.Move() for now but I’m sure there’s a cleaner way.

Still trying to figure this one out days later. My newness to Max is a big part of the frustration but honestly there isn’t much in the way of example for scripting max animation beyond walking it through auto-keying. Surely there must be a way to script setting the keys on this Zero_Pos_XYZ on the position list? Everything I try keys on the world position or says no attribute found.

I worked with 3dsMax many years, but no longer have access to verify so please take this as a guideline.

If you set the Position property, you’re not necessarily setting the value on the controller, but the global position result of all position controllers. It’s a bit like setting the global transform matrix, but only for the position.

For a local transform, what you want is to fetch the appropriate position controller and set its value directly. Last I tried this in MaxPlus, it was doable but painful. Keep in mind this was a while ago.

In your case the position controller is a list controller, so you will need to fetch the second sub-controller in that list, then set the separate float sub-controllers values for X, Y, Z. If I recall correctly, you can also set the vector directly on the root Position Controller (Zero Pos XYZ). In maxscript it’s something along the lines of:

node.transform.controller[0][1].value = vector

This might be incorrect so consider it more like pseudo code… it’s been a while.

Hopefully this helps.

Thanks very much for the reply CLR, I appreciate it. I found a different approach to work around this problem, which is doing the animation part of the pipeline in Maya (haha?). The game engine I work with doesn’t care where it’s havok file comes from so for now, as an animator and not a technical artist, that’s what I’m going with.

That said I did spend some time trying what you suggested, but still couldn’t figure out a way with pymxs to get any ‘controller’ attribute recognized beyond the world position. I did get it to work by executing a maxscript with the python execute command, and that seems to be the solution to a growing number of my obstacles with Max. I’m not sure how much of that should be attributed to my max inexperience vs. the implementation of Max python but so far the latter seems to leave quite a bit desired.

Thanks again.

Hey splinecraft,

I took a few moments to validate and I completely forgot that indices in 3dsMax maxscript are 1-based. So the maxscript equivalent of what you want to do is really:

$.transform.controller
>>>Controller:Position_Rotation_Scale
$.transform.controller[1][2]
>>>SubAnim:Zero_Pos_XYZ
$.transform.controller[1][2].value = [1, 2, 3]
>>> [1, 2, 3]

That would be how to get/set the local value of the controller in maxscript, as opposed to the global value.