Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set a nodes transform #67

Open
munkybutt opened this issue Aug 31, 2021 · 7 comments
Open

Set a nodes transform #67

munkybutt opened this issue Aug 31, 2021 · 7 comments

Comments

@munkybutt
Copy link

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?

@mottosso
Copy link
Owner

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.

@munkybutt
Copy link
Author

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
Copy link
Author

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?

@mottosso
Copy link
Owner

mottosso commented Sep 8, 2021

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.

@munkybutt
Copy link
Author

munkybutt commented Sep 8, 2021

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?

@mottosso
Copy link
Owner

mottosso commented Sep 8, 2021

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
Copy link
Owner

mottosso commented Sep 8, 2021

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants