"""This module deals with pivot import/export.
:created: 04/01/2018
:author: Benoit GIELLY <benoit.gielly@gmail.com>
"""
from __future__ import absolute_import, print_function
import json
import os
from maya import cmds
[docs]def export_to_file(path, rules=None, base_grp="modelHierarchy"):
"""Export pivots matrices.
Args:
path (file): Path to JSON file
rules (dict): Custom "SkinMap" or it will be autogenerated by :func:`generate_data`
base_grp (str): Top group to pass into the data autogeneration function
Returns:
dict: The pivot data
"""
rules = rules or generate_data(base_grp=base_grp)
pivot = {"data": dict()}
if not isinstance(rules, dict):
# from rig.data.data import SkinDict
rules = dict(zip(cmds.ls(rules), cmds.ls(rules)))
for item, name in rules.iteritems():
if cmds.objExists(name):
pivot["data"][item] = cmds.xform(
name, query=True, worldSpace=True, matrix=True
)
if path:
with open(path, "w") as _file:
json.dump(pivot, _file, indent=4)
print(' > Pivots exported properly in "{}"'.format(path))
return pivot
[docs]def generate_data(base_grp="modelHierarchy"):
"""Autogenerate a dictionary based on constraint nodes in scenes.
The key/value pair is equal to nodes/joints.
Args:
base_grp (str): Top group to investigate all descendents from.
Returns:
dict: Dictionary that maps the node with its driver.
"""
data = {}
all_constraints = cmds.listRelatives(
base_grp, allDescendents=True, type="constraint"
)
for each in all_constraints:
_cnst = getattr(cmds, cmds.nodeType(each))
_inputs = cmds.listConnections(each, source=False)
env = list({x for x in _cnst(each, query=True, targetList=True)})
nodes = list(
{x for x in _inputs if not cmds.nodeType(x).endswith("Constraint")}
)
for node in nodes:
if "dagNode" in cmds.nodeType(node, inherited=True):
data.update({str(node): str(env[0])})
return data
[docs]def import_from_file(path):
"""Import pivots from json file.
Args:
path (file): Path to JSON file
Returns:
dict: The data dictionary used
"""
if not os.path.exists(path):
return False
with open(path) as data_file:
data = json.load(data_file)
if "data" not in data:
return False
selection = cmds.ls(selection=True)
for node, matrix in data["data"].iteritems():
if not cmds.objExists(node):
continue
scale = cmds.getAttr(node + ".scale")[0]
childs = (
cmds.listRelatives(node, children=True, type="transform") or []
)
meshes = cmds.listRelatives(node, children=True, type="mesh")
for child in childs:
cmds.parent(child, world=True)
if not meshes:
cmds.xform(node, matrix=matrix, worldSpace=True)
else:
reset_pivot(node, matrix)
cmds.setAttr(node + ".scale", *scale)
if childs:
cmds.parent(childs, node)
cmds.select(selection)
print(" > Pivots properly applied to meshes!")
return data
[docs]def reset_pivot(mesh, matrix):
"""Reset given mesh to given matrix.
Args:
mesh (str): Node to reset pivot
matrix (matrix): Matrix table giving the exact position of the pivot
"""
# create temp locator at pivot position
loc = cmds.spaceLocator()[0]
cmds.xform(loc, worldSpace=True, matrix=matrix)
# parent the node in a transform and bring it back to world center
parent = (cmds.listRelatives(mesh, parent=True) or [None])[0]
temp = cmds.group(empty=True, parent=loc)
cmds.parent(mesh, temp)
cmds.parent(temp, world=True, relative=True)
# freeze tranforms and reset pivot
cmds.makeIdentity(
mesh, apply=True, translate=True, rotate=True, scale=True
)
cmds.delete(mesh, constructionHistory=True)
cmds.setAttr(mesh + ".rotatePivot", 0, 0, 0)
cmds.setAttr(mesh + ".scalePivot", 0, 0, 0)
# snap back to its original location
cmds.parent(temp, loc, relative=True)
if parent:
cmds.parent(mesh, parent)
else:
cmds.parent(mesh, world=True)
cmds.delete(temp, loc)