Search code examples
pythonmaya

In Maya can i block an animation curve node from reading?


What i am trying to achieve is to rig in Maya a ratchet. Right now I have a controller with limit rotation X values from 0-55. I created a driven key between my controller and the ratchet's rotation Z, so when the driver is 0 the driven is 0 and when the driver is 55 the driven is 60, there are also some in-between keys. What I want is, when the animator put the driver to 55 the driven must go to 60, until now all good, but when the animator puts the driver's value back to 0 I want the drive n's value to remain at 60. so when the driver goes again to 55 then the driver will go to 120 etc. This will be repeated until the ratchet goes 360. The only I have manage to do is to create a long attribute with values from 0-336, where everything happens at once. So there is no need for the animator to place the driver back to 0. But this is quite confusing. I know driven keys are mapped values so it is unavoidable , but how can I do this? I need script node with python where the animation node stops? and then starts again

So I am trying to write a function that will be in a scriptNode so will run each time the animator put values on the rotateX of the hammer. From 0—>55 is working, but i am stuck at the point where i have to lower the values from 55–>0.

import maya.cmds as mc
def hammer_C():
RX = mc.getAttr(‘hammer.rotateX’)
RZ = mc.getAttr(‘cylider.rotateZ’)
if RX > 0:
   mc.setAttr(‘cylider.rotateZ’, -RX )
elif RX < 55:
   mc.setAttr(‘cylider.rotateZ’, RZ )
else:
   print ‘TEST’

So basically i would like to know if there is a way in Python to say: As the value_A goes from 0 to 55 do that and as the value_A goes from 55 to 0 do something else


