how to control the rotation noise frequency by an attribute holder parameter?

The idea:
I am creating a quick setup script to insert controllable noise controllers on the finger rotations on a CAT rig in setup mode. The goal is to have a set of parameters in one central attribute holder modifier per wrist to control the rotation noise on a global and preferably on an individual finger

what I have so far:
I can select the finger bones where I want a noise rotation controller to be inserted.
it sets each CAT bone in the hierarchy - link tab to "animation controllers in setup mode" and "additive to base layer ON".
it adds an attribute holder modifier to the wrist and creates the wanted spinner float parameters.
the cat bone gets a rotation list controller and then an additional rotation noise controller added.
this noise rotation controller has by default the strenght available as controller slot.
so I an adding a float bezier controller to be able to hook them up to the parameter for noise strength in x, y, z.
I tried it with wireparameters and wirh a script or expression controller for the strength track.
this works so far.

but here my problem:
I can't hook the rotation noise frequency parameter to the attribute.
it is only exposed by a property and not by a controller track.

what is the best way to do this efficiently by a script for all fingers?

pseudo code:
take these selected fingers and hook the noise frequency of their noise rotation controller to the same attribute in the master wrist controller.

I thought about using a script controller for the noise strength and script the frequency manually to the attribute value. but I have trouble getting it to reference on itself (the finger) and set the frequency value.

any help would be highly appreciated!
(I could post example code tomorrow, if required.)

--- edit

let me rephrase it:

How can I connect an attribute holder modifier float spinner parameter to a controller property (the noise rotation .frequency)
My big issue is, that the noise frequency is not exposed by a controller track or something.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
ZalitZ's picture

Use the Custom Attribute event

First, you can't access the noise frequency directly with a wire parameter because it is not exposed as you say.
I came across a similar problem when I wanted to control the visibility of my IK/FK bones on a custom Rig. I don't know if my solution is a good way to do it, but it does the job without executing the script each frame.

The trick is to use the "on changed event" of your Custom Attribute to directly increment your target.rotation.controller.frequency

Since you don't want to break your script everytime you change the target's name (because of a scene merge for example), you can store your objects in a float script, via Assign Node. This float script can be applied on the wrist (on a list controller for example) or a dummy parented to your wrist ( I call that dummy a scriptHolder). However, that dummy should never be modified.

To access the target without naming it directly, you have to find where the float script is located, relatively to the object you are currently selecting, wich should be your attribute holder object (if you are modifying the spinner, that means you are neccessarily selecting your wrist)

There is an example of a scene containing a parent named MyAttributeHolder with a child named MyTarget.

fn Master_Custom_Attribute master = (
	local side = sideInt 
	local NoiseScriptHolder
	local fs_ScriptHolder
	local attrHolderMod
	local Master_CA 
	local oc
	NoiseScriptHolder = point cross:true box:false name: (uniquename "Noise_ScriptHolder_") size:5
	NoiseScriptHolder.transform = master.transform
	in coordsys #local (move NoiseScriptHolder [0,-30,0])
	NoiseScriptHolder.parent = master
	fs_ScriptHolder = float_script()
	NoiseScriptHolder[3][1][1].controller = fs_ScriptHolder 
	fs_ScriptHolder.AddNode "NoiseObj" $MyTarget
	NoiseFrequency_CA = attributes NoiseControl
		fn ScriptHolderStart = ( --there must be a cleaner way to access the ScriptHolder
			local mySelection = $selection
			local theObj = mySelection[1]
			local theChildren = theObj.children 
			local ScriptHolder = for i in theChildren where (matchpattern pattern:"*Noise_ScriptHolder_*") == true  collect i					
			local theHolder = ScriptHolder[1]
			return theHolder
		fn NoiseControl theHolder NoiseObj increment = (
			local i = increment
			local NoiseNode = theHolder[3][1][1].controller.GetObject NoiseObj
			NoiseNode.rotation.controller.frequency = increment
		parameters main rollout:params (
			NoiseFrequency_param type:#float ui:NoiseFrequency_UI default:1
		rollout params "Noise Control" (
			spinner NoiseFrequency_UI "Frequency" type: #float range:[0,100,1] fieldwidth: 30
			on NoiseFrequency_UI changed i do (
				local holder = ScriptHolderStart()
				NoiseControl holder "NoiseObj" i
	attrHolderMod = EmptyModifier()
	addmodifier master attrHolderMod
	Master_CA = master.modifiers[1] = "Custom Attributes"
	custAttributes.add Master_CA NoiseFrequency_CA
Master_Custom_Attribute $MyAttributeHolder
pixhellmann's picture

recap, another approach and more questions

Hey, thanks for the approach!
So let me recap to see if I got it right:
You use an additional object, which has a float script controller assigned, which is abused to store and retrieve the noise controller targets. then the custom attributes on changed event is looking up the stored node and sets its frequency parameter.

is this animatable, btw? so is the noise frequency getting updated if the master CA is animated?

what I dont get is how the storing of the targets as node in the float script keeps the rig from breaking..

*thinking out loud now*:
if the target gets renamed or deleted, will it not still break?
or is it like the "node" is the object and it doesn't care about its name. and you are looking it up by .getnode "variableNameInFloatScriptController". so it returns the object regardless of its name.

so lets transfer this back to my situation.
I have 5 fingers with each 3 bones.
I want to be able to control each of their noise rotation controllers from the wrists master Custom Attributes.
that means the script holder object needs to hold all finger objects and I will have to create for each CA parameter an on changed event handler.

now that pops another question, since I am lazy and want to be able to generally reuse my script.
can this attribute creation, etc. be automated also via script?
I think I want to populate the extra noise holder object and also the CAs based on the available/selected (finger) bones.
so it sets up automatically a noise rotation controller for each finger, adds a CA for noise strength and frequency for thumb, index, middle, ring and pinky and connects them via the float script noise holder extra object.

actually I managed to create something similar in the meantime:

I used an extra custom attribute on my wrist controller, which got an expression controller assigned.
this controller manages for me the frequency on each finger noise controller (which are 15 in total)
it reads the global noise frequency custom attribute and feeds it back to the fingers.frequency property.
in the creation script I iterate through the fingers and update the expression of this "temp attribute".
I am not sure if this is a good idea, since the temp expression controller now updates all 15 noise frequency values each frame. but hey, it works for animating the global frequency attribute.

I hope I find the time today to post working example code.
I really want to enhance it and get a better understanding.
I also really hope to find someone who can help me further understand scripting for CAT system.

Thanks awesome community!

Interactive, real-time, apps, games, character, animation, visualization, TV commercials, marketing and print material. Visit

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.