0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

maya python export curves

Last updated at Posted at 2022-09-05
import json
import logging
import maya.cmds as cmds
import maya.api.OpenMaya as OpenMaya

logger = logging.getLogger(__name__)

def export_curves(controls=None, file_path=None):
    """Serializes the given curves into the control library.

    :param controls: Optional list of controls to export. If no controls are specified,
        the selected curves will be exported.
    :param file_path: File path to export to
    :return: The exported list of ControlShapes.
    """
    if controls is None:
        controls = cmds.ls(sl=True)
    data = get_curve_data(controls)
    with open(file_path, "w") as fh:
        json.dump(data, fh, indent=4, cls=CurveShapeEncoder)
        logger.info("Exported controls to {}".format(file_path))
    return data

def import_curves(file_path=None, tag_as_controller=False):
    """Imports control shapes from disk onto their saved named transforms.

    :param file_path: Path to the control file.
    :param tag_as_controller: True to tag the curve transform as a controller
    :return: The new curve transforms
    """
    controls = load_curves(file_path)

    transforms = [
        curve.create(curve.transform, tag_as_controller) for curve in controls
    ]
    return transforms

def get_curve_data(controls=None):
    """Get the serializable data of the given controls.

    :param controls: Controls to serialize
    :return: List of ControlShape objects
    """
    if controls is None:
        controls = cmds.ls(sl=True)
    data = [CurveShape(transform=control) for control in controls]
    # Prune empty curves
    data = [x for x in data if x.cvs]
    return data

def load_curves(file_path=None):
    """Load the CurveShape objects from disk.

    :param file_path:
    :return:
    """

    with open(file_path, "r") as fh:
        data = json.load(fh)
    logger.info("Loaded controls {}".format(file_path))
    curves = [CurveShape(**control) for control in data]
    return curves

def get_shape(node, intermediate=False):
    """Get the shape node of a tranform

    This is useful if you don't want to have to check if a node is a shape node
    or transform.  You can pass in a shape node or transform and the function
    will return the shape node.

    :param node:  node The name of the node.
    :param intermediate:  intermediate True to get the intermediate shape
    :return: The name of the shape node.
    """
    if cmds.objectType(node, isAType="transform"):
        shapes = cmds.listRelatives(node, shapes=True, path=True)
        if not shapes:
            shapes = []
        for shape in shapes:
            is_intermediate = cmds.getAttr("{}.intermediateObject".format(shape))
            if (
                intermediate
                and is_intermediate
                and cmds.listConnections(shape, source=False)
            ):
                return shape
            elif not intermediate and not is_intermediate:
                return shape
        if shapes:
            return shapes[0]
    elif cmds.nodeType(node) in ["mesh", "nurbsCurve", "nurbsSurface"]:
        is_intermediate = cmds.getAttr("{}.intermediateObject".format(node))
        if is_intermediate and not intermediate:
            node = cmds.listRelatives(node, parent=True, path=True)[0]
            return get_shape(node)
        else:
            return node
    return None

def get_knots(curve):
    """Gets the list of knots of a curve so it can be recreated.

    :param curve: Curve to query.
    :return: A list of knot values that can be passed into the curve creation command.
    """
    curve = get_shape(curve)
    info = cmds.createNode("curveInfo")
    cmds.connectAttr("{0}.worldSpace".format(curve), "{0}.inputCurve".format(info))
    knots = cmds.getAttr("{0}.knots[*]".format(info))
    knots = [int(x) for x in knots]
    cmds.delete(info)
    return knots

