Maya - AutoJoint tool

Hello everyone, I wrote a script that places joints on a curve in maya for a guy I worked with. He needed it for something he was working on. I wanted to know if I did this somewhat well, I’m just starting out making tools for maya so any guidance would be appreciated.
Thank you!

    numberOfBones = TheNumberOfJointsPerCV

    curveShape = cmds.ls(selection=True)

    numberOfPoints = cmds.getAttr(str(curveShape[0]) + '.degree')


    initialPointPos = cmds.pointOnCurve(curveShape, pr = 0.0)
    initialJoint = cmds.joint(p =(initialPointPos[0], initialPointPos[1], initialPointPos[2]))


    for i in range(0, numberOfPoints):

        curvePointPosStart = cmds.pointOnCurve(curveShape, pr = i, cc = True)
        curvePointPosEnd = cmds.pointOnCurve(curveShape, pr = i+1, cc = True)

        initialJoint = cmds.joint(p =(curvePointPosStart[0], curvePointPosStart[1], curvePointPosStart[2]))

        boneDistanceX = (curvePointPosEnd[0] - curvePointPosStart[0])/numberOfBones
        boneDistanceZ = (curvePointPosEnd[2] - curvePointPosStart[2])/numberOfBones


        cmds.select(initialJoint)

        print "point: " + str(i)

        for i in range (0, numberOfBones):
            print i*boneDistanceX
            cmds.joint(p =(i*boneDistanceX, 0.0, i*boneDistanceZ))

        cmds.move(boneDistanceX, 0.0, boneDistanceZ, cmds.listRelatives(initialJoint, c = True), a=True, ls = True)

A couple things I see really quick. Instead of lines like this:
cmds.joint(p =(curvePointPosStart[0], curvePointPosStart[1], curvePointPosStart[2]))
You could just do this
cmds.joint(position=curvePointPosStart)

Also, for a script that you expect to reuse, always use the full names of flags.

You could also definitely turn this into a function that takes the curve, number of bones, and number of points.

You should probably also take an argument that lets you name the joints. Naming is very important.

3 Likes

Excellent point on the name flag thing, no way in hell can I remember any of them.

I plan on making a UI for this in order to specify the amount of bones and names and whatnot, thank you for the advice!

One problem I’m having is that this only works if the CVs are corners :confused: if they are bezier it won’t work, and also the ‘.degree’ attr doesn’t always give me the right number of CVs, so I’m at a bit of a wall

To get the cv count you want to add up the spans + degree values, like so:

from maya import cmds

degree = cmds.getAttr( 'curve1.degree' )
spans = cmds.getAttr( 'curve1.spans' )

cv_count = degree + spans
1 Like

Thank you for the tip! But when I add the degree and spans together is seems like if gives me way more CVs than there actually are and then I run the script with this new value it just places a bunch on extra joints I don’t need :frowning: is there some other way to get the number of CVs?

Thank you for the help!

Is your curve a loop? if so, the number of CV’s is the same as the number of spans.

When dealing with NURBS, spans doesn’t mean what you think it does. Also, knots means something different than either edit points or cv’s. And even worse, the documentation doesn’t make it clear, maya uses a non-standard way of defining the curve, and you have to use a curveInfo node instead of just mel commands to even access some of that data… I’m a little bitter about this.

Would you mind sharing a file with nothing but your curve in it? Ascii format only, if you please.

1 Like

There are a lot of things that make me bitter as well lol, thank you so much for your help!
How exactly should I upload my file for you?

Github gist, or pastebin. Or heck, if you just copy/paste the curve definition part of the ascii file in here, that would work too.

1 Like

Oh that makes sense, here’s the link to the file in my git project.
Thank you!

Ah Ha. You’re using a Bezier curve, so I now understand your confusion. The number of CV’s includes the tangent handles.

The way a Bezier curve is built in maya is as a NURBS curve with a specially designed knot vector where every third CV is on the curve. So technically, the handles are NURBS CV’s.

So a Bezier curve that you would say has 3 CV’s actually has 7.

1 Like

Huh, uh oh, so would this script work on a regular curve? I’m not sure what the difference is between the two, is it just that one has tangent handles and the other doesn’t? How can I take this into account?
Thank you for all the help, I will keep trying to improve my tool!

There’s not really such thing as a “regular curve”. It’s either a Nurbs or Bezier curve.

And, yes, from an end-user standpoint, the difference is that Bezier curves have tangent handles, and Nurbs curves don’t. Another key difference is that the Nurbs curve doesn’t necessarily pass through its control points (except the endpoints. But even then, that’s not technically required).

To tell the difference for your CornerCurveShape,
run cmds.nodeType('CornerCurveShape') which returns “bezierCurve”.
Nurbs curves will “nurbsCurve”


Some more detail:
The math that defines the Bezier curve is just a special case of the math that defines a Nurbs curve. So Maya only ever makes Nurbs curves under the hood.

That “special case” happens when the Nurbs knot vector is tripled numbers.
Like this: [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]
A cubic Nurbs curve with Maya default settings will have an evenly spaced knot vector.
Like this: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

You can see this special case in the text of the .ma file you posted.
You can also see that the attr type is “nurbsCurve” even though the node type is “bezierCurve”. That’s the under-the-hood nurbs I was talking about.

createNode transform -n "CornerCurve";
	rename -uid "89C9730C-4B11-8E33-13D6-E1BB3E988CFF";
createNode bezierCurve -n "CornerCurveShape" -p "CornerCurve";
	rename -uid "5BE5A645-41B7-DBA9-3804-A3B062C2FE3E";
	setAttr -k off ".v";
	setAttr ".cc" -type "nurbsCurve" 
		3 10 0 no 3
		15 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4
		13
		-17.532549986546456 0 6.0843492515285931
		-17.532549986546456 0 6.0843492515285931
		-5.9718218607240345 0 14.321103722188134
		-5.9718218607240345 0 14.321103722188134
		-5.9718218607240345 0 14.321103722188134
		-12.480434468537887 0 -3.40879322903222
		-12.480434468537887 0 -3.40879322903222
		-12.480434468537887 0 -3.40879322903222
		2.541526291218311 0 12.089344839801448
		2.541526291218311 0 12.089344839801448
		2.541526291218311 0 12.089344839801448
		-10.690339773538895 0 -9.9222121463491462
		-10.690339773538895 0 -9.9222121463491462
		;
1 Like

Oh, this actually makes a lot of sense. that’s why the cmds.pointOnCurve is placing my joints along the points of what would be a bezierCurve and won’t follow the curved lines of the nurbsCurve, right?

So then in this case I should be checking the bezierCruve’s CVs for the correct number, but I need to figure out about way to place them along the curve itself?
I need to take some time to look into this more deeply.

Thank you so much for you time!