cmdx icon indicating copy to clipboard operation
cmdx copied to clipboard

Set a nodes transform

Open munkybutt opened this issue 4 years ago • 7 comments

Hey!

I am trying to align the transform of one node to another, but have got to a point where I can't see a way forward. Here is my function:

def align_transforms_x(node1, node2):
    """
    Align the transform of node2 to node1

        Args:
            - node1: The target node.
            - node2: The node to align.

        Returns:
            None
    """
    node1 = cmdx.encode(node1)
    node2 = cmdx.encode(node2)
    transform = node1.transform()
    # this method does not exist:
    node2.set_transform(transform)

Is there something I am missing?

munkybutt avatar Aug 31 '21 08:08 munkybutt

Hm, yes you will need to set translate/rotate/scale explicitly, as well as account for any parent.

Try this.

def align_transforms_x(node1, node2):
    node1 = cmdx.encode(node1)
    node2 = cmdx.encode(node2)
    
    try:
        parent = node1.parent()
        parent_inverse_matrix = parent["worldInverseMatrix"][0].as_matrix()
    except AttributeError:
        parent_inverse_matrix = cmdx.Matrix4()
    
    matrix2 = node2["worldMatrix"][0].as_matrix()
    matrix2 = matrix2 * parent_inverse_matrix
    
    tm = cmdx.TransformationMatrix(matrix2)
    node1["translate"] = tm.translation()
    node1["rotate"] = tm.rotation()
    node1["scale"] = tm.scale()

Then if your source and target nodes have pivots and custom axes you'll need to take those into account as well, and for undo you should use cmdx.DagModifier() instead of setting things directly. There might be a function in the API, e.g. MFnTransform that can handle this I think? If you're up for it, it would be good to expose that to cmdx.

mottosso avatar Aug 31 '21 09:08 mottosso

ah thanks for the super detailed reply - my initial intention was to get/set it in world space, but parent space will likely be useful at some point too. Once I get things in working order I will submit a PR.

munkybutt avatar Aug 31 '21 09:08 munkybutt

Hey @mottosso - I have the basic logic in place, but I am struggling with getting undo to be recorded. Was your suggestion to expose MFnTransform to the DagModifier, effectively setting a nodes transform in a similar way to the createNode and parent methods?

munkybutt avatar Sep 08 '21 14:09 munkybutt

Yes, I think that's what has to happen. Setting the transform of a kTransform node implies setting a whole bunch of things at once..

  • Translate
  • Rotation
  • Scale
  • Shear
  • Scale pivot
  • Scale pivot translation
  • Rotate pivot
  • Rotate pivot translation
  • Rotation orientation
  • Reference

And if the input is a MMatrix as in your initial example, rather than a MTransformationMatrix that actually carries all of this information, then we'll also have to assume the user means to zero out everything but translate, rotate, scale and shear since a MMatrix doesn't carry anymore than that.

And, if the node isn't a kTransform but a e.g. kJoint then we'll also have to zero out the jointOrient as neither the MMatrix nor MTransformationMatrix carries that.

With that that in mind, manual use might look something like..

tm = cmdx.TransformationMatrix()
with cmdx.DagModifier() as mod:
  mod.setAttr(node["translate"], tm.translation())
  mod.setAttr(node["rotatePivot"], tm.rotatePivot())
  mod.setAttr(node["rotatePivotTranslate"], tm.rotatePivotTranslate())
  # etc...

Whereas some kind of wrapper function would do those things under the hoodl.

mod.setTransform(node, tm)

# Or..
node.setTransform(tm)

Undo would then be handled as any other call to setAttr.

mottosso avatar Sep 08 '21 14:09 mottosso

ah I see - I had completely overlooked setAttr for some reason - that works perfectly in my prototype function Would it make sense to create JointNode as a child class of DagNode, with access to joint specific attributes and methods such as jointOrient or do class specific checks on DagNode methods?

munkybutt avatar Sep 08 '21 15:09 munkybutt

Would it make sense to create JointNode

Yes, except not inheriting from DagNode as joints don't have things like rotatePivot. It would need to inherit from Node. Would welcome a PR with a JointNode implementation.

mottosso avatar Sep 08 '21 18:09 mottosso

Although that said, you can node.isA(cmdx.kJoint) to find the type (along with node.type() == "joint") and node["jointOrient"] to get the attribute. So there's not much benefit having a dedicated class for it.

mottosso avatar Sep 08 '21 18:09 mottosso