class CurveShape(object):
    """Represents the data required to build a nurbs curve shape"""

    def __init__(
        self, transform=None, cvs=None, degree=3, form=0, knots=None, color=None
    ):
        self.cvs = cvs
        self.degree = degree
        self.form = form
        self.knots = knots
        self.color = color
        self.transform_matrix = OpenMaya.MTransformationMatrix()
        self.transform = transform
        if transform and cmds.objExists(transform) and not cvs:
            self._set_from_curve(transform)

    def _set_from_curve(self, transform):
        """Store the parameters from an existing curve in the CurveShape object.

        :param transform: Transform
        """
        shape = get_shape(transform)
        if shape and cmds.nodeType(shape) == "nurbsCurve":
            create_attr = "{}.create".format(shape)
            connection = cmds.listConnections(create_attr, plugs=True, d=False)
            if connection:
                cmds.disconnectAttr(connection[0], create_attr)
            self.transform = transform
            self.cvs = cmds.getAttr("{}.cv[*]".format(shape))
            self.degree = cmds.getAttr("{}.degree".format(shape))
            self.form = cmds.getAttr("{}.form".format(shape))
            self.knots = get_knots(shape)
            if cmds.getAttr("{}.overrideEnabled".format(shape)):
                if cmds.getAttr("{}.overrideRGBColors".format(shape)):
                    self.color = cmds.getAttr("{}.overrideColorRGB".format(shape))[0]
                else:
                    self.color = cmds.getAttr("{}.overrideColor".format(shape))
            else:
                self.color = None
            if connection:
                cmds.connectAttr(connection[0], create_attr)

    def create(self, transform=None, as_controller=True):
        """Create a curve.

        :param transform: Name of the transform to create the curve shape under.
            If the transform does not exist, it will be created.
        :param as_controller: True to mark the curve transform as a controller.
        :return: The transform of the new curve shapes.
        """
        transform = transform or self.transform
        if not cmds.objExists(transform):
            transform = cmds.createNode("transform", name=transform)
        periodic = self.form == 2
        points = self._get_transformed_points()
        points = points + points[: self.degree] if periodic else points
        curve = cmds.curve(degree=self.degree, p=points, per=periodic, k=self.knots)
        shape = get_shape(curve)
        if self.color is not None:
            cmds.setAttr("{}.overrideEnabled".format(shape), True)
            if isinstance(self.color, int):
                cmds.setAttr("{}.overrideColor".format(shape), self.color)
            else:
                cmds.setAttr("{}.overrideRGBColors".format(shape), True)
                cmds.setAttr("{}.overrideColorRGB".format(shape), *self.color)
        cmds.parent(shape, transform, r=True, s=True)
        shape = cmds.rename(shape, "{}Shape".format(transform))
        cmds.delete(curve)
        if as_controller:
            cmds.controller(transform)
        logger.info("Created curve {} for transform {}".format(shape, transform))
        return transform

    def _get_transformed_points(self):
        matrix = self.transform_matrix.asMatrix()
        points = [OpenMaya.MPoint(*x) * matrix for x in self.cvs]
        points = [(p.x, p.y, p.z) for p in points]
        return points

    def translate_by(self, x, y, z, local=True):
        """Translate the curve cvs by the given values

        :param x: Translate X
        :param y: Translate Y
        :param z: Translate Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.translateBy(OpenMaya.MVector(x, y, z), space)

    def set_translation(self, x, y, z, local=True):
        """Set the absolute translation of the curve shape.

        :param x: Translate X
        :param y: Translate Y
        :param z: Translate Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.setTranslation(OpenMaya.MVector(x, y, z), space)

    def rotate_by(self, x, y, z, local=True):
        """Rotate the curve cvs by the given euler rotation values

        :param x: Rotate X
        :param y: Rotate Y
        :param z: Rotate Z
        :param local: True for local space, False for world
        """
        x, y, z = [v * 0.0174533 for v in [x, y, z]]
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.rotateBy(OpenMaya.MEulerRotation(x, y, z), space)

    def set_rotation(self, x, y, z):
        """Set the absolute rotation of the curve shape in euler rotations.

        :param x: Rotate X
        :param y: Rotate Y
        :param z: Rotate Z
        """
        x, y, z = [v * 0.0174533 for v in [x, y, z]]
        self.transform_matrix.setRotation(OpenMaya.MEulerRotation(x, y, z))

    def scale_by(self, x, y, z, local=True):
        """Scale the curve cvs by the given amount.

        :param x: Scale X
        :param y: Scale Y
        :param z: Scale Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.scaleBy([x, y, z], space)

    def set_scale(self, x, y, z, local=True):
        """Set the absolute scale of the curve shape.

        :param x: Scale X
        :param y: Scale Y
        :param z: Scale Z
        :param local: True for local space, False for world
        """
        space = OpenMaya.MSpace.kObject if local else OpenMaya.MSpace.kWorld
        self.transform_matrix.setScale([x, y, z], space)

def ExportCurves():
    curve_transforms = [cmds.listRelatives(i, p=1, type='transform')[0] for i
    in cmds.ls(type='nurbsCurve', o=1, r=1, ni=1)]
    selectList = []
    for c in curve_transforms:
        if "RootX_M" in c or "Neck_M" in c:
            selectList.append(c)

    file_path = "D:/curves.json"
    export_curves(selectList, file_path)

def ImportCurves():
    file_path = "D:/curves.json"
    import_curves(file_path, True)

#ExportCurves()
ImportCurves()
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?