Transferring information (like colour) between particles

Posted 23 February, 2013 Anthony Tan (staring at yet another render. But still loving it for some reason..)

« previous | next »

tags: maya, particles

Next time someone says you can't transfer particle attributes in Maya without any fancy-schmancy plugins or custom code, tell em 'feh'.

A mate of mine, Joao, mentioned offhandedly that he had something he wanted to play with and that he was having trouble in Maya transferring data between particles (in this case, colour) for a shot involving colliding nParticles. Clearly, I can't leave well enough alone, which leads us to this:

In maya, there's not an obvious way to transfer data between particles, esp not within the same nParticle group since the self-collision event doesn't really trigger anything (contrasting to say, Houdini where you can do all sorts of weirdness with your particles). The video above though shows that it's not impossible though you just have to be a bit sneaky, and take advantage of what's accessible - the force subsystem.

To recap (and summarise)

So just to recap: the challenge is to have particles somehow communicate between each other, and to update themselves based on some kind of input - here, we're going with the easily visualised colour.

For the impatient, what the solution involves here is conceptualising the colour attribute on each particle as a force, with the max dist setting the radius of influence. Imagine that each and every particle is broadcasting information (the force), which is received by other particles who can then in turn decide what to do with the broadcast data during the dynamics step.

setup

For today's demo, I've got a line of particles sketched out, spacing roughly 4 units and they shouldn't move, or jiggle or well, do anything. You can apply other forces later if you'd like, but it's worth testing all of this on a simple static system as you'll see. Here's our baseline so we're working off the same page since it can be a bit fiddly: a line of dots, spaced about 4 world units apartbaseline_scene.ma

Core mechanics - defining 'colour' as force

I'm going to use a simple uniform force as my template, set to emit from the particle shape. Key settings are max dist to be 5, attenuation at zero, and emit per vertex. The name of the force must be rgbForce for this demo.

To control this force, on the particleshape, add in two new attribs - rgbForce_magnitude (float, PP), and rgbForce_direction (vector, PP). These will override the globals defined on the uniform force.

Finally, in the EE, hop into the creation slot for the particle shape, and set some initial conditions. I'd suggest something like setting the rgbForce_direction vector to be [particleId % 2, 1, particleId] at this stage for debugging purposes (red becomes a toggle, green is a static 1, and blue is the particle Id).

Set the rgbForce_magnitude to be mag(rgbForce_direction).

This step is important because somewhere internally in the force, direction becomes normalised, so if you tried to store an RGB triplet of 1, 1, 1 on the direction vector, you'd be reading out 0.577,0.577,0.577 and have no way to tell if you really meant white, mid grey, or anything else with the same ratio of RGB

Righto, now that's set up, you should be able to query one of the inputForce slots and work out what's affecting this particle. Which inputForce? Well, if you're using my template file, inputForce[3] (check your hypergraph to be sure). There's no guaranteed mapping and it bounces around each time you disconnect and reconnect in the DR ed.

Just to verify that things are working, in your runtime before dynamics slot, you can drop some handy printfs to check. Again, suggestion is to do something like this:

int $probeParticle;
$probeParticle = 0;
if (particleId == $probeParticle){
    print("PID[" + $probeParticle + "]:" + inputForce[1] + "\n");
    }

To verify, if you've got things set up right you should be able to play with the max dist value. 5 should capture one particle, and so your report for inputForce will be 1 2 1. 10 should capture two, and the report will be 1 3 3, etc etc.

Note that you'll always be getting your particle's own value of this field in the data. Again, to check that, keep max dist at zero, and update $probeParticle from 0 to say, 12. The output should be 0 1 12, with the last digit referencing the particle ID (this is why the very particular initial state for debugging).

It's also a strict sum (which is all you're ever going to get, unfortunately) so if you want a neighborhood count, you'll need to add in a second force in the same vein (since we don't change this per particle though, no need to add PP attributes for control).

This is really the core of the system, if you can follow things up to here, ideally there should've been a lightbulb moment and you're now happily plotting out all sorts of crazy intra-particle weirdness. But wait! There's cleanup..

Here's the step 1 file incase you wanted a live example: step1.ma

Counteracting the force

By now you should've seen particles drifting all over the shop, since we're applying forces that will add energy to the system (even though we want it to represent colour, it's still a force), so you should either add in another pair of forces that are equal and opposite to the ones we've added, or write in code to counteract.

If you go the code route, then don't forget to take into account of mass and timestep (read: oversampling) since you'll be applying a delta to the acceleration slot. For prototyping, code is quick, but if you're comfortable with the wiring, then it may be worth going with a counter-force even though it's messier, it might pay off down the track if you have multiple particle systems since you can use the standard DR to link them in and have the same counteracting force effects.

More files: step2-antiforces.ma

Putting it together

Okay, so those are all the rough baseline building blocks, so if you understood those, you should have no trouble with the attached .ma here since now we're back in normal code territory where you just decide what you want to happen with the broadcast data.

Dive into the EE and there's comments but the result should be that each rewind will give all the particles a random colour, and when you hit play, each particle in a radius of 6 will try impose its colour force. You can see regions of colour developing, and logically if you let this run for infinity you'll get the average RGB value for all points in the system. Increasing the max dist will speed up convergence since that's effectively increasing the distance at which a point is sending information out.

More files: step3-dots.ma

Where to now?

Essentially what I'm describing here is a very simple intra-particle communication and/or sampling system, you could adapt it so that say, you have a sphere of particles, and those particles within a certain radius of each other light up, or trigger collision events, or emit particles, or well, stuff.

There's a couple of things that you'd want to invest the time into if you were going to use this in anger however. Top of the list: scripting to avoid having to know which inputforce you're looking for - the fact it changes on disconnect and reconnection makes this one helluva unfriendly artist tool...

Also, note that this is a push-type system, not pull. Wha? Well, each particle can't set it's own radius of interest, it relies on being hit by a field. Subtly, this means that you have to take a whole different approach. Your particles are responding to forces imposed on them, rather than being able to go out and query their neighbors (so if you used this technique for flocking you'd be going mad..)

The sphereball video

The sphereball demo video is just a further demo of the proof of concept. In this case, we have an emitter putting out particles in a completely unrelated particle shape, which then transfers colour data to the receptor ball of jiggling things. I've also set it to rotate so it's a bit clearer that the colours are persistent. And because it looks more interesting in motion. So yes, relatively simple all up, once you sort of wrap your head around it, but if something I've said is wrong or completely confusing email me, or ping me on twitter and I'll double check. It's late and I'm sure I'm not guaranteed coherent at 3am.

 
previous
The difference between .getValue and .toScript for Nuke knobs
next
Conceptualising a 3x3 (with houdini)
tags: maya, particles