Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation Import/Export #6

Open
mottosso opened this issue Jul 15, 2020 · 0 comments
Open

Animation Import/Export #6

mottosso opened this issue Jul 15, 2020 · 0 comments

Comments

@mottosso
Copy link
Owner

mottosso commented Jul 15, 2020

Compatible with Maya 2015 SP4 --> Maya 2021+

Out of the many ways to export/import animation in Maya, from the built-in .atom format from 2013 to the .anim file format form 1993, here's a different take.

  1. ---> Export related animCurve nodes as a mayaAscii scene
  2. <--- Import animCurve nodes from the mayaAscii scene, elsewhere
  3. -><- Connect each node to their corresponding target

It is..

  • Simple ~100 lines of Python, no "clipboard", no "views", no "templates", no MEL, no smarts
  • Robust In that the original animation is preserved exactly
  • Lightweight In that only animated channels are exported, no pre-processing required
  • Fast As fast as Maya is able to export and import scene files
  • Native As a regular Maya Ascii file, import it yourself, anywhere and without the need for Python

With a few caveats..

  • No static channels
  • No animation layers
  • No partial-range export or import
  • Names must match exactly between export/import targets

Each of which could potentially be solved with some further tinkering.

animio1


Usage

  1. Download cmdx to your ~/maya/scripts folder
  2. Copy/paste the implementation below, and use it like this..

Based on your current selection

# Custom suffix
fname = cmds.file("anim1.manim", expandName=True, query=True)

# From scene A
export_animation(fname)

# From scene B
import_animation(fname)

Implementation

import cmdx
from maya import cmds  # for select()

def export_animation(fname):
    """Export animation for selected nodes to `fname`

    Animation is exported as native Maya nodes, e.g. animCurveTU
    and later imported and re-connected to their original nodes
    
    Limitations:
        - No animation layers
        - Names much match exactly between exported and imported nodes

    """

    animation = []
    for node in cmdx.selection(type="transform"):  # Optionally limited to transform nodes

        # Find any curve connecting to this node
        for curve in node.connections():
            if not isinstance(curve, cmdx.AnimCurve):
                continue

            # Encode target connection as string attribute
            # for retrieval during `import_animation`
            if not curve.has_attr("target"):
                curve["target"] = cmdx.String()

            # Find the attribute to which this curve connects
            plug = curve.connection(plug=True)
            curve["target"] = plug.path()
    
            animation.append(curve)

    if not animation:
        cmds.warning(
            "Select objects in the scene to "
            "export any connected animation"
        )

        return cmds.warning("No animation found, see Script Editor for details")

    previous_selection = cmds.ls(selection=True)
    cmds.select(map(str, animation))

    try:
        cmds.file(
            fname,

            # Overwrite existing
            force=True,

            # Use our own suffix
            defaultExtensions=False,

            # Internal format, despite our format
            type="mayaAscii",

            exportSelected=True,

            # We don't want anything but the selected animation curves
            constructionHistory=False
        )

    except Exception:
        import traceback
        traceback.print_exc()
        cmds.warning("Something unexpected happened when trying to export, see Script Editor for details.")

    finally:
        cmds.select(previous_selection)

    print("Successfully exported '%s'" % fname)


def import_animation(fname):
    previous_selection = cmds.ls(selection=True)

    try:
        animation = cmds.file(fname, i=True, returnNewNodes=True)

    except Exception:
        import traceback
        traceback.print_exc()
        return cmds.warning(
            "Something unexpected happened when trying "
            "to import '%s', see Script Editor for details"
            % fname
        )

    finally:
        cmds.select(previous_selection)

    for curve in animation:
        curve = cmdx.encode(curve)

        if not curve.has_attr("target"):
            cmds.warning("Skipped: '%s' did not have the `target` "
                                  "attribute used to reconnect the animation"
                                  % curve)
            continue

        # Stored as "<node>.<attr>" e.g. "pCube1.tx"
        node, attr = curve["target"].read().rsplit(".", 1)

        try:
            target = cmdx.encode(node)
        except cmdx.ExistError:
            cmds.warning("Skipped: '%s' did not exist" % node)
            continue

        # Make the connection, replacing any existing
        curve["output"] >> target[attr]

    print("Successfully imported '%s'!" % fname)

Next Steps

  1. Avoid nameclashes When importing animation the second time, the curve nodes share a name which throws a warning. By importing into a namespace, any node matching the name outside of this namespace can be removed prior to import
  2. Search-and-replace To support alternative names, namespaces and multiple instances of the same character or scene
  3. Animation Layers It'd be a matter of exporting not just the curve, but the network leading into the node being animated, which would include the animation layer setup.

An example of how names clash.

animio2


When to Use

That is, why not use .anim or .atom? If you can, you probably should. The are already installed (or are they?), they've got documentation (or do they?), they've got more features (of value?) and others may be able to help out when things go south (or can they?).

I would use it when what I want is to export/import animation from one scene to another without fuss; when I don't remember my login details to HighEnd3D and aren't interested in experimenting with the various MEL alternatives on there, and when I haven't got the budget nor time to understand or implement support for ATOM.

YMMV :) Let me know what you think!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant