[PYTHON] Make up for the lack of Maya Node reference

Good morning everyone. It seems that ** Maya Road Book ** will be published soonApparently (Introduced by the author) According to the dependency node (DG), which is the core technology of maya, a purveyor to maya hackers. , Directed Acyclic Graph (DAG) will be explained. I'm happy! Now, let's prepare for the maya node by referring to the official document (http://help.autodesk.com/cloudhelp/2017/JPN/Maya-Tech-Docs/Nodes/index.html) [^ 3] .. If you are a unit conversion enthusiast, you will soon notice. Yes, I didn't write about decomposeMatrix / eulerToQuat / quatToEuler! What do you mean! This ** reference does not contain any plugin-derived nodes **! With this, it is hopeless that both the super cool MASH and Bifrost can be controlled by a node from a script. What a mess * (If you know the location of the reference for the node derived from the plugin, please let me know) * But don't be sad! ** Although it is not official, it is posted on http://yamahigashi.github.io/maya-node-list/index.html **. This is ** Conversion Hodai **. Yay

[^ 3]: If you want to prepare, don't use this http://help.autodesk.com/view/MAYAUL/2017/JPN/?guid=__files_DAG_Hierarchy_htm or http://help.autodesk.com/view/MAYAUL/2017/ Read JPN /? Guid = __files_Dependency_graph_plugins_htm first


Yota Preface has been lengthened, this article will explain how to retrieve node information via a script and how to write it out to a document. Through the generation of the document, I will tell you a small story when executing the desired process without starting the GUI of maya. All the scripts used to generate the documentation can be found at here. (However, please note that it uses a lot of extremely bad manners. * I thought I would never see it twice. * Please bring only the idea.)

Overview

First of all, the general flow of document generation is

  1. Export node information from mayapy.exe with reStructured Text (rst)
  2. Convert the exported rst to html using sphinx

There are two steps.

Batch launch

You can also execute the export from normal maya gui, but here we will try batch startup. Please refer to the official documentation for using mayapy.exe. http://help.autodesk.com/view/MAYAUL/2017/JPN/?guid=GUID-83799297-C629-48A8-BCE4-061D3F275215

Script execution

Feed mayapy an rst generation script from the command line C: \ Program Files \ Autodesk \ Maya2017 \ bin \ mayapy.exe dump_maya_nodes.py And so on.

The purpose of the process is ** [Export node information list] **. Now let's think about how to handle a large number of nodes. To write out node information, you first need to identify the node. It seems that ID can be used for this. So how do you get the ID? Google? No Let the computer do what the computer is good at. That's right, let's count from 0. [^ 1] Create a node by brute force, continue processing if there is a hit, and pass through as it is if there is nothing. [^ 2]

This is anyway, so let's run it in parallel. Use the multiprocessing module.

[^ 1]: While I was doing this article, I noticed that MPlugin might be able to pull MTypeId. [^ 2]: As an aside, I have no idea what to do with MTypeId. I wonder what criteria should be used when creating my own node plug-in because it is a built-in one ... Issuing an id in Autodesk? Hmm

dump_maya_nodes.py


# https://github.com/yamahigashi/maya-node-list/blob/gh-pages/tool/dump_maya_nodes.py#L1265-L1294
def dump_id_range_using_multiprocessing():

    import multiprocessing as mp
    import itertools  # python 2.x can not iterate over 'long int' cause overflow error
    range = lambda start, stop: iter(itertools.count(start).next, stop)

    process_count = 4  # mp.cpu_count()
    po = mp.Pool(process_count)
    po.map(initialize_process, xrange(process_count))

    start = 0x30000000
    steps = 0x00001000
    end = 0x90000001
    ceil = 1e4

    while start < end:
        # print('start processing...', start)
        res = po.map_async(dump_node_by_id, range(start, start + steps))

        # wait a moment as the main process eat up huge memory
        # when runnig continuously
        if len(po._cache) > ceil:
            print(".", hex(start))
            res.wait()

        start = start + steps

    po.close()
    po.join()

    print('... done processing')

It looks like this.

I will omit about multiprocessing. Let's look at the processing order. First, prepare a process for process_count in the pool. Initialize the prepared process and load the plug-in.

    po.map(initialize_process, xrange(process_count))

It is a line of. The reality is

def initialize_process(*args):
    load_plugins()


def load_plugins():

    default_plugins = [
        "ik2Bsolver.mll",
        "objExport.mll",
        "dgProfiler.mll",
        "DirectConnect.mll",
        "quatNodes.mll",
        "matrixNodes.mll",
        "ikSpringSolver.mll",
        "animImportExport.mll",
        ...
    ]

    def _l(name):
        try:
            # print "load plugin load: ", name
            cmds.loadPlugin(name)
        except:
            pass
            # print "pass plugin load: ", name

    for n in default_plugins:
        _l(n)

It looks like this. When you start mayapy, it will be born in a pure state, so it will load what you need. Here, only the plug-in is loaded, but let's describe it if necessary depending on the process such as module loading.

Define the id at the start of processing, the number of steps, and the end id, turn the loop, and execute parallel processing with po.map_async inside it. If you want to process a lot like this, you can just spin the gun as it is-that is, according to this code, if you do map_async (dump, range (start, end)) outside the while loop, you will die due to memory pressure. Therefore, after dividing the appropriate steps and proceeding to a certain level, res.wait () is inserted. Avoid running out of machine resources inexhaustibly. The optimum number of steps and ceil will vary depending on the situation and will require some trial and error.

Also, if you set process_count to the core of your machine, you can't do anything while it's running, so it's a good idea to allow some margin. It will take an hour to complete.

Get node information

here

# https://github.com/yamahigashi/maya-node-list/blob/gh-pages/tool/dump_maya_nodes.py#L43-L91
def dump_node_by_id(raw_id):
        id = om2.MTypeId(raw_id)
        nc = om2.MNodeClass(id)

        typ = om2.MFnDependencyNode()
        obj = typ.create(id, 'test')
        dpn = om2.MFnDependencyNode(obj)

        attributes = {}
        for num in xrange(ac):
            a = om2.MFnAttribute(dpn.attribute(num))
            k, v = inspect_attribute(dpn, a)
            attributes[k] = v

I'm going to create a node as and explore its attributes. See the code for ʻinspect_attribute ()`.

Export to rst

If you want to export something that is well-formatted, it is convenient to use some template engine. Here, I used Jinja2 (shrine = tempuru). Therefore, let's place the module where it can be seen from maya python. The attribute search result of the node is applied to the template and generated. https://raw.githubusercontent.com/yamahigashi/maya-node-list/gh-pages/source/_templates/node.tpl.rst The template looks like this.

Shpinx

Once you've got this far, all you have to do is run Sphinx. Run make html.

Caution If you do not have a sphinx project, create and set up a sphinx project before creating rst. http://sphinx-users.jp/gettingstarted/make_project.html

in conclusion

What did you think. It was a rush, but I have looked at the generation of maya's node list document. Each person reading this article wants to generate a node list! It is unlikely that something like that would happen, and if it did, something would be wrong in the world. However, it is often necessary to have information that is not documented, not just maya. I hope that the essence explained here will be of some help when you encounter such a situation. It didn't appear in this article, but in Python, the built-in function help () (also [appeared] in @ sporty's article (http://qiita.com/sporty/items/681aa8bbeac81c71c518). ), Dir () and ʻinspect` modules allow you to analyze existing code. In C #, reflection etc. can be used. The ability to find documents is also very important, but it will be helpful someday to keep in mind that there is such a way when that alone is not enough.


Recommended Posts

Make up for the lack of Maya Node reference
Introducing commands around the Maya reference
Examine the (hidden?) Options for Maya | commands
The third night of the loop with for
Pandas of the beginner, by the beginner, for the beginner [Python]
The second night of the loop with for
Make the default value of the argument immutable
The story of low learning costs for Python
Change the default reference repository for pip install
Watch out for the return value of __len__
Make a copy of the list in Python
Image processing? The story of starting Python for
Code for checking the operation of Python Matplotlib
Make progress of dd visible in the progress bar
[Note] The story of setting up the SDK for Python of Azure IoT Hub on Linux
The concept of reference in Python collapsed for a moment, so I experimented a little.