Copyright (c) 2026
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Compatibility
-
2011, 2010, 2009, 2008
Operating Systems
History
| Created: | 04/27/2010 |
| Last Modified: | 04/30/2010 |
| File Size: | 5.47 KB |
Q/A
here is a revised version of the code
| Date: | 01/31/2026 |
|---|---|
| Submitted by: |
#=================================================================================================================================================
# JAMMSoft Joint Orient Tool - Joints Orient Tool (with tooltips)
#=================================================================================================================================================
import maya.cmds as cmds
# ====================================================================================================
# CALLBACKS
# ====================================================================================================
def worldUpX(*args):
cmds.floatFieldGrp("rbgWorldUp", e=True, v1=1.0, v2=0.0, v3=0.0)
def worldUpY(*args):
cmds.floatFieldGrp("rbgWorldUp", e=True, v1=0.0, v2=1.0, v3=0.0)
def worldUpZ(*args):
cmds.floatFieldGrp("rbgWorldUp", e=True, v1=0.0, v2=0.0, v3=1.0)
def addInXValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v1=(cmds.floatFieldGrp("rbgManualTweak", q=True, v1=True) + 0.1))
def minusInXValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v1=(cmds.floatFieldGrp("rbgManualTweak", q=True, v1=True) - 0.1))
def addInYValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v2=(cmds.floatFieldGrp("rbgManualTweak", q=True, v2=True) + 0.1))
def minusInYValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v2=(cmds.floatFieldGrp("rbgManualTweak", q=True, v2=True) - 0.1))
def addInZValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v3=(cmds.floatFieldGrp("rbgManualTweak", q=True, v3=True) + 0.1))
def minusInZValue(*args):
cmds.floatFieldGrp("rbgManualTweak", e=True, v3=(cmds.floatFieldGrp("rbgManualTweak", q=True, v3=True) - 0.1))
def rotateAxisManualTweakPlus(*args):
cmds.undoInfo(ock=True)
rotationValues = [
cmds.floatFieldGrp("rbgManualTweak", q=True, v1=True),
cmds.floatFieldGrp("rbgManualTweak", q=True, v2=True),
cmds.floatFieldGrp("rbgManualTweak", q=True, v3=True)
]
jointsSelected = cmds.ls(sl=True, type="joint")
rotateAxisManualTweak(jointsSelected, rotationValues)
cmds.select(jointsSelected, r=True)
cmds.undoInfo(cck=True)
def rotateAxisManualTweakMinus(*args):
cmds.undoInfo(ock=True)
rotationValues = [
-cmds.floatFieldGrp("rbgManualTweak", q=True, v1=True),
-cmds.floatFieldGrp("rbgManualTweak", q=True, v2=True),
-cmds.floatFieldGrp("rbgManualTweak", q=True, v3=True)
]
jointsSelected = cmds.ls(sl=True, type="joint")
rotateAxisManualTweak(jointsSelected, rotationValues)
cmds.select(jointsSelected, r=True)
cmds.undoInfo(cck=True)
def rotateAxisManualTweak(jointsSelected, rotationValues):
for joint in jointsSelected:
cmds.xform(joint, r=True, os=True, ra=(rotationValues[0], rotationValues[1], rotationValues[2]))
freezeJointOrientation(joint)
def freezeJointOrientation(joint):
cmds.joint(joint, e=True, zeroScaleOrient=True)
cmds.makeIdentity(joint, apply=True, t=0, r=1, s=0, n=0)
def crossProduct(firstObj, secondObj, thirdObj):
a = cmds.xform(firstObj, q=True, ws=True, rp=True)
b = cmds.xform(secondObj, q=True, ws=True, rp=True)
c = cmds.xform(thirdObj, q=True, ws=True, rp=True)
u = [a[i]-b[i] for i in range(3)]
v = [c[i]-b[i] for i in range(3)]
return [u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0]]
def doToggleLocalAxis(jointsSelected, showOrHide):
for joint in jointsSelected:
cmds.toggle(joint, localAxis=True, state=showOrHide)
def showSelectedLocalAxis(*args):
elemSelected = cmds.ls(typ="joint", sl=True)
if not elemSelected: print("USE: Select at least one joint.")
else:
doToggleLocalAxis(elemSelected, 1)
cmds.select(elemSelected, r=True)
def showHierarchyLocalAxis(*args):
elemSelected = cmds.ls(typ="joint", sl=True)
if not elemSelected: print("USE: Select at least one joint.")
else:
cmds.select(hi=True)
joints = cmds.ls(typ="joint", sl=True)
doToggleLocalAxis(joints, 1)
cmds.select(elemSelected, r=True)
def hideSelectedLocalAxis(*args):
elemSelected = cmds.ls(typ="joint", sl=True)
if not elemSelected: print("USE: Select at least one joint.")
else:
doToggleLocalAxis(elemSelected, 0)
cmds.select(elemSelected, r=True)
def hideHierarchyLocalAxis(*args):
elemSelected = cmds.ls(typ="joint", sl=True)
if not elemSelected: print("USE: Select at least one joint.")
else:
cmds.select(hi=True)
joints = cmds.ls(typ="joint", sl=True)
doToggleLocalAxis(joints, 0)
cmds.select(elemSelected, r=True)
# ====================================================================================================
# ORIENT JOINTS
# ====================================================================================================
def orientJointsUI(*args):
aimSelected = cmds.radioButtonGrp("rbgAim", q=True, sl=True)
upSelected = cmds.radioButtonGrp("rbgUp", q=True, sl=True)
aimReverse = cmds.checkBox("chbReverseAim", q=True, v=True)
upReverse = cmds.checkBox("chbReverseUp", q=True, v=True)
operateOn = cmds.radioButtonGrp("rbgAllOrSelected", q=True, sl=True)
worldUp = [
cmds.floatFieldGrp("rbgWorldUp", q=True, v1=True),
cmds.floatFieldGrp("rbgWorldUp", q=True, v2=True),
cmds.floatFieldGrp("rbgWorldUp", q=True, v3=True)
]
guessUp = cmds.checkBox("chbGuess", q=True, v=True)
aimAxis = [0,0,0]
upAxis = [0,0,0]
aimAxis[aimSelected-1] = -1 if aimReverse else 1
upAxis[upSelected-1] = -1 if upReverse else 1
selected = cmds.ls(sl=True, typ="joint")
cmds.undoInfo(ock=True)
if aimSelected == upSelected:
print("USE: Aim Axis and Up Axis can't be the same.")
elif not selected:
print("USE: Select at least one joint to orient.")
else:
if operateOn == 1:
cmds.select(hi=True)
jointsToOrient = cmds.ls(typ="joint", sl=True)
else:
jointsToOrient = cmds.ls(typ="joint", sl=True)
doOrientJoint(jointsToOrient, aimAxis, upAxis, worldUp, guessUp)
cmds.select(selected, r=True)
cmds.undoInfo(cck=True)
def doOrientJoint(joints, aimAxis, upAxis, worldUp, guessUp):
prevUp = [0,0,0]
for joint in joints:
children = cmds.listRelatives(joint, type="joint", c=True)
if children:
unparented = cmds.parent(children, w=True)
aimChild = cmds.listRelatives(unparented[0], type="joint", c=True)
upDir = worldUp
if guessUp and aimChild:
upDir = crossProduct(joint, unparented[0], aimChild[0])
cmds.delete(cmds.aimConstraint(unparented[0], joint, w=1, o=(0,0,0), aim=aimAxis, upVector=upAxis, worldUpVector=upDir, worldUpType="vector"))
freezeJointOrientation(joint)
cmds.parent(unparented, joint)
prevUp = upDir
else:
parent = cmds.listRelatives(joint, type="joint", p=True)
if parent:
cmds.delete(cmds.orientConstraint(parent[0], joint, w=1, o=(0,0,0)))
freezeJointOrientation(joint)
# ====================================================================================================
# ORIENT AS OBJECT / WORLD
# ====================================================================================================
def orientJointAsObjectUiManager(*args):
cmds.undoInfo(ock=True)
sel = cmds.ls(sl=True)
if len(sel)<2 or cmds.objectType(sel[1])!="joint":
print("USE: Select the object first, then SHIFT select the joint.")
else:
orientJointAsObject(sel[1], sel[0])
cmds.select(sel, r=True)
cmds.undoInfo(cck=True)
def orientJointAsObject(joint, obj):
children = cmds.listRelatives(joint, c=True)
if children: unparented = cmds.parent(children, w=True)
cmds.delete(cmds.orientConstraint(obj, joint, w=1, o=(0,0,0)))
freezeJointOrientation(joint)
if children: cmds.parent(unparented, joint)
def orientJointAsWorldUiManager(*args):
cmds.undoInfo(ock=True)
sel = cmds.ls(sl=True, type="joint")
if not sel: print("USE: Select one or more joints.")
else:
locator = cmds.spaceLocator()[0]
for j in sel: orientJointAsObject(j, locator)
cmds.delete(locator)
cmds.select(sel, r=True)
cmds.undoInfo(cck=True)
# ====================================================================================================
# MAIN WINDOW
# ====================================================================================================
def orientJointsWindow():
if cmds.window("jammOrientJointsWindow", ex=True):
cmds.deleteUI("jammOrientJointsWindow")
cmds.window("jammOrientJointsWindow", w=500, h=400, t="JAMMSoft Joint Orient Tool - v 1.0", sizeable=True)
cmds.formLayout("mainForm")
# === UI ELEMENTS WITH TOOLTIPS ===
cmds.radioButtonGrp("rbgAim", l="Aim Axis:", nrb=3, la3=("X","Y","Z"), sl=1, cw4=(80,40,40,40), ann="Select the aim axis for the joint.")
cmds.radioButtonGrp("rbgUp", l="Up Axis:", nrb=3, la3=("X","Y","Z"), sl=2, cw4=(80,40,40,40), ann="Select the up axis for the joint.")
cmds.checkBox("chbReverseAim", l="Reverse", ann="Reverse the aim axis direction.")
cmds.checkBox("chbReverseUp", l="Reverse", ann="Reverse the up axis direction.")
cmds.separator("sep1", style="in", h=3)
cmds.radioButtonGrp("rbgAllOrSelected", l="Operate on:", nrb=2, la2=("Hierarchy","Selected"), sl=1, cw3=(80,80,80), ann="Choose to orient all hierarchy or just selected joints.")
cmds.separator("sep2", style="in", h=3)
cmds.floatFieldGrp("rbgWorldUp", l="World Up: ", nf=3, v1=0.0, v2=1.0, v3=0.0, cw4=(65,50,50,50), ann="World Up vector for joint orientation.")
cmds.button("btnXUp", l="X", w=20, h=20, c=worldUpX, ann="Set World Up to X axis.")
cmds.button("btnYUp", l="Y", w=20, h=20, c=worldUpY, ann="Set World Up to Y axis.")
cmds.button("btnZUp", l="Z", w=20, h=20, c=worldUpZ, ann="Set World Up to Z axis.")
cmds.checkBox("chbGuess", l="Guess Up Direction", ann="Automatically calculate the Up axis.")
cmds.separator("sep3", style="in", h=3)
cmds.button("btnOrientJoints", l="Orient Joints", al="center", h=40, c=orientJointsUI, ann="Orient selected joints using the settings above.")
cmds.separator("sep4", style="double", h=3)
cmds.button("btnOrientJointAsOther", l="Orient Joint as Object Selected (Select object + SHIFT Select joint)", al="center", h=25, c=orientJointAsObjectUiManager, ann="Orient joint like the selected object.")
cmds.separator("sep5", style="in", h=3)
cmds.button("btnOrientJointAsWorld", l="Orient Joint as World Axis", al="center", h=25, c=orientJointAsWorldUiManager, ann="Orient joint as world space axis.")
cmds.separator("sep6", style="double", h=3)
cmds.floatFieldGrp("rbgManualTweak", l="Manual Tweak: ", nf=3, v1=0.0, v2=0.0, v3=0.0, cw4=(90,60,60,60), ann="Manual rotation tweak for X/Y/Z axes.")
cmds.button("btnPlusX", l="+", w=25, h=20, c=addInXValue, ann="Increase X rotation by 0.1")
cmds.button("btnMinusX", l="-", w=25, h=20, c=minusInXValue, ann="Decrease X rotation by 0.1")
cmds.button("btnPlusY", l="+", w=25, h=20, c=addInYValue, ann="Increase Y rotation by 0.1")
cmds.button("btnMinusY", l="-", w=25, h=20, c=minusInYValue, ann="Decrease Y rotation by 0.1")
cmds.button("btnPlusZ", l="+", w=25, h=20, c=addInZValue, ann="Increase Z rotation by 0.1")
cmds.button("btnMinusZ", l="-", w=25, h=20, c=minusInZValue, ann="Decrease Z rotation by 0.1")
cmds.button("btnPlusAll", l="Tweak All +", w=120, h=20, c=rotateAxisManualTweakPlus, ann="Apply manual tweak to all axes (+)")
cmds.button("btnMinusAll", l="Tweak All -", w=120, h=20, c=rotateAxisManualTweakMinus, ann="Apply manual tweak to all axes (-)")
cmds.separator("sep7", style="double", h=3)
cmds.button("btnShowAxisAll", l="Show Axis on Hierarchy", w=150, h=20, c=showHierarchyLocalAxis, ann="Show local rotation axes on all joints in hierarchy.")
cmds.button("btnHideAxisAll", l="Hide Axis on Hierarchy", w=150, h=20, c=hideHierarchyLocalAxis, ann="Hide local rotation axes on all joints in hierarchy.")
cmds.button("btnShowAxisSelected", l="Show Axis on Selected", w=150, h=20, c=showSelectedLocalAxis, ann="Show local axes on selected joints.")
cmds.button("btnHideAxisSelected", l="Hide Axis on Selected", w=150, h=20, c=hideSelectedLocalAxis, ann="Hide local axes on selected joints.")
cmds.separator("sep8", style="double", h=3)
cmds.iconTextButton("lblCopyright", l="Copyright 2010 - Jose Antonio Martin Martin.", w=310, h=20, style="textOnly", c="cmds.showHelp('http://www.joseantoniomartinmartin.com ', a=1)", ann="Visit the author's website.")
cmds.iconTextButton("lblCopyright2", l="All Rights Reserved.", w=310, h=20, style="textOnly", c="cmds.showHelp('http://www.joseantoniomartinmartin.com ', a=1)", ann="All rights reserved.")
# === FORM ATTACHMENTS (same as original)
cmds.formLayout("mainForm", e=True, attachForm=[
('rbgAim','left',0),('rbgAim','top',0),
('chbReverseAim','top',0),('chbReverseAim','left',210),('chbReverseAim','right',0),
('rbgUp','left',0),('rbgUp','top',20),
('chbReverseUp','top',20),('chbReverseUp','left',210),('chbReverseUp','right',0),
('sep1','left',0),('sep1','top',40),('sep1','right',0),
('rbgAllOrSelected','left',0),('rbgAllOrSelected','top',45),('rbgAllOrSelected','right',0),
('sep2','left',0),('sep2','top',65),('sep2','right',0),
('rbgWorldUp','left',0),('rbgWorldUp','top',70),
('btnXUp','left',255),('btnXUp','top',71),
('btnYUp','left',280),('btnYUp','top',71),
('btnZUp','left',305),('btnZUp','top',71),
('chbGuess','left',10),('chbGuess','top',90),('chbGuess','right',0),
('sep3','left',0),('sep3','top',110),('sep3','right',0),
('btnOrientJoints','left',0),('btnOrientJoints','top',115),('btnOrientJoints','right',0),
('sep4','left',0),('sep4','top',160),('sep4','right',0),
('btnOrientJointAsOther','left',0),('btnOrientJointAsOther','top',165),('btnOrientJointAsOther','right',0),
('sep5','left',0),('sep5','top',195),('sep5','right',0),
('btnOrientJointAsWorld','left',0),('btnOrientJointAsWorld','top',200),('btnOrientJointAsWorld','right',0),
('sep6','left',0),('sep6','top',230),('sep6','right',0),
('rbgManualTweak','left',0),('rbgManualTweak','top',235),
('btnPlusX','left',270),('btnPlusX','top',236),
('btnMinusX','left',300),('btnMinusX','top',236),
('btnPlusY','left',330),('btnPlusY','top',236),
('btnMinusY','left',360),('btnMinusY','top',236),
('btnPlusZ','left',390),('btnPlusZ','top',236),
('btnMinusZ','left',420),('btnMinusZ','top',236),
('btnPlusAll','left',150),('btnPlusAll','top',260),
('btnMinusAll','left',280),('btnMinusAll','top',260),
('sep7','left',0),('sep7','top',285),('sep7','right',0),
('btnShowAxisAll','left',0),('btnShowAxisAll','top',290),
('btnHideAxisAll','left',160),('btnHideAxisAll','top',290),
('btnShowAxisSelected','left',0),('btnShowAxisSelected','top',315),
('btnHideAxisSelected','left',160),('btnHideAxisSelected','top',315),
('sep8','left',0),('sep8','top',340),('sep8','right',0),
('lblCopyright','left',0),('lblCopyright','top',345),
('lblCopyright2','left',0),('lblCopyright2','top',365)
])
cmds.showWindow("jammOrientJointsWindow")
# ====================================================================================================
# RUN
# ====================================================================================================
orientJointsWindow()
Related Items:
-
Human Character Rig in 1 minute (skeleton, rig & bind skin in 1 minute) 3.1.0 for Maya (maya script)
$25.00 (USD) -
Python Batch for Maya 2.0.0 (maya script)
$20.00 (USD) -
3D Sphynx Cat Maya Rig 0.0.1 for Maya
$250.00 (USD) -
3D Silver Cyborg Maya Rig 0.0.1 for Maya
$200.00 (USD) -
Fire Ant Maya Rig 0.0.1 for Maya
$100.00 (USD) -
Nick-Maya Rig With Advance Facial Setup for Maya 0.1.0
$20.00 (USD)







Replies to this question: