Shuffling MASH Points with the Python node
Say you want to create the above animation of random spokes moving about; to do this you’ll need to shuffle the MASH points, read on to find out why, and how.
Let’s start with a grid distribution:
As you can see, when MASH creates a grid distribution, all the points are in an order (0, 1, 2, 3, 4 across the top here). I’ve used the Points node to visualise the numbers here.
If we add a Trails node to create some lines between a single point and say, 30 MASH points, it will connect to the first 30 points. See below.
This is obviously not what we’re after so we need to add a Python node to shuffle our MASH points and put them into a random order. This means that even though the first 30 points are connected, they’re all in a random order.
You can copy and paste the below into a Python node. It will shuffle all the points in any MASH network.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import openMASH import random #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() #create a list of ids idlist = [] for i in range(count): idlist.append(i) #variable for seed, you'll see why in a moment seed = 0 #set a seed random.seed(seed) #shuffle the ids random.shuffle(idlist) for i in range(count): #get shuffled ids md.outPosition[i] = md.position[int(idlist[i])] #tell MASH to write the network data md.setData() |
As you can see, our ids are now shuffled.
You can animate this by ’rounding’ the seed. In this example, every 10 frames we change the seed (it’s rounded up in 10s). I’ve commented out a version that will change the seed every 20 frames so you can see how it works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import openMASH import random #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() #create a list of ids idlist = [] for i in range(count): idlist.append(i) seed = 0 #change the seed every 10 frames seed = (frame + 9) // 10 * 10 #change the seed every 20 frames. #seed = (frame + 19) // 20 * 20 #set a seed random.seed(seed) #shuffle the ids random.shuffle(idlist) for i in range(count): #get shuffled ids md.outPosition[i] = md.position[int(idlist[i])] #tell MASH to write the network data md.setData() |
So there are actually 2 MASH networks here. The first one just has a grid of little dots. The second one is more interesting; the Instancer is empty, but it has the same grid in the Distribute node as the first network. The second network is the one with the Python and Trails nodes.
The reason there are two different networks is because in the animation the Trails wander about but the grid stays still. So, on the network with the Trails on it, as you’ve probably guessed, I added a Signal node to make the trails animate about.
The finishing touch was adding an Offset node and using the Low Clamp and High Clamp settings to clip the point positions and keep them inside the grid. Before and after below:
On the left are the clamp settings.
On the right is how the MASH Editor looks when we’re finished (ignore the Id node!).
Multiple looping animations with the Instancer
The Time node in MASH is really useful for creating looping or offset animations inherited from an input model. Check out this tutorial for more on that.
The problem is that the Time node is only available when MASH is creating an output mesh via the Repro node (this is MASH’s default mode). This mode can be impractical if you want to create thousands high polygon objects all with looping input animations. So, how do you do this if you’re using the Instancer with MASH?
If you’ve only got one model, the answer is simple, id cycling.
The Id node in MASH can do id cycling which is really useful for looping animations where each frame of the animation is a separate model on the Instancer (you set this up by creating an Animation Snapshot of your model). This is an age old technique that will be familiar to anyone who’s used the Particle Instancer with Maya’s nParticles.
However, what if you’ve got multiple models with different loop lengths (like different models of people cheering in a crowd). The answer here, ladies and gentleman, as with everything else so far on this blog, is the Python node which you would use instead of the Id node. The script is pretty short, take a look:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import openMASH import random #three animations on the instancer, here are their start ids and end ids #the animations do not have to be the same length animationStarts = [0, 30, 60] animationEnds = [29, 59, 89] #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() #change the id based on the frame number for i in range(count): random.seed(i) #which animation shall we use whichAnim = random.randint(0,len(animationStarts)-1) #how long is this animation animationLength = animationEnds[whichAnim]-animationStarts[whichAnim] #create a random start point for the animation startpoint = random.randint(0,animationLength) #which frame in this sequence are we frameInSequence = (startpoint+frame)%animationLength #offset to the correct animation sequence md.outId[i] = frameInSequence+animationStarts[whichAnim] #tell MASH to write the network data md.setData() |
Getting Particle Positions with the MASH Python node
If for some reason you don’t want to plug your particle system directly into your MASH network you can get particle positions via the Python node like this.
You’ll need to edit the name of the particle system in the Python script, but other then that, you can just copy and paste this script into the Python node in order to use it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import openMASH #initialise the MASH network data md = openMASH.MASHData(thisNode) #storage for the particle positions ppositions = [] try: #this will fail if the particle count is zero ppositions = cmds.getAttr('nParticleShape1.worldPosition') md.setPointCount(len(ppositions)) except: md.setPointCount(0) #and this gets the number of objects in the network count = md.count() #set the MASH position to the particle position for i in range(count): md.outPosition[i].x=ppositions[i][0] md.outPosition[i].y=ppositions[i][1] md.outPosition[i].z=ppositions[i][2] #tell MASH to write the network data md.setData() |
Strange Attractors with MASH and Python
Here’s a quick and dirty implementation of a couple of strange attractors in MASH using the Python node. To use them simply copy and paste the Python into the Python node and click run (top right of the Python Editor).
I used the Trails node in Join the Dots mode to create the tube between all the points (I duplicated it, then got rid of the trails node, and smoothed the mesh). Make sure to have a zeroed distribution on the Distribute node and a few thousand points.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import openMASH #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() a = .9 b = 5 c = 10 d = 1 dt = 0.003 #delta for i in range(count): x = md.position[i].x y = md.position[i].y z = md.position[i].z if i > 0: x += md.position[i-1].x y += md.position[i-1].y z += md.position[i-1].z x += (-a*x + y*y - z*z + a*c) * dt y += (x*(y - b*z) + d) * dt z += (-z + x*(b*y + z)) * dt md.outPosition[i].x=x md.outPosition[i].y=y md.outPosition[i].z=z #tell MASH to write the network data md.setData() |

This one is a Lorenz System / Attractor. Check out this fantastic Behance page for some inspiration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import openMASH #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() h = 0.01 sigma = 10.0 rho = 28.0 beta = 8.0 / 3.0 x0 = 0.1 y0 = 0.0 z0 = 0.0 for i in range(count): x1 = x0 + h * sigma * (y0 - x0) y1 = y0 + h * (x0 * (rho - z0) - y0) z1 = z0 + h * (x0 * y0 - beta * z0) x0 = x1 y0 = y1 z0 = z1 md.outPosition[i].x=x0 md.outPosition[i].y=y0 md.outPosition[i].z=z0 #tell MASH to write the network data md.setData() |

Random 90 Degree rotations in MASH

Add random 90 degree rotations to all MASH objects. To use the code, simply copy and paste it into the Python node.
The below variation will give you random Y rotation, you can use the same idea to adjust the X and Z rotations as well if you need to.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import openMASH import random #initialise the MASH network data md = openMASH.MASHData(thisNode) #this is how to get the frame number frame = md.getFrame() #and this gets the number of objects in the network count = md.count() random.seed(0) #add the index to the Y position for i in range(count): multiplier = random.randint(0,6) rot = 90*multiplier md.outRotation[i].y=rot #tell MASH to write the network data md.setData() |
Maya Tip: In View Messages
Maya 2014 added some helpful in-view messages to aid users, here’s an example of how they can be used:
The built in messages are almost universally useless for professionals, however, if you’re a tool developer, you can make your own messages by using the inViewMessage command in MEL of Python.
MEL example from the Manual:
1 |
inViewMessage -smg "test message" -pos topRight -bkc 0x00000000 -fade; |
Python:
1 2 |
import maya.cmds as cmds cmds.inViewMessage( amg='In-view message <hl>test</hl>.', pos='midCenter', fade=True ) |
So, if you try them you’ll notice that the Python one looks much nicer, this is because the MEL one has a black background set, and the Python one uses this cool tag which highlights text in yellow.
Alongside this tag you can also use HTML to format your messages, this is extremely useful.
Some of the HTML tags that work are:
<em> – Italics
<hl> – Highlight (not HTML, but it works)
<small> – Small
<i> – Italics
<sub> – Subscript
<sup> – Superscript
<blockquote> – Indented Quote
<h1> – Large heading
<h2> – Medium heading
<h3> – Small heading
<br> – Line break
<p> – Paragraph
<span> – Allows you to set the font colour and size amongst other things.
Dont forget to close your tags like this </tag>
In my opinion these messages should replace a great many calls to ‘print’, ‘error’ and ‘warning’ in the command line.
This example in MEL creates the messages from the top image:
1 2 3 |
inViewMessage -amg ("<span style=\"color:#82C99A;\">Info:</span> Some info here.") -dragKill -pos midCenterTop -fade; inViewMessage -amg ("<span style=\"color:#F4FA58;\">Warning:</span> Some warning here.") -dragKill -pos midCenter -fade; inViewMessage -amg ("<span style=\"color:#F05A5A;\">Error:</span> Some error here.") -dragKill -pos midCenterBot -fade; |
MASH GIF
Maya Tip: Select faces based on a map
I discovered this by accident today and it’s a real treat of a time saver.
To select components based on a map simply do the following:
1. Double click on the Pain Selection Tool.
2. Scroll down to Attribute Maps and roll it out.
3. Open the Import roll out.
4. Click Import… and select a map.
Done!
A major time saver as I’m sure you’ll agree


