View Full Version : Maya "optimizing" my Arrays

03 March 2008, 06:54 PM
Hi, I have a custom node with a few array attributes. Now I noticed that on one array input attribute that is not connected, maya will "erase" some indices that have 0 as value when I save and reload my scene. For example, when saving the array looks like this:
node.attribute[0] 0
node.attribute[1] 0
node.attribute[2] 1
node.attribute[3] 2
After reloading the scene the array will look like this:
node.attribute[2] 1
node.attribute[3] 2
So, is this some sort of optimization or what? I would like to have the 0 array elements, too. Can I do that by altering my plug configuration (I also tried the indexMatters option but that didn`t hep either) or should I connect it to soemthing else, so that this info is not lost?
Thanks in advance

03 March 2008, 07:54 PM
Maya is using the sparse array structure for array plugs. So essentially it optimizes out the elements that are 0, but you still have the ability to read/write them. Maya will automatically resize and create new elements when the values aren't zero anymore. Hence the 2 methods in MPlug, where you can get plugs of the array by either logical (sparse) or physical indexes.

03 March 2008, 08:33 PM
Hey Henry, thanks for the info. When I try to get the value from this non-existing plug, I get some odd value. So to make this reliable I should probably call an ArrayBuilder that recreates my precious 0 value arrays after file load, right?

03 March 2008, 10:06 PM
Upon file reload I check the array and if there is an MS::kInvalidParamater (which means there is no element at the given index) I add an element there with an MArrayDataBuilder. Works so far...

03 March 2008, 11:07 PM
How are you reading the values from the array plug after opening the scene?

03 March 2008, 11:34 PM
MArrayDataHandle and then I use jumpToElement to get a certain index`s status

07 July 2008, 06:27 PM
Had to deal with this as well lately. Thing is Maya is using sparse array representation to store values. Means that if the element stored is 0, Maya will not store it.

Instead it stores some kind of binary search table, {index, value} pairs from which it can then rebuild the initial array.

So for the array

{0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0}

Maya would actually store:

Values: {1, 2, 3}
Indexes: {2, 3, 5}

So what you do is traverse the non-zero elements by traversing the array handle. You should compare the elementIndex of current item, compare it to your counter and if they are equal take the value stored in the handle and advanced to next element.
Else the element is not in the sparse table, which means its value is 0.

I am not aware of any automatic convenience method in API to straight-forward traverse the array. If anyone has experience with that please share :)


07 July 2008, 03:49 PM
Well, first off, the reason Maya is not writing those out is that Maya will not write out plugs that have default values. They are redundant setAttr calls. This is used to optimize file load time. Calling setAttr n.x 0 , where n.x's default value is 0 is unnecessary bloat.

Since plugs are not instantiated until actually set/retrieved, on save and reload you have the appearance of losing plugs.

You have a few options here. Assuming you require your array attribute to always have contiguous data:

1. For in-between indices, you can add the elements via MArrayDataBuilder. You'll probably want some other attribute to store the total number of elements that this array should contain in case there are trailing elements with default values.

2. For in-between indices, you can simply assume the default value. Unless there is a specific need to instantiate the plug, then just assume it since that is what the plug would effectively store once you query it.

3. Remember that MPlug::getElementByLogicalIndex will instantiate a given plug index as well. Although it's badform to be calling this during a compute() and instead you should rely on MArrayDataBuilder during compute(). So getElementByLogicalIndex is useful if you want to create those plugs outside of the compute().

This is more or less what you've guys have already noted. I just thought I'd add some extra context.

07 July 2008, 04:33 PM
the only thing I have to add is that I have a variable that stores if the arrayBuilder has been used to create all the sparse array elements. So after a file load this creates all the elements in the first compute cycle and than only if the number of elements changes.

CGTalk Moderation
07 July 2008, 04:33 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.