Last active
August 29, 2015 14:15
-
-
Save danbradham/929ab23057fbb3a01108 to your computer and use it in GitHub Desktop.
An arm rigging marathon.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
toolshed | |
======== | |
Rigging tools for Autodesk Maya. | |
''' | |
from maya import cmds, OpenMaya | |
import maya.api.OpenMaya as mapi | |
import traceback | |
CURVE_CTRLS = { | |
'circle' : [2, 3, [[2.0, 0.0, 0.0], [1.4142135381698608, 0.0, 1.4142135381698608], [0.0, 0.0, 2], [-1.4142134189605713, 0.0, 1.4142134189605713], [-2, 0.0, 0.0], [-1.4142134189605713, 0.0, -1.4142134189605713], [0.0, 0.0, -2], [1.4142134189605713, 0.0, -1.4142134189605713], [2.0, 0.0, 0.0], [1.4142135381698608, 0.0, 1.4142135381698608], [0.0, 0.0, 2]], [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], | |
'double_arrow' : [0, 3, [[1.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -2.0], [1.0, 0.0, -1.0], [1.0, 0.0, 0.0], [1.0, 0.0, 1.0], [1.0, 0.0, 2.0], [1.0, 0.0, 3.0], [1.0, 0.0, 3.0], [1.0, 0.0, 3.0], [2.0, 0.0, 3.0], [2.0, 0.0, 3.0], [2.0, 0.0, 3.0], [0.0, 0.0, 5.0], [0.0, 0.0, 5.0], [0.0, 0.0, 5.0], [-2.0, 0.0, 3.0], [-2.0, 0.0, 3.0], [-2.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 2.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, -2.0], [-1.0, 0.0, -3.0], [-1.0, 0.0, -3.0], [-1.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [0.0, 0.0, -5.0], [0.0, 0.0, -5.0], [0.0, 0.0, -5.0], [2.0, 0.0, -3.0], [2.0, 0.0, -3.0], [2.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -3.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42]], | |
'diamond' : [0, 1, [[0.0, -2.2204460492503131e-16, 1.0], [0.0, 1.0, 2.2204460492503131e-16], [1.0, 0.0, 0.0], [0.0, -2.2204460492503131e-16, 1.0], [0.0, -1.0, -2.2204460492503131e-16], [1.0, 0.0, 0.0], [0.0, 2.2204460492503131e-16, -1.0], [0.0, 1.0, 2.2204460492503131e-16], [-1.0, 0.0, 0.0], [0.0, -2.2204460492503131e-16, 1.0], [0.0, -1.0, -2.2204460492503131e-16], [-1.0, 0.0, 0.0], [0.0, 2.2204460492503131e-16, -1.0], [0.0, -1.0, -2.2204460492503131e-16]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], | |
'arrow' : [0, 3, [[-1.0, 0.0, 2.0], [-1.0, 0.0, 2.0], [-1.0, 0.0, 2.0], [1.0, 0.0, 2.0], [1.0, 0.0, 2.0], [1.0, 0.0, 2.0], [1.0, 0.0, 1.0], [1.0, 0.0, 0.0], [1.0, 0.0, -1.0], [1.0, 0.0, -2.0], [1.0, 0.0, -2.0], [1.0, 0.0, -2.0], [2.0, 0.0, -2.0], [2.0, 0.0, -2.0], [2.0, 0.0, -2.0], [0.0, 0.0, -4.0], [0.0, 0.0, -4.0], [0.0, 0.0, -4.0], [-2.0, 0.0, -2.0], [-2.0, 0.0, -2.0], [-2.0, 0.0, -2.0], [-1.0, 0.0, -2.0], [-1.0, 0.0, -2.0], [-1.0, 0.0, -2.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, 0.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 2.0], [-1.0, 0.0, 2.0], [-1.0, 0.0, 2.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]], | |
'square' : [0, 3, [[-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, -1.0], [0.0, 0.0, -1.0], [1.0, 0.0, -1.0], [1.0, 0.0, -1.0], [1.0, 0.0, -1.0], [1.0, 0.0, 0.0], [1.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]], | |
'quad_arrow' : [0, 3, [[-1.0, 0.0, -1.0], [-1.0, 0.0, -2.0], [-1.0, 0.0, -3.0], [-1.0, 0.0, -3.0], [-1.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [-2.0, 0.0, -3.0], [0.0, 0.0, -5.0], [0.0, 0.0, -5.0], [0.0, 0.0, -5.0], [2.0, 0.0, -3.0], [2.0, 0.0, -3.0], [2.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -3.0], [1.0, 0.0, -2.0], [1.0, 0.0, -1.0], [1.0, 0.0, -1.0], [1.0, 0.0, -1.0], [2.0, 0.0, -1.0], [3.0, 0.0, -1.0], [3.0, 0.0, -1.0], [3.0, 0.0, -1.0], [3.0, 0.0, -2.0], [3.0, 0.0, -2.0], [3.0, 0.0, -2.0], [5.0, 0.0, 0.0], [5.0, 0.0, 0.0], [5.0, 0.0, 0.0], [3.0, 0.0, 2.0], [3.0, 0.0, 2.0], [3.0, 0.0, 2.0], [3.0, 0.0, 1.0], [3.0, 0.0, 1.0], [3.0, 0.0, 1.0], [2.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 0.0, 2.0], [1.0, 0.0, 3.0], [1.0, 0.0, 3.0], [1.0, 0.0, 3.0], [2.0, 0.0, 3.0], [2.0, 0.0, 3.0], [2.0, 0.0, 3.0], [0.0, 0.0, 5.0], [0.0, 0.0, 5.0], [0.0, 0.0, 5.0], [-2.0, 0.0, 3.0], [-2.0, 0.0, 3.0], [-2.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 3.0], [-1.0, 0.0, 2.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-1.0, 0.0, 1.0], [-2.0, 0.0, 1.0], [-3.0, 0.0, 1.0], [-3.0, 0.0, 1.0], [-3.0, 0.0, 1.0], [-3.0, 0.0, 2.0], [-3.0, 0.0, 2.0], [-3.0, 0.0, 2.0], [-5.0, 0.0, 0.0], [-5.0, 0.0, 0.0], [-5.0, 0.0, 0.0], [-3.0, 0.0, -2.0], [-3.0, 0.0, -2.0], [-3.0, 0.0, -2.0], [-3.0, 0.0, -1.0], [-3.0, 0.0, -1.0], [-3.0, 0.0, -1.0], [-2.0, 0.0, -1.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, -1.0], [-1.0, 0.0, -1.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80]], | |
'cube' : [0, 1, [[-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, -1.0, -1.0], [-1.0, -1.0, -1.0], [-1.0, 1.0, -1.0], [1.0, 1.0, -1.0], [1.0, -1.0, -1.0], [1.0, 1.0, -1.0], [1.0, 1.0, 1.0], [1.0, -1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], [-1.0, -1.0, 1.0], [-1.0, 1.0, 1.0], [-1.0, 1.0, -1.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]], | |
'sphere' : [0, 1, [[0.0, 0.0, 0.99999994039535522], [0.0, 0.70710676908493042, 0.70710670948028564], [0.0, 1.0, 0.0], [0.0, 0.70710676908493042, -0.70710670948028564], [0.0, 0.0, -0.99999988079071045], [0.0, -0.70710676908493042, -0.70710670948028564], [0.0, -1.0, 0.0], [0.0, -0.70710676908493042, 0.70710670948028564], [0.0, 0.0, 0.99999994039535522], [-0.70710670948028564, 0.0, 0.70710670948028564], [-0.99999988079071045, 0.0, 0.0], [-0.70710670948028564, -0.70710676908493042, 0.0], [0.0, -1.0, 0.0], [0.70710676908493042, -0.70710676908493042, 0.0], [1.0, 0.0, 0.0], [0.70710676908493042, 0.70710676908493042, 0.0], [0.0, 1.0, 0.0], [-0.70710670948028564, 0.70710676908493042, 0.0], [-0.99999988079071045, 0.0, 0.0], [-0.70710670948028564, 0.0, -0.70710670948028564], [0.0, 0.0, -0.99999988079071045], [0.70710670948028564, 0.0, -0.70710670948028564], [1.0, 0.0, 0.0], [0.70710676908493042, 0.0, 0.70710676908493042], [0.0, 0.0, 0.99999994039535522]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]], | |
'curve_arrow' : [0, 3, [[-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229], [-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229], [-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229], [0.018569192177553262, 1.2821060677180985e-16, -2.288704620441234], [0.54183430390929821, 8.7536372115188425e-17, -1.1971143864196638], [0.72153617366577438, 0.0, 0.0], [0.54183430390929821, -8.7536372115188425e-17, 1.1971143864196638], [0.018569192177553262, -1.2821060677180985e-16, 2.288704620441234], [-0.80213398918053513, -7.9291405962377267e-17, 3.1785483731729229], [-0.80213398918053513, -7.9291405962377267e-17, 3.1785483731729229], [-0.80213398918053513, -7.9291405962377267e-17, 3.1785483731729229], [-0.0014337406636666383, -5.2190130379426478e-16, 4.1752172586460139], [-0.0014337406636666383, -5.2190130379426478e-16, 4.1752172586460139], [-0.0014337406636666383, -5.2190130379426478e-16, 4.1752172586460139], [-3.0848709783395956, 7.3507530853700062e-16, 3.3447575571917558], [-3.0848709783395956, 7.3507530853700062e-16, 3.3447575571917558], [-3.0848709783395956, 7.3507530853700062e-16, 3.3447575571917558], [-2.5066285909950636, 8.6291659629758236e-16, 1.0568845692311961], [-2.5066285909950636, 8.6291659629758236e-16, 1.0568845692311961], [-2.5066285909950636, 8.6291659629758236e-16, 1.0568845692311961], [-1.7059283424781946, 4.2030669846569465e-16, 2.0535534547042875], [-1.7059283424781946, 4.2030669846569465e-16, 2.0535534547042875], [-1.7059283424781946, 4.2030669846569465e-16, 2.0535534547042875], [-1.1756995538936976, 2.315235723958968e-16, 1.4786552628151766], [-0.83763552221426174, 1.0062375886995711e-16, 0.77341543852432126], [-0.72153617366577438, 0.0, 0.0], [-0.83763552221426174, -1.0062375886995711e-16, -0.77341543852432126], [-1.1756995538936976, -2.315235723958968e-16, -1.4786552628151766], [-1.7059283424781946, -4.2030669846569465e-16, -2.0535534547042875], [-1.7059283424781946, -4.2030669846569465e-16, -2.0535534547042875], [-1.7059283424781946, -4.2030669846569465e-16, -2.0535534547042875], [-2.5066285909950636, -8.6291659629758236e-16, -1.0568845692311961], [-2.5066285909950636, -8.6291659629758236e-16, -1.0568845692311961], [-2.5066285909950636, -8.6291659629758236e-16, -1.0568845692311961], [-3.0848709783395956, -7.3507530853700062e-16, -3.3447575571917558], [-3.0848709783395956, -7.3507530853700062e-16, -3.3447575571917558], [-3.0848709783395956, -7.3507530853700062e-16, -3.3447575571917558], [-0.0014337406636666383, 5.2190130379426478e-16, -4.1752172586460139], [-0.0014337406636666383, 5.2190130379426478e-16, -4.1752172586460139], [-0.0014337406636666383, 5.2190130379426478e-16, -4.1752172586460139], [-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229], [-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229], [-0.80213398918053513, 7.9291405962377267e-17, -3.1785483731729229]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42]], | |
'curve_quad_arrow' : [0, 3, [[-1.0, 1.2195798144924379, -1.0], [-1.0, 1.0319021046902834, -2.0], [-1.0, 0.73962334077416081, -3.0000000000000004], [-1.0, 0.73962334077416081, -3.0000000000000004], [-1.0, 0.73962334077416081, -3.0000000000000004], [-2.0, 0.57612185552316775, -3.0000000000000004], [-2.0, 0.57612185552316775, -3.0000000000000004], [-2.0, 0.57612185552316775, -3.0000000000000004], [0.0, 0.0052882016263648239, -5.0], [0.0, 0.0052882016263648239, -5.0], [0.0, 0.0052882016263648239, -5.0], [2.0, 0.57612185552316775, -3.0000000000000004], [2.0, 0.57612185552316775, -3.0000000000000004], [2.0, 0.57612185552316775, -3.0000000000000004], [1.0, 0.73962334077416081, -3.0000000000000004], [1.0, 0.73962334077416081, -3.0000000000000004], [1.0, 0.73962334077416081, -3.0000000000000004], [1.0, 1.0319021046902834, -2.0], [1.0, 1.2195798144924379, -1.0], [1.0, 1.2195798144924379, -1.0], [1.0, 1.2195798144924379, -1.0], [2.0, 1.0319021046902834, -1.0], [3.0000000000000004, 0.73962334077416081, -1.0], [3.0000000000000004, 0.73962334077416081, -1.0], [3.0000000000000004, 0.73962334077416081, -1.0], [3.0000000000000004, 0.57612185552316775, -2.0], [3.0000000000000004, 0.57612185552316775, -2.0], [3.0000000000000004, 0.57612185552316775, -2.0], [5.0, 0.0052882016263648239, 0.0], [5.0, 0.0052882016263648239, 0.0], [5.0, 0.0052882016263648239, 0.0], [3.0000000000000004, 0.57612185552316775, 2.0], [3.0000000000000004, 0.57612185552316775, 2.0], [3.0000000000000004, 0.57612185552316775, 2.0], [3.0000000000000004, 0.73962334077416081, 1.0], [3.0000000000000004, 0.73962334077416081, 1.0], [3.0000000000000004, 0.73962334077416081, 1.0], [2.0, 1.0319021046902834, 1.0], [1.0, 1.2195798144924379, 1.0], [1.0, 1.2195798144924379, 1.0], [1.0, 1.2195798144924379, 1.0], [1.0, 1.0319021046902834, 2.0], [1.0, 0.73962334077416081, 3.0000000000000004], [1.0, 0.73962334077416081, 3.0000000000000004], [1.0, 0.73962334077416081, 3.0000000000000004], [2.0, 0.57612185552316775, 3.0000000000000004], [2.0, 0.57612185552316775, 3.0000000000000004], [2.0, 0.57612185552316775, 3.0000000000000004], [0.0, 0.0052882016263648239, 5.0], [0.0, 0.0052882016263648239, 5.0], [0.0, 0.0052882016263648239, 5.0], [-2.0, 0.57612185552316775, 3.0000000000000004], [-2.0, 0.57612185552316775, 3.0000000000000004], [-2.0, 0.57612185552316775, 3.0000000000000004], [-1.0, 0.73962334077416081, 3.0000000000000004], [-1.0, 0.73962334077416081, 3.0000000000000004], [-1.0, 0.73962334077416081, 3.0000000000000004], [-1.0, 1.0319021046902834, 2.0], [-1.0, 1.2195798144924379, 1.0], [-1.0, 1.2195798144924379, 1.0], [-1.0, 1.2195798144924379, 1.0], [-2.0, 1.0319021046902834, 1.0], [-3.0000000000000004, 0.73962334077416081, 1.0], [-3.0000000000000004, 0.73962334077416081, 1.0], [-3.0000000000000004, 0.73962334077416081, 1.0], [-3.0000000000000004, 0.57612185552316775, 2.0], [-3.0000000000000004, 0.57612185552316775, 2.0], [-3.0000000000000004, 0.57612185552316775, 2.0], [-5.0, 0.0052882016263648239, 0.0], [-5.0, 0.0052882016263648239, 0.0], [-5.0, 0.0052882016263648239, 0.0], [-3.0000000000000004, 0.57612185552316775, -2.0], [-3.0000000000000004, 0.57612185552316775, -2.0], [-3.0000000000000004, 0.57612185552316775, -2.0], [-3.0000000000000004, 0.73962334077416081, -1.0], [-3.0000000000000004, 0.73962334077416081, -1.0], [-3.0000000000000004, 0.73962334077416081, -1.0], [-2.0, 1.0319021046902834, -1.0], [-1.0, 1.2195798144924379, -1.0], [-1.0, 1.2195798144924379, -1.0], [-1.0, 1.2195798144924379, -1.0]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80]], | |
'curve_double_arrow' : [0, 3, [[1.0, 0.84919716903699882, -3.0000000000000004], [1.0, 0.84919716903699882, -3.0000000000000004], [1.0, 0.84919716903699882, -3.0000000000000004], [1.0, 1.1847764905703249, -2.0], [1.0, 1.4002583055283548, -1.0], [1.0, 1.4745123954786876, 0.0], [1.0, 1.4002583055283548, 1.0], [1.0, 1.1847764905703249, 2.0], [1.0, 0.84919716903699882, 3.0000000000000004], [1.0, 0.84919716903699882, 3.0000000000000004], [1.0, 0.84919716903699882, 3.0000000000000004], [2.0, 0.66147324152660014, 3.0000000000000004], [2.0, 0.66147324152660014, 3.0000000000000004], [2.0, 0.66147324152660014, 3.0000000000000004], [0.0, 0.0060716389043447977, 5.0], [0.0, 0.0060716389043447977, 5.0], [0.0, 0.0060716389043447977, 5.0], [-2.0, 0.66147324152660014, 3.0000000000000004], [-2.0, 0.66147324152660014, 3.0000000000000004], [-2.0, 0.66147324152660014, 3.0000000000000004], [-1.0, 0.84919716903699882, 3.0000000000000004], [-1.0, 0.84919716903699882, 3.0000000000000004], [-1.0, 0.84919716903699882, 3.0000000000000004], [-1.0, 1.1847764905703249, 2.0], [-1.0, 1.4002583055283548, 1.0], [-1.0, 1.4745123954786876, 0.0], [-1.0, 1.4002583055283548, -1.0], [-1.0, 1.1847764905703249, -2.0], [-1.0, 0.84919716903699882, -3.0000000000000004], [-1.0, 0.84919716903699882, -3.0000000000000004], [-1.0, 0.84919716903699882, -3.0000000000000004], [-2.0, 0.66147324152660014, -3.0000000000000004], [-2.0, 0.66147324152660014, -3.0000000000000004], [-2.0, 0.66147324152660014, -3.0000000000000004], [0.0, 0.0060716389043447977, -5.0], [0.0, 0.0060716389043447977, -5.0], [0.0, 0.0060716389043447977, -5.0], [2.0, 0.66147324152660014, -3.0000000000000004], [2.0, 0.66147324152660014, -3.0000000000000004], [2.0, 0.66147324152660014, -3.0000000000000004], [1.0, 0.84919716903699882, -3.0000000000000004], [1.0, 0.84919716903699882, -3.0000000000000004], [1.0, 0.84919716903699882, -3.0000000000000004]], [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42]] | |
} | |
def create_follicle(name): | |
'''Create a follicle. | |
:param name: Name of the follicle''' | |
shape = cmds.createNode('follicle') | |
transform = cmds.listRelatives(shape, parent=True)[0] | |
transform = cmds.rename(transform, name) | |
shape = cmds.listRelatives(transform, shapes=True)[0] | |
cmds.connectAttr(shape + '.outRotate', transform + '.rotate') | |
cmds.connectAttr(shape + '.outTranslate', transform + '.translate') | |
return transform, shape | |
def get_shape(transform): | |
'''Get the first non-intermediate shape under a transform. | |
:param transform: The transform to query | |
''' | |
return cmds.listRelatives(transform, shapes=True, noIntermediate=True)[0] | |
def get_surface_type(surface): | |
'''Wrapper around cmds.nodeType, returns a str instead of unicode''' | |
return str(cmds.nodeType(surface)) | |
def rivet(name, surface, u, v): | |
'''Create a rivet. | |
:param name: Name of the rivet | |
:param surface: transform, mesh or nurbsSurface | |
:param u: U parameter of rivet | |
:param v: V parameter of rivet | |
:returns: transform and shape of a follicle attached to the given surface | |
''' | |
transform, shape = create_follicle(name) | |
surface_type = get_surface_type(surface) | |
if surface_type == 'transform': | |
surface = get_shape(surface) | |
surface_type = get_surface_type(surface) | |
if surface_type == 'mesh': | |
cmds.connectAttr(surface + '.worldMesh', shape + '.inputMesh') | |
cmds.connectAttr(surface + '.worldMatrix', shape + '.inputWorldMatrix') | |
elif surface_type == 'nurbsSurface': | |
cmds.connectAttr(surface + '.worldSpace', shape + '.inputSurface') | |
else: | |
raise RuntimeError('Incorrect surface type: ' + surface_type) | |
cmds.setAttr(shape + '.parameterU', u) | |
cmds.setAttr(shape + '.parameterV', v) | |
return transform, shape | |
def multi_rivet(nodes, surface, constrain=False): | |
'''Rivet a bunch of nodes to a surface. | |
:param nodes: List of nodes to rivet | |
:param surface: transform, mesh, or surface | |
:param constraint: use a parentConstraint instead of direct parenting | |
''' | |
rivets = [] | |
for node in nodes: | |
rivet_name = node.split('|')[-1] + '_RIV' | |
position = cmds.xform(node, q=True, ws=True, rp=True) | |
u, v = get_closest_uv(position, surface) | |
transform, shape = rivet(rivet_name, surface, u, v) | |
if not constrain: | |
cmds.parent(node, transform) | |
else: | |
cmds.parentConstraint(transform, node, maintainOffset=True) | |
rivets.append(transform) | |
clean_up() # Remove closest point nodes | |
return rivets | |
def get_closest_uv(position, surface): | |
'''Get the closest uv point from a worldspace position, on a mesh or | |
nurbsSurface. | |
:param position: worldspace position | |
:param surface: nurbsSurface, mesh, or transform | |
''' | |
surface_type = get_surface_type(surface) | |
if surface_type == 'transform': | |
surface = get_shape(surface) | |
surface_type = get_surface_type(surface) | |
if surface_type == 'mesh': | |
max_v = 1 | |
closest = 'closest_on_mesh' | |
if not cmds.objExists(closest): | |
cmds.createNode('closestPointOnMesh', name=closest) | |
if not surface in cmds.listConnections(closest, shapes=True): | |
cmds.connectAttr( | |
surface + '.worldMesh', | |
closest + '.inputMesh', | |
force=True) | |
cmds.connectAttr( | |
surface + '.worldMatrix', | |
closest + '.inputMatrix', | |
force=True) | |
elif surface_type == 'nurbsSurface': | |
max_v = cmds.getAttr(surface + '.spansV') | |
closest = 'closest_on_surface' | |
if not cmds.objExists(closest): | |
cmds.createNode('closestPointOnSurface', name=closest) | |
try: | |
cmds.connectAttr( | |
surface + '.worldSpace', | |
closest + '.inputSurface', | |
force=True) | |
except RuntimeError: | |
pass | |
cmds.setAttr(closest + '.inPosition', *position) | |
u = cmds.getAttr(closest + '.parameterU') | |
v = cmds.getAttr(closest + '.parameterV') / max_v | |
return u, v | |
def clean_up(): | |
'''Removes closest point nodes that maye have been created.''' | |
nodes = ['closest_on_mesh', 'closest_on_surface'] | |
for node in nodes: | |
if cmds.objExists(node): | |
cmds.delete(node) | |
def rivet_selected(): | |
'''Rivet selected items to a surface. Selected the rivet surface laster.''' | |
cmds.undoInfo(openChunk=True) | |
sel = cmds.ls(sl=True, long=True) | |
multi_rivet(sel[:-1], sel[-1], constrain=True) | |
cmds.undoInfo(closeChunk=True) | |
def insert_parent(node, suffix="_GRP"): | |
'''Insert a group above each node. | |
:param nodes: A list of all nodes to insert a group above. | |
:param suffix: Suffix to append to group name. | |
:returns: Long name of inserted parent | |
''' | |
ws_matrix = cmds.xform(node, q=True, ws=True, matrix=True) | |
p = cmds.group(name = node + suffix, em=True) | |
cmds.xform(p, ws=True, matrix=ws_matrix) | |
#Insert parent | |
current_p = cmds.listRelatives(node, parent=True) | |
if current_p: | |
cmds.parent(p, current_p) | |
cmds.parent(node, p) | |
return cmds.ls(p, long=True)[0] | |
def insert_joint_chain(base, end, num_joints=1): | |
'''Insert a joint chain beneath a joint. | |
:param base: Base joint to insert under | |
:param end: End joint to reparent under new chain | |
:param num_joints: Number of joints to insert (default=1) | |
''' | |
base_matrix = mapi.MMatrix(cmds.xform(base, q=True, ws=True, matrix=True)) | |
base_vect = mapi.MVector(cmds.xform(base, q=True, ws=True, rp=True)) | |
end_vect = mapi.MVector(cmds.xform(end, q=True, ws=True, rp=True)) | |
joint_vect = base_matrix * ((end_vect - base_vect) / (num_joints + 1.0)) | |
mid_chain = [] | |
for i in range(num_joints): | |
mid_chain.append(cmds.joint(relative=True, position=joint_vect)) | |
cmds.parent(end, mid_chain[-1]) | |
return mid_chain | |
def insert_joints(base, end, name='mid_{0:0>2d}_JNT', num_joints=1): | |
'''Insert unparent joints between a base joint and end joint. | |
:param base: Base joint to insert under | |
:param end: End joint to reparent under new chain | |
:param num_joints: Number of joints to insert (default=1) | |
''' | |
base_matrix = mapi.MMatrix(cmds.xform(base, q=True, ws=True, matrix=True)) | |
base_vect = mapi.MVector(cmds.xform(base, q=True, ws=True, rp=True)) | |
end_vect = mapi.MVector(cmds.xform(end, q=True, ws=True, rp=True)) | |
joint_vect = ((end_vect - base_vect) / (num_joints + 1.0)) | |
mid_joints = [] | |
for i in range(num_joints): | |
cmds.select(clear=True) | |
jnt = cmds.joint(name=name.format(i)) | |
cmds.xform(jnt, ws=True, matrix=base_matrix) | |
cmds.xform(jnt, ws=False, relative=True, translation=joint_vect * (i + 1)) | |
cmds.makeIdentity(jnt, rotate=True, apply=True) | |
mid_joints.append(jnt) | |
return mid_joints | |
def curve(points, degree, knots=None, periodic=False): | |
'''Create a nurbsCurve of a certain degree, automagically figure out knots. | |
:param points: list of OpenMaya.MVectors or lists of x, y, z values | |
:param degree: Degree of curve | |
''' | |
clean_points = [] | |
for point in points: | |
if isinstance(point, OpenMaya.MVector): | |
clean_points.append([point.x, point.y, point.z]) | |
else: | |
clean_points.append(point) | |
if degree == 1: | |
return cmds.curve(p=clean_points, d=1, periodic=False) | |
if knots is None: # Calculate knots | |
knots = [] | |
num_knots = len(clean_points) + degree - 1 | |
for i in xrange(num_knots): | |
if i < degree: | |
knots.append(0) | |
elif i > num_knots - degree: | |
knots.append(knots[-1]) | |
else: | |
knots.append(knots[-1] + 1) | |
return cmds.curve(p=clean_points, d=degree, k=knots, periodic=periodic) | |
def ribbon_surface(start_pos, end_pos, width, | |
divisions, up_vec=(0, 1, 0), pad=True): | |
'''Create a surface along the length of a joint. | |
:param start_pos: start of surface in world space | |
:param end_pos: end of surface in world space | |
:param joint: joint to create ribbon along | |
:param divisions: number of surface divisions | |
''' | |
start_pos = mapi.MVector(start_pos) | |
end_pos = mapi.MVector(end_pos) | |
vec = (end_pos - start_pos) | |
length = vec.length() | |
normal_vec = vec.normal() | |
up_vec = mapi.MVector(up_vec) | |
ortho_vec = normal_vec ^ up_vec | |
up_vec = normal_vec ^ ortho_vec | |
pnt_step = length / divisions | |
plus_curve_pnts = [] | |
minus_curve_pnts = [] | |
for x in xrange(divisions + 1): | |
pos = start_pos + (normal_vec * x * pnt_step) | |
plus_curve_pnts.append(pos + (up_vec * width * 0.5)) | |
minus_curve_pnts.append(pos - (up_vec * width * 0.5)) | |
degree = 3 if divisions > 1 else 1 | |
if degree == 3 and pad: | |
for crv_pnts in [plus_curve_pnts, minus_curve_pnts]: | |
start_a, start_b = crv_pnts[:2] | |
end_a, end_b = crv_pnts[-2:] | |
crv_pnts.insert(1, start_a + (start_b - start_a) * 0.3334) | |
crv_pnts.insert(-1, end_a + (end_b - end_a) * 0.6667) | |
plus_curve = curve(points=plus_curve_pnts, degree=degree) | |
minus_curve = curve(points=minus_curve_pnts, degree=degree) | |
surface = cmds.loft(plus_curve, minus_curve, degree=1, ch=False)[0] | |
cmds.delete(plus_curve, minus_curve) | |
return surface | |
def ribbon_surface_from_nodes(nodes, *args, **kwargs): | |
start_pos, end_pos = [cmds.xform(node, q=True, ws=True, rp=True) | |
for node in nodes] | |
return ribbon_surface(start_pos, end_pos, *args, **kwargs) | |
def ribbon_rig(start_jnt, end_jnt, num_controls, num_joints, *args, **kwargs): | |
start_pos = cmds.xform(start_jnt, q=True, ws=True, rp=True) | |
start_mat = cmds.xform(start_jnt, q=True, ws=True, matrix=True) | |
end_pos = cmds.xform(end_jnt, q=True, ws=True, rp=True) | |
end_mat = cmds.xform(end_jnt, q=True, ws=True, matrix=True) | |
# Nurbs surfaces | |
control_surface = ribbon_surface( | |
start_pos, | |
end_pos, | |
width=1, | |
divisions=1, | |
up_vec=start_mat[4:7]) | |
control_surface = cmds.rename(control_surface, 'ribbon_CTRL_SURF#') | |
joint_surface = ribbon_surface( | |
start_pos, | |
end_pos, | |
width=1, | |
divisions=num_joints + 1, | |
pad=True, | |
up_vec=start_mat[4:7]) | |
joint_surface = cmds.rename(joint_surface, 'ribbon_JNT_SURF#') | |
# Joints | |
aim_joints = [ | |
cmds.duplicate(start_jnt, name='ribbon_start_AIM_JNT#', po=True)[0], | |
cmds.duplicate(end_jnt, name='ribbon_end_AIM_JNT#', po=True)[0]] | |
ctrl_locs = [] | |
for mat, aim_joint in zip([start_mat, end_mat], aim_joints): | |
cmds.select(aim_joint, replace=True) | |
cmds.joint( | |
name=aim_joint.replace('AIM', 'AIM_END'), | |
relative=True, | |
position=[1, 0, 0]) | |
offset = mapi.MVector(mat[8:11]) + mapi.MVector(mat[12:15]) | |
up_mat = mat[:12] + list(offset) + mat[-1:] | |
pos_loc = cmds.spaceLocator(name=aim_joint.replace('_AIM_JNT', ''))[0] | |
up_loc = cmds.spaceLocator(name=aim_joint.replace('AIM_JNT', 'up'))[0] | |
cmds.xform(pos_loc, ws=True, matrix=mat) | |
cmds.xform(up_loc, ws=True, matrix=up_mat) | |
cmds.parent((up_loc, aim_joint), pos_loc) | |
ctrl_locs.append((pos_loc, up_loc)) | |
cmds.aimConstraint( | |
ctrl_locs[1][0], | |
aim_joints[0], | |
worldUpType='objectrotation', | |
worldUpObject=ctrl_locs[0][1]) | |
cmds.aimConstraint( | |
ctrl_locs[0][0], | |
aim_joints[1], | |
worldUpType='objectrotation', | |
worldUpObject=ctrl_locs[1][1]) | |
ctrl_joints = insert_joints( | |
start_jnt, | |
end_jnt, | |
name='j_{0:0>2d}_j#', | |
num_joints=num_controls) | |
ctrl_joints.insert(0, cmds.duplicate(start_jnt, po=True)[0]) | |
ctrl_joints.append(cmds.duplicate(end_jnt, po=True)[0]) | |
cmds.hide(ctrl_joints) | |
cmds.parent([ctrl_joints[0], ctrl_joints[-1]], world=True) | |
for i, j in enumerate(ctrl_joints): | |
ctrl_joints[i] = cmds.rename(j, 'ribbon_{0:0>2d}_JNT#'.format(i + 1)) | |
bind_joints = insert_joints( | |
start_jnt, | |
end_jnt, | |
name='ribbon_{0:0>2d}_BIND_JNT#', | |
num_joints=num_joints) | |
ctrl_groups = [] | |
for ctrl in ctrl_joints: | |
ctrl_group, ctrl_curve = add_control( | |
ctrl, | |
name=ctrl.replace('JNT', 'CTRL'), | |
typ='circle', | |
color='yellow', | |
axis=(1, 0, 0), | |
scale=cmds.getAttr(start_jnt + '.radius') * 0.667, | |
constrain=False) | |
ctrl_groups.append(ctrl_group.split('|')[-1]) | |
ctrl_rivets = multi_rivet(ctrl_groups, control_surface, constrain=True) | |
bind_rivets = multi_rivet(bind_joints, joint_surface, constrain=True) | |
rivet_grp = cmds.group(ctrl_rivets + bind_rivets, name='ribbon_RIV_GRP#') | |
bind_grp = cmds.group(bind_joints, name='ribbon_BIND_GRP#') | |
cmds.skinCluster(aim_joints, control_surface, toSelectedBones=True) | |
cmds.skinCluster(ctrl_joints, joint_surface) | |
return ctrl_locs, bind_grp, rivet_grp, ctrl_groups, (control_surface, joint_surface) | |
def override_color(color=None, *nodes): | |
"""Sets override color for transform or shape. | |
:param color: The name of a color or an int(0-31)""" | |
colors = { | |
"blue": 6, | |
"red": 13, | |
"yellow": 17, | |
"light yellow": 22, | |
"green": 26, | |
"light green": 27, | |
"light blue": 29, | |
} | |
if color in colors: | |
color = colors[color] | |
for node in nodes: | |
cmds.setAttr(node + ".overrideEnabled", 1) | |
cmds.setAttr(node + ".overrideColor", color) | |
def add_control(node, name, axis=(0, 1, 0), scale=1, typ='circle', color=None, | |
constrain=False): | |
'''Add a control to a node. | |
:param node: Node that needs a new control | |
:param name: Name of the new control | |
:param typ: Type of control to create | |
:param color: Color of control to create | |
:param constrain: Use a parent constraint instead of direct parenting | |
''' | |
per, deg, pnts, knts = CURVE_CTRLS[typ] | |
ctrl = curve(points=pnts, degree=deg, knots=knts, periodic=per) | |
ctrl = cmds.rename(ctrl, name) | |
ctrl_shape = get_shape(ctrl) | |
scale = [scale for i in xrange(3)] | |
if color is not None: | |
override_color(color, ctrl_shape) | |
if axis == (1, 0, 0): | |
cmds.xform(ctrl, ws=True, scale=scale, rotation=mapi.MVector((0, 0, 1)) * 90) | |
elif axis == (0, 0, 1): | |
cmds.xform(ctrl, ws=True, scale=scale, rotation=mapi.MVector((1, 0, 0)) * 90) | |
cmds.makeIdentity(apply=True, rotate=True) | |
if not constrain: | |
ctrl_grp = insert_parent(node) | |
cmds.parent(ctrl, ctrl_grp, relative=True) | |
cmds.parent(node, ctrl) | |
else: | |
ctrl_grp = cmds.group(ctrl) | |
cmds.xform( | |
ctrl_grp, | |
ws=True, | |
matrix=cmds.xform(node, q=True, ws=True, matrix=True)) | |
cmds.parentConstraint(ctrl, node) | |
return ctrl_grp, ctrl | |
def ribbon_limb(joints, num_controls, num_joints): | |
'''Add a ribbon between each set of joints in a chain. | |
:param joints: list of joints to add ribbons to | |
''' | |
old_selection = cmds.ls(sl=True, long=True) | |
cmds.select(clear=True) | |
start_jnt, mid_jnt, end_jnt = joints | |
# Setup mid section | |
mid_radius = cmds.getAttr(mid_jnt + '.radius') | |
mid_control = cmds.circle( | |
name='mid_LOC#', | |
radius=mid_radius * 2.5, | |
normal=(1, 0, 0))[0] | |
mid_bind_jnt = cmds.joint(name='mid_BIND_JNT#', radius=mid_radius * 1.5) | |
cmds.parent(mid_control, mid_jnt, relative=True) | |
cmds.parentConstraint(mid_control, mid_bind_jnt) | |
mid_grp = insert_parent(mid_control) | |
cmds.orientConstraint(start_jnt, mid_jnt, mid_grp) | |
cmds.select(clear=True) | |
# Setup Ribbons | |
ribbon_a = ribbon_rig(start_jnt, mid_jnt, num_controls, num_joints) | |
ribbon_b = ribbon_rig(mid_jnt, end_jnt, num_controls, num_joints) | |
a_ctrls, a_bind, a_rivet, a_ctrl_groups, a_surfaces = ribbon_a | |
b_ctrls, b_bind, b_rivet, b_ctrl_groups, b_surfaces = ribbon_b | |
cmds.pointConstraint(start_jnt, a_ctrls[0][0]) | |
cmds.pointConstraint(mid_control, a_ctrls[1][0]) | |
cmds.orientConstraint(mid_control, a_ctrls[1][0], skip='y') | |
cmds.orientConstraint(mid_control, b_ctrls[0][0], skip='y') | |
cmds.pointConstraint(mid_control, b_ctrls[0][0]) | |
cmds.pointConstraint(end_jnt, b_ctrls[1][0]) | |
cmds.orientConstraint(end_jnt, b_ctrls[1][0], skip='none') | |
# Regroup it all | |
bind_joints = [mid_bind_jnt] | |
bind_joints.extend(cmds.listRelatives(a_bind, children=True)) | |
bind_joints.extend(cmds.listRelatives(b_bind, children=True)) | |
bind_grp = cmds.group(bind_joints, name='ribbon_BIND#') | |
ctrl_groups = a_ctrl_groups + b_ctrl_groups | |
ctrl_grp = cmds.group(ctrl_groups, name='ribbon_CTRLS#') | |
scale_grp = cmds.group(empty=True, name='ribbon_SCALE_GRP#') | |
cmds.delete(cmds.parentConstraint(start_jnt, scale_grp)) | |
cmds.parent([bind_grp, ctrl_grp], scale_grp) | |
cmds.parent([a_ctrls[0][0], a_ctrls[1][0]], scale_grp) | |
cmds.parent([b_ctrls[0][0], b_ctrls[1][0]], scale_grp) | |
extras = cmds.group(name='ribbon_EXTRAS#', empty=True) | |
cmds.parent(a_surfaces, extras) | |
cmds.parent(b_surfaces, extras) | |
cmds.parent([a_rivet, b_rivet], extras) | |
cmds.hide([a_ctrls[0][0], a_ctrls[1][0], b_ctrls[0][0], b_ctrls[1][0]]) | |
cmds.hide(extras) | |
cmds.hide(bind_grp) | |
#Clean up | |
cmds.delete(a_bind, b_bind) | |
cmds.select(old_selection) | |
return | |
if __name__ == '__main__': | |
cmds.undoInfo(openChunk=True) | |
try: | |
ribbon_limb(cmds.ls(sl=True, type='joint'), 2, 5) | |
except Exception as e: | |
traceback.print_exc() | |
finally: | |
# clean_up() | |
cmds.undoInfo(closeChunk=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment