Source code for bgdev.utils.pivot

"""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)