Mel Script - Using Nodes for Structured Data Storage

 

 

 

In C, C++ and Java you have the concept of a structure, i.e. a way of collecting together related data in a single package. For example, in C++ you would be able to write :

 

   // declare a new data type to hold a vector
   struct Vector {
       float x;
       float y;
       float z;
   };
   
   // create a variable called V, of 
   // type Vector
   Vector v;
   
   // set it's attributes...
   v.x = 0;
   v.y = 10;
   v.z = 0;	

 

Structures allow our code to take on a much more organised approach to data storage. By grouping together attributes your eventual programs become simpler, ie storing an array of objects rather than seperate arrays for all the components.

One of the biggest drawbacks of mel scripting is the inability to use any structures within mel. This does actually make our lives somewhat difficult :(

In effect we need to find some way of creating some form of structured storage. The answer it turns out, is fairly obvious. Maya has a rather nice scenegraph capable of storing structured objects on which we can dynamically add our our custom attributes via script.

The other plus points as far as we are concerned are that we also get persistant data storage, ie - the data we store in a node will be saved into and loaded from maya binary files. We also get a handy gui of the data for free since all extra attributes can be viewed in the attribute editor and channel box.

 

 

 

 

Step 1 : Creating a structure for us to use

The simplest possible node available to us, is an empty group. For our script we can simply ask that if the node "myScriptNode" doesn't exist, create an empty group (aka. null) and name it "myScriptNode".

 

 


		// check to see if "myScriptNode" exists.
		// if it doesn't, then create an empty group
		// so that the node does exist
		if( !`objExists "myScriptNode"` ) {
			group -empty -name "myScriptNode";
		}

 

 

 

 

Step 2 : Adding Some attributes

We can use the AddAttr command to add our own custom attributes to our node. The following code example demonstrates some of the simplest attribute types to add onto our node. The attribute's value can now be changed in the Attribute editor, or via setAttr.

 

 

		// check to see if "myScriptNode" exists.
		// if it doesn't, then create an empty group
		// so that the node does exist
		if( !`objExists "myScriptNode"` ) {
			// create an empty group called "myScriptNode"
			group -empty -name "myScriptNode";

			//---------------------------------------- Add Attributes

			// add a float attribute
			addAttr -ln "floatAttr" -sn "fa" -at "float";
			
			// add a double attribute
			addAttr -ln "doubleAttr" -sn "da" -at "double";
			
			// add an int attribute
			addAttr -ln "intAttr" -sn "ia" -at "long";
			
			// add a boolean attribute
			addAttr -ln "boolAttr" -sn "ba" -at "bool";
			
			// add a string attribute
			addAttr -ln "stringAttr" -sn "sa" -dt "string";

			//---------------------------------------- Set Initial Values
			setAttr "myScriptNode.fa" 0.0;
			setAttr "myScriptNode.da" 0.0;
			setAttr "myScriptNode.ia" 0;
			setAttr "myScriptNode.ba" true;
			setAttr "myScriptNode.sa" -type "string" "hello";

		}

 

 

 

Step 3 : Retrieving Attribute Values

As we saw previously, you can use setAttr to set the value of the attributes at any time. We may also need to retrieve those values, to do that we can simply use getAttr.

 

 

 


		// check to see if "myScriptNode" exists.
		if( !`objExists "myScriptNode"` ) {

			// Get Values from our node
			$fa = `getAttr "myScriptNode.fa"`;
			$da = `getAttr "myScriptNode.da"`;
			$ia = `getAttr "myScriptNode.ia"`;
			$ba = `getAttr "myScriptNode.ba"`;
			$sa = `getAttr "myScriptNode.sa"`;

			// print values
			print( "fa= " + $fa + "\n" +
			       "da= " + $da + "\n" +
				   "ia= " + $ia + "\n" +
				   "ba= " + $ba + "\n" +
				   "sa= " + $sa + "\n" );
		}

 

 

 

Step 4 : Making Attributes Appear in the Channel Box

One of the problems we currently have is that our attributes do not appear within the channel box :(

The answer to this is straight-forward. The channel box holds all keyable attributes of the node. It is there as a handy way to set values whilst animating. The Attribute Editor holds All attributes on the node.

The answer then is to make the attributes keyable when we add them to the node. To do this we simply use the -keyable flag for addAttr. This will make all attributes appear in the channels box (Apart from strings because Maya doesn't know how to interpolate them !!).

 

 


		// check to see if "myScriptNode" exists.
		// if it doesn't, then create an empty group
		// so that the node does exist
		if( !`objExists "myScriptNode"` ) {
			// create an empty group called "myScriptNode"
			group -empty -name "myScriptNode";

			//---------------------------------------- Add Attributes

			// add a float attribute
			addAttr -ln "floatAttr" -sn "fa" -at "float" -keyable true;
			
			// add a double attribute
			addAttr -ln "doubleAttr" -sn "da" -at "double" -keyable true;
			
			// add an int attribute
			addAttr -ln "intAttr" -sn "ia" -at "long" -keyable true;
			
			// add a boolean attribute
			addAttr -ln "boolAttr" -sn "ba" -at "bool" -keyable true;
			
			// add a string attribute
			addAttr -ln "stringAttr" -sn "sa" -dt "string" -keyable true;

			//---------------------------------------- Set Initial Values
			setAttr "myScriptNode.fa" 0.0;
			setAttr "myScriptNode.da" 0.0;
			setAttr "myScriptNode.ia" 0;
			setAttr "myScriptNode.ba" true;
			setAttr "myScriptNode.sa" -type "string" "hello";

		}