[Maya] Lock position of a shapeNode when doing 'parent -r -s' command?

maya

#1

Hi,

I want to have a joint function as a controller. For this reason, I want a shapeNode parented into it.
However, whenever I run the ‘parent -r -s’ command, it flips/moves.
You can see an illustration of the problem here: https://www.dropbox.com/s/rcpkn9g3ak7h893/MYA072_remain_shape_after_parenting.mp4?dl=0

I understand that I can just manually move it back in place, but I’m trying to make a script out of it so I need it to function without much manual intervention. (The R_controllers are actually just a mirror of the L_controllers scaled by -1 on X axis)

I tried having the exact WorldRotate and World Scale Pivot. But even if they are the same, they are not orientated the same.

Is there a way around this?

Thank you


#2

If you don’t want the shape to move while reparenting, use parent -a -s instead of -r.
That should preserve the existing world space transformation of the child.


#3

Thanks for the response. I tried -a -s
But it creates another transform node. So in effect, the shape node is not parented to the joint as a shape but as a separate object.


#4

oh derp, forgot about that.

Your next best bet, is to mess with the transform of your shape ahead of the reparent operation to match the new offset that you want.

I believe something along the lines of shape.matrix = shape.matrix * joint.matrix.inverse, then do parent -r -s. Though I’m a bit rusty on my order of operations for the matrix multiplication, but effectively what you’re trying to do is transform the shape to be joints local space before doing the relative parent operation, so that nothing needs to change.


#5

Not really sure about the matrix but isn’t it the same with just using the parentConstraint with maintain offset to false.

If that is the case, yes it will acquire the joints space but it will still flip/move. The difference is that now it flips/moves before the parent command is executed rather than after.

Correct me if I’m wrong.


#6

If you parent the new shape’s transform under the joint and freeze transforms, and then shape parent it should work.

cmds.makeIdentity() is the command you could look into.


#7

You aren’t wrong, but the trick with the matrices is that you’re basically subtracting out the joint’s transform, so that when you apply the relative parent operation, it adds it back in, and it appears as if your shape hasn’t moved.

So yes, as an intermediate step, you are moving the shape, but then you are moving it back.


#8

Thanks for the response.

@clesage
I tried but it didn’t work. I think I missed a thing.
You can see how re-execute the process here:
https://www.dropbox.com/s/c7aadt6buw6oquy/MYA072_remain_shape_after_parenting_v1.2.mp4?dl=0

@R.White
I see your point, but assuming we are in the parent -r -s route,
The shape moves when the command is executed.

Now we want to move it back. But I’m not sure how.
Since the immediate transformNode of the shape is now the joint/new parent.


#9

You do the operation on the shape’s initial transform node, and then do the parent.

I’ve used this kind of trick for combining multiple mesh shapes under a single transform node without losing the initial transform data, to get around some annoyances with polyUnite in the past. Though you might need some extra scripting steps in there to massage everything.


#10

I’m winging this a little bit as I’m not in front of Maya right now - as for parenting a shape, the values of its subcomponents (in this case its cv’s) will be relative to their transform. If your re-parenting the shape to a joint the cv’s position will be relative to the joints transform. So if you want the cv’s to stay where they are when they get re-parented you’ll need to store their relative position to the new parent.

A rule of thumb for transform manipulation - always compute in a common space. I.e. I’ll always work in world space and then push back to a relative space. This will help you a lot in the world of rigging. So this is the basic workflow:

  1. Collect all your cv’s world positions.
  2. Build a matrix for each using the cv position for the position part (w).
    • You can probably collect the entire world transform instead of just the position from the first step.
  3. Multiply each matrix by the inverse world matrix of the new parent. - This will get your local transform.
  4. Store the position part of this matrix - the new relative position.
  5. In either order:
    • Do the parenting.
    • Set the cv’s position the stored position in local space. I.e. setAttr.

This is the gist of it - from this you can do things like save out the data to JSON for retrieval later, update the shapes in the scene etc etc.

Another note on handedness - Maya works on a right-handed system. (max handles both) but it essentially means if your changing the handedness of an object the only axis you can scale is Z. Scaling negatively any other axis will cause the entire transform to flip.

I’ll try and create an example for you.


#11

@R.White
Unfortunately, I am still unable to wrap my head on your method. But no worries, I was able to find a solution based on @Chalk post

@chalk
Thanks for the idea! Yea, I worked your steps and it worked as expected (with help of course from various internet posts)

Also, thanks for handy info on the "right-handed system’. Where do you learn this stuff? :slight_smile: I read the official Maya book some time ago but I didn’t pass through such info.

Here is the working script:

proxyControlShape = 'nurbsCircleShape1'
newParent = 'joint1'

# Store CV World Position

curveCVs = cmds.getAttr( proxyControlShape + '.cp', multiIndices=True )
vtxWorldPosition = []

for i in curveCVs :
	curPointPosition = cmds.xform(proxyControlShape + '.cp[' + str(i) + ']', query=True, translation=True, worldSpace=True ) 
	vtxWorldPosition.append( curPointPosition )
	
# Parent the shapeNode 

cmds.parent(proxyControlShape, newParent, r=True, s=True)

# Restore the world position
for i in curveCVs:
    cmds.xform(proxyControlShape + '.cp[' + str(i) + ']',a=True, worldSpace=True, t=vtxWorldPosition[i])
 

Here is the main reference I used for the script: http://www.fevrierdorian.com/blog/post/2011/09/27/Quickly-retrieve-vertex-positions-of-a-Maya-mesh-(English-Translation)


#12

Awesome @bentraje - completely forgot you can just set the world position back! Been thinking too long in transforms. You can happily skip step 2 - 4.

Your code looks concise. Thanks for the link - looks solid :+1:

Understanding transforms is basically from years of asking programmers, peers, reading journals, blogs etc - I’d say finding a mentor was a huge deal for me learning this stuff. I’m happy to pass that on.


#13

Glad you got it working. @bentraje

Yeah, you’re basically doing the same thing I was trying to say, except skipping all the transform matrix shenanigans.