Solution

  • I don't know maya, but I think I understand what you need, you are trying to model ratchet device and by 55 or 60 or 360 you mean current rotation angle in degrees.

    enter image description here

    I also expect that you need to lock your ratchet at every 60 degrees, meaning that as soon as it has reached angle multiple of 60 degrees it should be locked from going backward below that degree. And between two multiples of 60 it may go forward and backward.

    Hence I suggest next code, it is not maya-specific but still it may give you idea what to do and can be adopted to your case. We can start from this code and imporve it if needed.

    I understood that you don't know python much and for that I've also created very small piece of code with one-line formula (computation of next_driven_angle) that you can also try online (plus accepted final version with maya):

    import math
    previous_driver_angle = 0.
    previous_driven_angle = 0.
    for next_driver_angle in [0, 10, 25, 35, 55, 35, 45]:
        next_driven_angle = max(math.floor(previous_driven_angle / 60. + 10 ** -6) * 60., previous_driven_angle + (next_driver_angle - previous_driver_angle) * 60. / 55.)
        print('driver', next_driver_angle, 'driven', next_driven_angle)
        previous_driver_angle = next_driver_angle
        previous_driven_angle = next_driven_angle
    

    Output of this small code above is:

    driver 0 driven 0.0
    driver 10 driven 10.909090909090908
    driver 25 driven 27.272727272727273
    driver 35 driven 38.18181818181818
    driver 55 driven 60.0
    driver 35 driven 60.0
    driver 45 driven 70.9090909090909
    

    Output of next big code (listed down below afterwards) emulating random process of ratchet:

      0: driver   0.0 driven   0.0 non-locked |   1: driver -33.8 driven   0.0     locked |
      2: driver -17.0 driven  18.4 non-locked |   3: driver   3.5 driven  40.7 non-locked |
      4: driver  34.8 driven  74.9 non-locked |   5: driver  53.9 driven  95.7 non-locked |
      6: driver  90.2 driven 135.3 non-locked |   7: driver  79.0 driven 123.0 non-locked |
      8: driver 103.7 driven 150.0 non-locked |   9: driver  67.3 driven 120.0     locked |
     10: driver  34.9 driven 120.0     locked |  11: driver  22.5 driven 120.0     locked |
     12: driver -13.5 driven 120.0     locked |  13: driver   5.4 driven 140.6 non-locked |
     14: driver -11.9 driven 121.7 non-locked |  15: driver -48.5 driven 120.0     locked |
     16: driver -67.5 driven 120.0     locked |  17: driver -78.0 driven 120.0     locked |
     18: driver -56.0 driven 143.9 non-locked |  19: driver -27.2 driven 175.3 non-locked |
     20: driver -60.2 driven 139.4 non-locked |  21: driver -60.2 driven 139.4 non-locked |
     22: driver -25.5 driven 177.3 non-locked |  23: driver -38.5 driven 163.1 non-locked |
     24: driver -30.8 driven 171.4 non-locked |  25: driver -40.4 driven 161.0 non-locked |
     26: driver  -8.3 driven 196.0 non-locked |  27: driver  -5.0 driven 199.6 non-locked |
     28: driver -25.4 driven 180.0     locked |  29: driver -21.0 driven 184.8 non-locked |
     30: driver   7.3 driven 215.6 non-locked |  31: driver  39.9 driven 251.1 non-locked |
     32: driver   1.3 driven 240.0     locked |  33: driver  24.8 driven 265.6 non-locked |
     34: driver  48.7 driven 291.7 non-locked |  35: driver  71.7 driven 316.8 non-locked |
     36: driver  79.3 driven 325.0 non-locked |  37: driver  54.7 driven 300.0     locked |
     38: driver  73.8 driven 320.8 non-locked |  39: driver  43.5 driven 300.0     locked |
     40: driver   6.6 driven 300.0     locked |  41: driver -29.4 driven 300.0     locked |
     42: driver  -7.7 driven 323.6 non-locked |  43: driver  20.5 driven 354.4 non-locked |
     44: driver -12.0 driven 318.9 non-locked |  45: driver  23.8 driven 358.0 non-locked |
     46: driver  61.8 driven 399.4 non-locked |
    

    Next code can be also run online here.

    def Main():
        import math, random, sys
    
        driven_lock_angle_step = 60.
        driver_to_driven_ratio = 55. / driven_lock_angle_step
        driver_angle = 0.
        driven_angle = 0.
    
        def SetDriverAngle(new_driver_angle):
            nonlocal driver_angle, driven_angle
            
            driver_angle_delta = new_driver_angle - driver_angle
            driven_angle_delta = driver_angle_delta / driver_to_driven_ratio
            
            nearest_driven_lock_angle = math.floor(driven_angle / driven_lock_angle_step + 10 ** -6) * driven_lock_angle_step
            
            driven_was_locked = driven_angle + driven_angle_delta < nearest_driven_lock_angle
            driven_angle = max(nearest_driven_lock_angle, driven_angle + driven_angle_delta)
            driver_angle += driver_angle_delta
            
            return driven_was_locked
            
        # Emulate Process
        
        forward_prob = 0.6 # Probability of forward move, backward move probability will be 1 - forward_prob
        max_step = 40 # Maximum random jump to do
        max_possible_steps = 1000
        driven_stop_angle = 360.
        outputs_per_line = 2 # Entries per line when printing text
        
        was_locked = False
        random.seed(0)
        for i in range(max_possible_steps):
            sys.stdout.write(
                f'{str(i).rjust(3)}: driver {str(round(driver_angle, 1)).rjust(5)} ' +
                f'driven {str(round(driven_angle, 1)).rjust(5)} ' +
                f'{("locked" if was_locked else "non-locked").rjust(10)} | '
            )
            if (i + 1) % outputs_per_line == 0 or i + 1 >= max_possible_steps or driven_angle >= driven_stop_angle:
                sys.stdout.write('\n')
            if driven_angle >= driven_stop_angle:
                break
            driver_angle_delta = random.random() * max_step * (1. if random.random() < forward_prob else -1.)
            was_locked = SetDriverAngle(driver_angle + driver_angle_delta)
        
    Main()