Modifier Sub-Object Transform Properties

In MAXScript, the values of modifier sub-object transform properties, such as centers and gizmo position, rotation and scale, are not given in the current working coordinate system, but rather are typically in the coordinate system of the object to which it is applied. This is in contrast to scene node transform properties. The values given are exactly as would be seen in the sub-object's corresponding track view or as might be referenced in an Expression controller track variable for that sub-object property. To convert from local to world coordinates, you multiply the local coordinates by the node's objecttransform matrix. To convert from world to local coordinates, you multiple the world coordinates by the inverse of the node's objecttransform matrix. For example:

obj=box pos:[10,20,30]

addModifier obj (affect_region())

objTM=obj.objecttransform

modTM=getModContextTM obj obj.affect_region

-- calculate world coordinates of end point

obj.affect_region.end_point * (inverse modTM) * objTM

-- set end point at world coordinates [20,20,0]

obj.affect_region.end_point = [20,20,0] * modTM * (inverse objTM)

FFD Control Points

FFD control point sub-object properties are also accessible but have several special considerations. The control points properties are named as they appear in the track view, subject to the MAXScript convention of using '_' underscores for spaces, so for example:

$foo.ffd_2x2x2.control_point_1

$baz.ffd_3x3x3.control_point_32 = [1,2,3]

There are two special considerations when accessing FFD control points. First, you can only access control points that have ALREADY been animated by hand, or by using the animateVertex() or the animateAll() MAXScript functions (see Scripting Vertex and Control Point Animation). The FFD doesn't actually create accessible control points until you do this, a behavior that shows up in the track view in normal 3ds max use - you cannot actually place control point keyframes in the track view until you've animated the control point.

Second, control point coordinates are in FFD lattice space. This is a normalized space, with [0,0,0] at the lower left-hand corner (at control_point_1) and [1,1,1] at the opposite corner of the FFD lattice, so you have to be careful about computing and scaling correct coordinates when you set them. This is also reflected in the track view for FFD control points in normal 3ds max use - if you look at their values in a keyframe property dialog or a function graph, they are in this normalized lattice space, not world-space coordinates. You'd have to work in this space also if you tried to use expression controllers to control FFDs. The modifier utility functions getModContextBBoxMin() and getModContextBBoxMin() can be used to determine the world-space bounds of an FFD lattice allowing you to compute scaled lattice space coordinates from world coordinates. See details on these functions in Modifier Common Properties, Operators, and Methods. An example of accessing and converting coordinate systems for FFD control points is shown in the following script:

b=box pos:[10,20,0]

ffd=ffdbox()

addModifier b ffd

animateVertex ffd 64

cp64posL=ffd.control_point_64

objTM=b.objecttransform

modTM=(getModContextTM b ffd)*ffd.lattice_transform.value

modBBMin=getModContextBBoxMin b ffd

modBBMax=getModContextBBoxMax b ffd

cp64posW=(modBBMin+(cp64posL*(modBBMax-modBBMin)) * (inverse modTM) * objTM