Deactivating deformer evaluation

I have hundreds of clusters driving curves (that are skinned). Naturally the playback gets slow with all the clusters active. How can I deactivate them for preview purposes, so that only the skinning is evaluated?

I tried this (setting all relevant node states to “has no effect”):

for cl in mc.ls(type ='cluster'):
    mc.setAttr('%s.nodeState'%cl, 1)
for cl in mc.ls(type ='expression'): # because expressions drive the clusters
    mc.setAttr('%s.nodeState'%cl, 1)
for cl in mc.ls(type ='clusterHandle'):
    mc.setAttr('%s.nodeState'%cl, 1)

The clusters have no effect after this, but the FPS stays the same (which more than doubles after deleting the clusters). And they still show up in the Profiler. Why doesn’t the node state affect the performance time?

Thanks!

Have you tried setting the envelope attribute to 0 instead? I think that might work better than what you’re currently doing.

Yes, I have actually… also doesn’t affect the performance :frowning:

What version of Maya?
Have you tried using the profiler?
What if you delete the expressions but keep the clusters? What effect on the FPS does this have? Are you using expressions that query values on other frames? getAttr -t can be pretty slow in my experience, for example.
If you turn on the Evaluation HUD in the viewport, what does it say?
image

1 Like

Expressions are deemed untrusted by Maya’s evaluation manager (essentially because it does not know whats happening inside them) this means they will bottleneck everything else until they are evaluated.

During the masterclass I went to, they can be used to prototype functionality but should be turned into a node (or a graph of other nodes) in production.

Asserts this node is not thread-safe and that no other nodes should be evaluated while an instance of this node is evaluated. Untrusted nodes are deferred to the end of the evaluation schedule and can introduce costly synchronization.

You can change the scheduling, but i’m not sure how this affects their node state - from my understanding state is acted upon evaluation. So if evaluation itself is blocked due to the safety of the node your not going to see a benefit changing it.

From the training I did - c++ nodes tend to be parallel, (unless they have state - e.g. simulation), clusters, constraints where feedback is interned run serial, python nodes are bound to single threads via GIL and run global serial. Expressions are deemed untrusted.

2 Likes
  • It’s Maya 2018. The profiler lists the clusters and the expressions (hard to read because it’s so much small stuff - the scene has 1800 clusters and corresponding expressions).
  • the expressions don’t include mel commands. It only outputs a noise function that queries frequency, amp etc from custom cluster attributes.
  • I tried to replace the expression with a regular keyframe animation. This lead to the same frame rate, which was a surprise . Seems like the expressions aren’t the problem.
  • Evaluation is parallel / ready / enabled

Thanks for the info, interesting!

I couldn’t use nodes, because the noise function is only available in expressions.

Writing a plugin wasn’t an option, because as far as I know the render farm I use doesn’t allow custom plugins. And writing it in cpp is too much of detour for me at this time :wink: .

And like I wrote above the expressions don’t seem to be the problem, it’s just the 1800 animated clusters that need time to compute. I don’t understsand why I can’t bypass the evaluation.

For now I made a “delete and remember” function, that stores all relevant information in a pickled python dict for each curve and then reconstructs the clusters /expressions when needed…

As an aside, the noise function itself is only available in mel, but a noisy function can be approximated in many different ways. For example, consider using a noise texture, and using the place2dTexture node attached to move the sampled UV point over time.

1 Like

Yes, that would be a possible solution. But as far as I know there is no node that lets me connect a sampled texture point directly to an attribute. I always had to use MELs “colorAtPoint” for this kind of thing. Or is there a way?

I just did a quick test and made a noise node and set it to a perlin noise at frequency 3. I connected outColorR to a locator translateY.

Then I connect time1.outTime (or any driving attribute) to the place2dTexture node that got created with the noise node. I connect to rotateUV.

A trick I learned from a Houdini tutorial was that rotating noise or a 3D texture means it will loop. You might be able to offset it in translation too. I don’t know. So multiply it so that your driving attribute loops on 360, and it will seamlessly loop.

Also I suggest changing the offset of the UV coordinates (place2dTexture1.offsetU) so that the rotating pivot point is not in the center and your sample is at 0,0. You want your sample to be somewhere where the rotation is rotating at a set speed. An offset of 0 will look like it is accelerating at some points. An offset of 1.0 worked for me to appear at a uniform speed. I don’t know how to change where the outColor gets sampled from, so I assume it is 0,0 by default.

(Edit: Offsetting using place2dTexture1.translateFrameU seems to work fine too. Better than rotating after all. Rotating loops on a known point of 360. Translating I guess can just be pushed forever and keep being noisy, I don’t know whether it loops.)

1 Like

Rotation is super cool for controlling the periodicity of the noise too! I think moving in one axis will repeat, as the noise is a periodic function - for a value which (practically) nev er loops, I use the technique in figure 7 of this: https://www.cg.tuwien.ac.at/research/publications/2009/Habel_09_PGT/Habel_09_PGT-draft.pdf

This way you wrap the path back around the texture in both axes and move diagonally (although given maya is periodic it would be enough to feed in a steadily increasing diagonal offset anyway)

2 Likes

Amazing, thanks! I did not know you could just connect the out color to an attribute and it will sample at (0,0). Still, I don’t think it would be better than expressions in this case. Because 1) you would have 1800*3 (per axis) noise textures since you can’t change the sampled point 2) the test showed that expressions ar not slower than keyframes (so clusters are the bottleneck) and 3) it would be harder to reproduce the functionality, this is the expression for every cluster:

float $frame = int((frame + nthOffset)/ nthFrame) * nthFrame;
translateX = noise($frame*curve1.noise_freq*freqMult + noise_offset + 1* curve1.noise_distMult+ 3079.181)*curve1.noise_ampX * ampMult;
translateY = noise($frame*curve1.noise_freq*freqMult + noise_offset + 1* curve1.noise_distMult+ 16935.493)*curve1.noise_ampY * ampMult;
translateZ = noise($frame*curve1.noise_freq*freqMult + noise_offset + 1* curve1.noise_distMult+ 47727.299)*curve1.noise_ampZ * ampMult; 

Anyway, thanks again - also to EdArt for the additional info. But still I’d like to know how to deactivate deformer evaluation :slight_smile: