[MAYA] OOP Python/Maya Concept

Hi!

I’m very new to Maya/Py programming and I’m trying to understand some OOP concepts and how they would relate to a tool that I’m developing.

Design/Patterns
I want to represent real world objects in Maya. Those real world objects would be made up of other objects. I’ve been studying different design patterns and I think the “Composite” pattern would work well for that. So I would want all of the objects to inherit from a custom class CdbObject. So CdbComposite and CdbUnit for example would inherit from CdbObject, where CdbComposite is multiple CdbUnits.

Each CdbUnit (the leaf) would have it’s own set of attributes, as each CdbUnit would represent a different real world object that can “do” different things. A CdbComposite would then be a collection of those things with it’s own interface that would control the CdbUnits. I’m not sure how to implement that yet, I feel like I’ve glanced at some design patterns that would allow for this this. Decoration?

Somethings needs to control how each CdbUnit interacts with another as well. Each CdbUnit has a type of mount, namely male or female in most cases. I think the “mount” should be a class as well. CdbUnit would have a mount type and when is put in a CdbComposite with another CdbUnit they need to see if their mount types are compatible and then that would dictate how they would interact.

The whole idea is to define a set a universal CdbObject and then be able to introduce new types of CdbUnits or then CdbComposites to the system as time goes on. The mount class, once defined doesn’t really change but every CdbUnit needs to have one to define how it should interact with other CdbUnits.

I would then want to be able to store CdbObjects in an array or maybe a custom class array. Then add/remove, animate attributes. Save their states and load them back in.

CdbLayout (would be a collection of CdbObjects(CdbUnits/CdbComposites)
i would want to be able to call:
CdbLayout.add(CdbUnit)
CdbLayout.remote(cdbUnit)

Then be able to call:
CdbUnit.spin()
CdbUnit.pan()
CdbUnit.tilt()

And a CdbComposite would need to dynamically create and iterface that controlled all of the CdbUnit’s interfaces that are children of it.

Implementation
Up until now I’ve just had a library of .mb files that a script procedurally imports and renames and adds the name to a list. I then in Maya can select each “rig” in the viewport that has custom attributes that I can animate. The problem is when I want to combine different .mb into a new rig, I have to manually connect them.

I want to design a system where each .mb inherits from a master class. CdbObject. Then a “rig” is a CdbComposite that is a number of CdbObjects that controls the attributes of it’s children. I want to user to be able to select dynamically what .mb/CdbUnits/CdbObjects they want to combine and have the system correctly put them together and generate the UI and interface. The user would then interact with the “rig” CdbComposite through the new interface that was created.

I’m struggling conceptually of how to create the CdbObject base class, as I’m very new to the Python/PyMel/OpenMaya. I watched a video where the entire system was setup using MObjects (so Maya API) which seamed like a good way to start. What is the best way to associate a class with a .mb file?

class CdbObject():

def init(self, arg):
pass

def create(self, arg)
if arg = something:
#import file: something.mb

How do I link the imported Maya DAG nodes to the CdbObject class?

This post is all over the place, so I thank anyone for their time that has made it this far. I’m trying to understand the Maya frameworks that are available and learn how to apply OOP Patterns, which I’m also learning as I go.

Thank,

Matt

No problem with asking, that’s what we’re here for. This is a big topic and there’s a lot of stuff to consider. The basic idea of using objects to represent rig pieces and composing them into rigs is a good one, but the devil is definitely in the implementation details.

  1. Objects as “things” makes intuitive sense, but it’s important to try to get a clear understanding of what the “things” are. In most maya code, you’ve got a tricky relationship between the code object and the maya object to maintain: in some contexts, you can do something like just storing the string name of an object, in other cases you may need to do something more elaborate like use the API to get a handle to an object that survives renaming, etc.

  2. You can fudge the difference between properties and methods if that makes the code cleaner and easier to read. This is what PyMel does, for example. If you go that route, do it once and do it properly so you can rely on it and forget about it. Using Pymel is the easy way to get this ability but if pymel is too heavy you can do it on your own (the method is documented here)

  3. The easiest way to mess yourself up with OOP is by creating side effects. That is, if you initialize object A, but it changes the state of object B without any explicit action on your part, bugs are a likely result. This is a headache for OOP maya programming, because there are lots of ways that you can mess with the state of the scene that have unpredictable results for your object wrappers. I find it helpful to think of my objects as ‘managers’ or ‘interfaces’ instead of being scene objects themselves: it reminds me to write the code so that the objects don’t get too messed up when the user or another bit of code changes the scene.

In your example, having each object representing a maya file seems like an invitation to side effects, since you will be importing lots of objects with all sorts of odd edge cases (name collisions, new namespaces, unit settings and the like). Guard against that carefully!

  1. Don’t split the data! If you have data controlling the way your pieces get assembled, you want to be clear where it lives. For example, if you’ve got a rig file that represents an ‘arm’, the fact that its an arm should EITHER live in code OR in something like attributes on the objects in the scene. Using too much of a mix of both strategies is asking for trouble.

  2. Expect that your first pass will be too complex :slight_smile: The trick to designing these kinds of systems is finding the simplest, most minimalist solution and then expanding it later. 95% of all the clever things I’ve done in class and API design end up not getting used. Don’t try to solve problems you haven’t seen yet !

1 Like

You can’t automatically connect a DAG node to a Python object instance per se and have inheritance work the way you’re describing it, though you could probably use ScriptJobs to fake it more seamlessly than your current approach. Many scripts “link” to a Maya DAG node via naming. If you go this route, you don’t have a real linkage as you would with a real C++ style object pointer, and if the node name changes, you have problems. You can access object pointers via the OpenMaya API from Python. Take a look at maya.OpenMayaMPx. There are a few examples out there that might help you create a custom Maya node that has the attributes and behaviors you’re looking for. You’re looking for stuff like this. In other words, rather than create a separate Python object that ties to a Maya node, create a new Maya node that is accessible from Python/MEL/C++. The only drawback here is that you are now going to be creating scenes that aren’t compatible with vanilla copies of Maya. You will have to load your plugin/Python classes before loading the scenes that use them. Again, you’re creating new types of Maya nodes rather than Python objects if you take this approach. All of your node data would be in the form of Maya attributes, and you would access it as you would any other attribute on a Maya node. I suppose you could have different types of nodes definitions inherit from each other in Python using this approach. Note that if you know C++, you might want to look at creating a system like this as a Maya plugin…

I’d wait for a few more people to chime in before starting on any of this. There are some people on here who have far more experience with this kind of stuff than I have.

Theodox & btribble: thank you so much for the replies. All of those points are helping me figure out my approach. I need to finishing reading my Design Patterns book, but it’s a lot to take in.

Here is a link to the tool I’m working on:

Production Previs Tools
http://www.cinematographydb.com/production-previs-tools/


I’m a commercial cinematographer and a previs artist. My goal is to VERY accurately represent the camera rigs, grip, lighting, sets, and eventually lighting of a live action “Production” in Maya. I’ve already scale modeled a large amount of film equipment in Maya and I can say from on set experience that it matches up very well. Most of the “fucntion” is built directly into the Maya.MB files. A transform node has custom Attrs that control the geometry via SetDrivenKeys and Expressions where appropriate.

So the user imports the rig, grabs the custom transform/control and just animates those attrs. A global grp controls the pos/rot/scale/vis.

I need the script for automating connecting a “light” to a “light stand.” How objects connect and behave is dependent on their interface or mount type. Some only rotate(baby/junior pins), some slide (gobohead/arm)(clamp/pole), etc. i want to build a logic system that automatically generates the custom control rig with the appropriate interface based on the mount type.

Do I have to implement the mount type as a class? Or can I just use a dict that stores the type of mount and what to do based on type?

I already use this WIP system every day to prepare for my commercials, but I need a way of taming the eventually 100s of different pieces of equipment I’ll have available. This will be useful for live action directors/DPs/Gaffers/Grips, previs/layout/virtual cinematographers, and hopefully eventually the virtual production world.

Writing the managing classes/scripts in Python/MEL procedurally in Maya would 100% work. But I can see that down the road updating and maintaining this without proper design patterns and well though tout classes will be a lot of work.

I want to seamlessly be able to add a new piece of equipment and have it “behave” properly in the system for free.

I do know C++ but I really like the speed of developing in Python. My script won’t be big manipulating geometry sets, deformers, rending, etc. It will be be managing states of objects and maintaing order/logic. So the performance hit is fine, especially as computers are getting insanely fast.

I’ve been researching Pymel and PySide/QT quite a bit. Pymel seams like a great framework but I’m worried about relying on it as I move forward. It’s not Pythonic but maya.cmds is really simple to use, although I get why Pymel exists. As a single developer, does.
Pymel make you life easier as far as managing a growing/evolving tool?

My hacky approach now just relies on the script explicitly renaming the models as they come in and storing the names in a list. If the names change it breaks for sure.

To have the interface be told we are interacting with something in the viewport I need to use the API / plugs right?

Since you want the separate parts to snap together, why can’t you just create external references to the parts in question and use regular Maya parenting to attach two components together? You don’t need this connection to have any special behaviors since things like pan/tilt would be built into nodes in the “tripod”. What am I missing? What gets connected between two parts besides that “physical” attachment?

EDIT: BTW, the parts themselves can externally reference subparts from other Maya scenes (inheritance). Once in a while multiple levels of referencing can cause hiccups, but this is mostly a non-issue so long as you are careful to use namespaces cleanly when you make the reference. Keep your namespaces short if you expect to use multiple levels of nameapacing. If you do this, you can make a change to a core piece of the “equipment”, and this will automatically propagate through the chain.

Let me see if I understand this correctly. If I get it, it seems like you have 2 parts to worry about:

  1. What amounts to a database of saved assets with different names, roles, and affordances: you want to import tripod X and pan head Y and camera Z, using a UI that knows all the things a user will care about

  2. A method for assembling a finished set out of these pieces, including I suppose snapping pieces together

The first problem is a nice clean programming problem that you can handle with a fairly simple set of information: you need to essentially design and query a database that maps maya files onto the info that users care about, and then provide a UI to let them browse/select the pieces. The result of (1) is a list of maya files mapped onto a set of roles: this maya file is the light stand, this other one is the light itself, and so on.

The second one is more like an animation rigging system: you want to import components from multiple files and then snap them together to make more complex systems.

Do I have that right?

Hey!

Thanks again for the comments and questions. I think that I was over complicating things a bit and trying to re-write the native Maya constraints like parenting/orient/etc.

I was planning on doing something with custom nodes/API but I’m realizing that to start I can keep it simple and have the script select the stand, select the light, and then just parent the light to the stand(mount_locator).

Then I’ll have the script read all of the “custom attributes” I’ve added to the stand/lights and have them linked into a custom control.

Talk soon,

Matt