Thursday, July 25, 2013

Connect Attribute: Maintain Offset

Connecting attributes is one way to drive a node's attribute using another in Maya. When connecting numeric values, such as translate or rotate, sometimes an offset exists prior to the connection which you might not want to lose. It would be nice if we could maintain that offset when doing the connection between attributes, like we can with our standard constraints.

A simple way to do that is using a math node plusMinusAverage as a buffer. We can first calculate the difference between the two attributes we are connecting. For example, if we have A = < 0, 0, 0 >  and B = < 3, 1, 3 >  if we connect A to B directly, now B = < 0, 0, 0 >. What we can do to get around this is to first find the difference between A and B as A-B and then use our plusMinusAverage node to subtract this difference from A. We can first store the current value for the source attribute, A, in the first input, and set the other input to the difference we have just computed, in this case < -3, -1, -2 >. By default the node's operation is set to Sum, we want Subtract. We then connect the output to the destination attribute, and now the attributes are connecting but no 'snap' happened.

In this example I want to connect pCube2.translateY to pCube1.translateZ, but notice the pCube2.translateY is 0 while pCube1.translateZ is 3.


If I do a simple connection, pCube1 will 'snap' to the origin.


We might not want that. So we do this setup to keep that offset.








Here is a wrapper for Maya's connectAttr command allowing to maintain the current offset by using a plusMinusAverage node in between.

UPDATED
def connectAttr(srcPlug, destPlugs, maintainOffset=False, **kwargs):
    ''' Wrapper for Maya's connectAttr command with the extra functionality of allowing to maintain offset
        if attribute is a numeric attribute and to connect to multiple objects '''
    if type(destPlugs) != list:
        destPlugs = [destPlugs]
    
    srcValue = cmds.getAttr(srcPlug)

    for destPlug in destPlugs:
        if maintainOffset:
            # get the attribute type
            attrType = cmds.getAttr(srcPlug, type=True)
            
            destValue = cmds.getAttr(destPlug)
            
            if attrType in ["doubleLinear", "doubleAngle", "double", "long", "float"]:
                # find the difference 'delta' between the two attributes    
                diff = srcValue - destValue
                # create a node to keep the offset
                offsetNode = cmds.createNode("plusMinusAverage")
                cmds.setAttr(offsetNode + ".operation", 2)      # subtract
                
                # connect and disconnect plug to get the value in
                cmds.connectAttr(srcPlug, offsetNode + ".input1D[0]")
                cmds.connectAttr(srcPlug, offsetNode + ".input1D[1]")
                cmds.disconnectAttr(srcPlug, offsetNode + ".input1D[1]")
                cmds.setAttr(offsetNode + ".input1D[1]", diff)
                
                cmds.connectAttr(offsetNode + ".output1D", destPlug, **kwargs)
            
            elif attrType in ["double3", "float3"]:
                # find the difference 'delta' between the two attributes    
                diff = []
                for i, d in enumerate(srcValue[0]):
                    diff.append(d - destValue[0][i])
                
                # create a node to keep the offset
                offsetNode = cmds.createNode("plusMinusAverage")
                cmds.setAttr(offsetNode + ".operation", 2)      # subtract
                
                # connect and disconnect plug to get the value in
                cmds.connectAttr(srcPlug, offsetNode + ".input3D[0]")
                cmds.connectAttr(srcPlug, offsetNode + ".input3D[1]")
                cmds.disconnectAttr(srcPlug, offsetNode + ".input3D[1]")
                cmds.setAttr(offsetNode + ".input3D[1]", diff[0], diff[1], diff[2])
                
                cmds.connectAttr(offsetNode + ".output3D", destPlug, **kwargs)
                
                return offsetNode
        else:
            cmds.connectAttr(srcPlug, destPlug, **kwargs)
Hope you guys find this useful.

0 comments:

Post a Comment