Exploring the Trackbar Filter Callback Functions

To understand how the filter function callback works, you can register a test function to explore the argument passed by the callback:

SCRIPT

fn testCallbackFilterFunction theAnimatable theParent theSubAnimIndex theGrandParent theNode=(
format "theAnimatable: %\n" theAnimatable
format "theParent: %\n" theParent
format "theSubAnimIndex: %\n" theSubAnimIndex
format "theGrandParent: %\n" theGrandParent
format "theNode: %\n\n" theNode
true ) --always returns true, means show all keys
fn testCallbackAdditionFunction arg1 arg2 = (true)
theInterface = maxOps.trackbar
theIndex = theInterface.registerFilter testCallbackFilterFunction\
callbackAdditionFunction "Test Filter" 8 active:true stopTraversal:false

For example, if you select a Sphere scene node called "Sphere01", the callback traverses all its sub-anim tracks and calls the function multiple times. The function prints all arguments to the Listener.

You can take a look at some of them for better understanding:

theAnimatable: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theParent: undefined
theSubAnimIndex: 1
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, the scene node Sphere01 is being filtered. There is no grand parent, there is no parent either, the animatable to be filtered is the node itself, the subAnim Index is 1. This is the "top level" of the node.

theAnimatable: Controller:Bezier_Float
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 1
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 1, which is the Bezier Controller of the Visibility track. This shows that the visibility of this sphere is animated. Otherwise, theAnimatable would be undefined.

theAnimatable: undefined
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 2
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 2, which is undefined. Track 2 of every node is the Space_Warps subAnim track. You can verify by typing in the Listener:

$Sphere01[2]
$Sphere01[2].controller
--results:
SubAnim:Space_Warps
undefined
theAnimatable: Controller:Position_Rotation_Scale
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 3
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 3, which is the Transformation controller (in this case a Position_Rotation_Scale controller).

theAnimatable: Controller:Position_XYZ
theParent: Controller:Position_Rotation_Scale
theSubAnimIndex: 1
theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now, go one level deeper. The grand parent is the Sphere, the parent is the Transformation controller (Position_Rotation_Scale), the subAnim index inside the parent is 1, which corresponds to the Position track (in this case a Position_XYZ controller). For comparison, try typing in the Listener:

$Sphere01[3][1].controller
Controller:Position_XYZ
theAnimatable: Controller:Bezier_Float
theParent: Controller:Position_XYZ
theSubAnimIndex: 1
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now, go even deeper. The grand parent is the node Transformation track (the PRS controller), the parent is the Position track (the Position_XYZ), the animatable to be filtered is the subAnim with Index 1, which is the Bezier controller assigned to the X axis of the node position.

theAnimatable: Controller:Bezier_Float
theParent: Controller:Position_XYZ
theSubAnimIndex: 2
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: Controller:Bezier_Float
theParent: Controller:Position_XYZ
theSubAnimIndex: 3
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Same with these two tracks, which are the Y and Z sub-controllers of the Position track with indices 2 and 3 respectively. This is the same as accessing

$Sphere01[3][1][3].controller
--result
Controller:Bezier_Float
theAnimatable: Controller:Euler_XYZ
theParent: Controller:Position_Rotation_Scale
theSubAnimIndex: 2
theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now, go back one level and get to the second subAnim index of the PRS controller, which is the Rotation track. It has an Euler_XYZ controller assigned. The following three calls traverses the X, Y, and Z sub-controllers of the rotation:

theAnimatable: Controller:Bezier_Float
theParent: Controller:Euler_XYZ
theSubAnimIndex: 1
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: Controller:Bezier_Float
theParent: Controller:Euler_XYZ
theSubAnimIndex: 2
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: Controller:Bezier_Float
theParent: Controller:Euler_XYZ
theSubAnimIndex: 3
theGrandParent: Controller:Position_Rotation_Scale
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Go back one level again and get to the third subAnim index of the PRS controller, which is the Scale track. It has a Bezier_Scale controller assigned that does not have sub-controllers:

theAnimatable: Controller:Bezier_Scale
theParent: Controller:Position_Rotation_Scale
theSubAnimIndex: 3
theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: Sphere
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 4
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Go back to the Sphere object level and check the 4 th subAnim index, which is the Sphere object.

Try this in the Listener:

$Sphere01[4]
$Sphere01[4].controller
--results:
SubAnim:Object__Sphere
undefined
theAnimatable: ReferenceTarget:ParamBlock
theParent: Sphere
theSubAnimIndex: 1
theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now, you are inside the ParamBlock of the sphere. The grand parent is the Sphere node itself, the parent is the sphere, the subAnim index is 1 and the animatable track is the Parameter Block. It does not have any keys, so you can go on and traverse its subAnim tracks that contain the animatable parameters of the Sphere

theAnimatable: undefined
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 1
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

This is the first subAnim of the ParamBlock, which is the Radius of the sphere. The radius of this sphere was not animated, so there is no controller assigned - theAnimatable parameter is passed as undefined.

Compare to the Listener:

$Sphere01[4][1]
$Sphere01[4][1].controller
--results:
SubAnim:Radius
undefined
theAnimatable: Controller:Bezier_Float
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 2
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

This is the second subAnim of the ParamBlock, which is the Segments count of the sphere. The Segments of this sphere are animated, so there is a Bezier_Float controller assigned.

Compare to the Listener:

$Sphere01[4][2]
$Sphere01[4][2].controller
--results:
SubAnim:Segments
Controller:Bezier_Float

This following calls traverse the remaining tracks of the ParamBlock and of the Sphere itself, but do not find any controllers assigned - they all return undefined as theAnimatable:

theAnimatable: undefined
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 3
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 4
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 5
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: ReferenceTarget:ParamBlock
theSubAnimIndex: 6
theGrandParent: Sphere
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 5
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 6
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theAnimatable: undefined
theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
theSubAnimIndex: 7
theGrandParent: undefined
theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

The test function always returns true. Now, that you know how it is being called, you can change it to perform actual filtering.

See Trackbar Filter Callback Function Examples for some ideas for filter functions including a way to limit the number of displayed keys in the trackbar to increase interaction speed with the 3ds Max UI.