Tuesday, 3 January 2012

Maya Strands*

*OK, not exactly the same as Softimage ICE strands (which are great, by the way), but here is a way to get a very basic approximation.

I am basically taking Sigillarium's particle expression for making a uniform trail of particles and adding a line to take the seed particle's colour attribute and passing it to the emit command. This way, the trails have the same colour as the emitter particle, which is very handy if you are emitting from a surface and inheriting particle colour from that surface.

Here is the expression:

//runtime before dynamics

seed_particleShape.beforePosition = seed_particleShape.position;



//runtime after dynamics

string $trail_pt = "smoke_nParticle";

float $separ = seed_particleShape.separation;

vector $lastPos = seed_particleShape.beforePosition;

vector $pos = seed_particleShape.position;

vector $move = <<(($pos.x)-($lastPos.x)), (($pos.y)-($lastPos.y)), (($pos.z)-($lastPos.z))>>;


//get colour info

vector $rgb=seed_particleShape.rgbPP;

float $r=$rgb.r;

float $g=$rgb.g;

float $b=$rgb.b;


//get number of particles to emit per frame

int $num = ceil( mag( $move ) / $separ );


//loop !

if( $num != 0 ) {

vector $step = $move / $num;

for( $i = 1; $i <= $num; $i++ ) {

vector $newPos = $lastPos + $step*$i;

float $life = time - (1.0/25/$num * ($num-$i));

emit -o $trail_pt -pos ($newPos.x) ($newPos.y) ($newPos.z) -at rgbPP -vv ($r) ($g) ($b) -at "birthTime" -fv $life;

}

}



There are a couple of things to note:


The seed particle shape node has an extra attribute added - separation. This is a float value that determines the distance between each particle in the trail. The number you use depends on the scale of the scene and velocity of the seed particle. It's handy to have this variable on the shape node rather than in the expression.


There is a per-particle vector attribute called beforePosition, which stores a particle's position from the previous frame. This attribute needs to be created using the Add Attribute dialogue:





Also, note the variable $trail_pt in the expression. This is just the name of the trail particle object. Create this object before running the expression either by a 'particle' or 'nParticle' MEL command or by creating an emitter via the menus and deleting the emitter and leaving the particle object behind. Set the $trail_pt variable to the name of your trail particle object.






So, you can hopefully see that I have an image on a plane from which I am emitting some particles which are taking the colour from the plane. Those particles are then emitting more particles in a trail and inheriting the colour from the first particles.

Thanks to Sigillarium for the excellent expression. Please check the Sigillarium blog as it is outstanding and very clearly explains some difficult concepts.

Tuesday, 29 November 2011

Motion Vectors for hardware particles

I am trying to write an expression which will mimic the mv2DToxik motion vectors, but for hardware particles. Therefore removing the need to instance some geo to get the motion vectors to render.

I have not got very far before I came across some vector maths...


Here is the setup which works for a camera pointing exactly down the z-axis.







Here is the render loaded into Nuke. Notice the RGB values.



I now need to find a way to convert World Velocity to Screen Space Velocity.
In a MEL expression. Hmmm, time to ask the Forum

After some great advice from Zoharl, I grabbed some code which uses the camera's worldInverseMatrix to transform the velocity vector.

Here is the expression:

//multiplier
float $mult=0.5;

//get the particle's World Space velocity
vector $vel=particleShape1.worldVelocity;
float $xVel=$vel.x;
float $yVel=$vel.y;
float $zVel=$vel.z;

// create particle's velocity matrix which is in World Space
matrix $WSvel[1][4]=<<$xVel,$yVel,$zVel,1>>;

// get the camera's World Inverse Matrix
float $v[]=`getAttr camera1.worldInverseMatrix`;
matrix $camWIM[4][4]=<< $v[ 0], $v[ 1], $v[ 2], $v[ 3]; $v[ 4], $v[ 5], $v[ 6], $v[ 7]; $v[ 8], $v[ 9], $v[10], $v[11]; $v[12], $v[13], $v[14], $v[15] >>;

//multiply particle's velocity matrix by the camera's World Inverse Matrix to get the velocity in Screen Space
matrix $SSvel[1][4]=$WSvel * $camWIM;

vector $result = <<$SSvel[0][0],$SSvel[0][1],$SSvel[0][2]>>;
float $xResult = $mult * $result.x;
float $yResult = $mult * $result.y;
float $zResult = $mult * $result.z;

//rgbPP
particleShape1.rgbPP=<<$xResult,$yResult,0>>;


So far it seems to be working, but I will try to test it and see if it breaks down.





Thanks to Zoharl on the CGTalk forum and to xyz2.net and 185vfx who came up with the original matrix manipulation code.

Thursday, 10 November 2011

Emit particles upon the death of another particle

In Maya it is relatively easy to emit particles when another particle collides with an object, but to emit a particle when another particle dies required a different procedure, and... an expression !
I wanted to use this little trick today so I will show how it is done:

The effect I wanted to create was for a load of small zingy trails roughly following a path. There a many ways to create this, here is how I did it:

1 create a path

2 create a emitter for some particles that will die quickly but randomly and emit particles upon their death. Those emitted particles will themselves emit a trail of streaky particles.

so we have three particle objects: death_particles, birth_particles, trail_particles. The death_particles will die and give birth to the birth_particles, which will then emit the trail_particles. Still with me ? Then let's do it !

3 give death_particle a lifespanPP

4 create a particle object using either the particle MEL command or by using the Create Emitter command from the menus and then deleting the emitter but keeping the particle object. Rename the particle object to 'birth'

5 Now we need to make the runtime expression. here it is, I will explain it afterwards:

//
// emit upon death
//

if (death_particleShape.age >= death_particleShape.lifespanPP) {

vector $pos = death_particleShape.position;

vector $vel = death_particleShape.velocity;

float $randVelMag=10;

float $randPosMag=1;

float $velMult=0.1;

float $emitNum = rand(1,3);

for ($i=0; $i<$emitNum; $i++) {

vector $randVel = <<$randVelMag*rand(-1,1),$randVelMag*rand(-1,1),$randVelMag*rand(-1,1)>>;

vector $randPos = <<$randPosMag*rand(-1,1),$randPosMag*rand(-1,1),$randPosMag*rand(-1,1)>>;

vector $newVel=<<($velMult*(($randVel.x)+($vel.x))),($velMult*(($randVel.y)+($vel.y))),($velMult*(($randVel.z)+($vel.z)))>>;

emit -o birth -position (($randPos.x)+($pos.x)) (($randPos.y)+($pos.y)) (($randPos.z)+($pos.z)) -at velocity -vv ($newVel.x) ($newVel.y) ($newVel.z);

};

};


basically it is an EMIT command with some randomness added to the position and velocity parameters.


$randVelMag is a multiplier for the randomness in the velocity of the birth_particle when it is emitted

$randPosMag is a multiplier for the emitted position of the birth_particle

$velMult is another multiplier of the velocity, just so I can go in and change one parameter and all the velocity vectors are affected.
$emitNum is how many birth_particles are created each time a death_particle dies







I then applied some turbulence fields to the birth_particles to get them to wiggle a bit and tweaked the conserve on them and the trail_particles. Here is a rendered frame.




Thursday, 27 October 2011

Rendering a refraction UV pass for water droplets



I've been working on a shot with a swimming pool and some splashes and water droplets. There was no light probe so I needed to replicate the lighting and refraction within the droplets.
I used the UV pass method with Nuke's STmap node- here's how:

1. Once you have your droplets simulated and you are ready to render, assign your particles as Blobby Surface (s/w) type.

2. Create a Blinn shader with 100% transparency, switch on refractions in the raytrace options and assign that shader to your particle object.





3. create a poly plane that fills the frame and is behind the particles (i.e. you can see the particles in front of the place when looking through your camera). rename the plane to UVplane. In the UVplane's render options, set the primary visibility to be off but make sure it is visible in refractions.



4. create a surface shader and assign it to the UVplane

5. create a sampler info node and make the following connections:

samplerInfo.vCoord -> surfaceShader.outColorG

samplerInfo.uCoord -> surfaceShader.outColorR


6. Render.


7. In Nuke, get a STMap node and plug in the background plate into the src pipe and your render into the stmap pipe



You will see a refracted background in your droplets and you can composite this how you like.


In this example, you can see the original plate with the swimming pool and the person in the pool refracted through the water droplets (just...).

Thursday, 6 October 2011

SOuP shatter recipe

This is not strictly a particle effect tip, but particles are involved in a way.

I will simply outline the steps involved in creating a shatter effect using Peter Shipkov's most excellent SOuP plugin suite for Maya. I recommend all Maya users to install SOuP and learn how to use it. I am also referring to Jostein Finnekasa's excellent tutorial on Vimeo.

The purpose of this post is simply to write down all the steps that have already been outlined by Peter and Jostein, so that I can remember them!

Here are my notes on how to set up the shatter effect:

1. Drag any poly object's shape node from the Outliner to the Hypershade

2. Create a Scatter node from the SOuP shelf

3. Create a Shatter node from the SOuP shelf

4. Connect:

polyShape.worldMesh -> scatterShape.inGeometry
polyShape.worldMatrix -> scatterShape.inWorldMesh


5. Connect:

scatterShape.outPositionPP -> shatter.inPositionPP
scatterShape.outGeometry -> shatter.inGeometry


6. Make a copy of the poly object, set its scale to (1,1,1), drag its shape node into the Hypershade

7. Connect:

shatter.outGeometry -> polyShape2.inMesh

You should have a network like this one:






Now, you will notice that my horse is shattered but yours is not, that is because I checked Auto Evaluate on the Shatter node which is disabled by default. This is because the shattering process can take a long time to calculate depending on the number of points generated by the Scatter node. I suggest lowering the Max Number of Points on the Scatter node to 10 before checking the Auto Evaluate on the Shatter node so you can check that everything is connected up and working correctly.



So, you have a shattered poly, but there are no dynamics. The method that I have used to add dynamics is to make the shattered geometry a nCloth object. Here are my notes taken from Jostein Finnekasa's Vimeo tutorial which explains everything very clearly.

1. Check Auto Evaluate on the Shatter node

2. Click the Bake Result on the shatter node when you are happy with your shatter results.

3. Apply a shader to the bakedResult

4. Create nCloth with the bakedResult selected


This will give you a nCloth object to which ou can apply all the usual forces and collisions. The workflow goes on to create dynamic contraints, nComponents and SOuP's Attribute Transfer node with Bounding Boxes to override the constraints. Here are my notes:

1. Select all vertices of the nCloth object

2. create a Transform nContsraint

3. Making the constraint created a Dynamic Constraint node. Drag this node from the outliner to the Hypershade

4. If you select and graph the bakedResult and the Dynamic Constraint nodes. You should see a graph like this one:



Here is the method for setting up the Attribute Transfer on the nCloth constraint:

1. Create an Attribute Transfer node

2. Check the Weight box on the Attribute Transfer node

3. In the Attribute Transfer node, create two Bounding Box objects.

4. Set the first Bounding Box to a cube and scale it so that it completely envelopes the poly object.

5. Set the first Bounding Box's Weight Falloff to a flat ramp with value 1

6. Set the second Bounding Box shape to a sphere

7. Set the second Bounding Box's Weight Falloff to a flat ramp with value -1

8. Connect:

bakedResultShape.worldMesh -> attributeTransfer.inGeometry

9. Connect:

attributeTransfer.outWeight -> nComponent.strengthPerVertex

attributeTransfer.outWeight -> nComponent.glueStrengthPerVertex

attributeTransfer.outWeight -> nComponent.weightPerVertex

10. Set nComponent Map Types to per vertex for all three maps

11. In the Dynamic Constraint node, set the Strength to 1, the Glue Strength to 0.1 and Glue Strength Scale to 0.1. These values are just starting points to control the way the nCloth acts, but they give good results for the tests I have done.

So, that is the setup done, you should have a network like this one:



Please go to the SOuP website and get the plugin. It's free, it's very powerful and there is loads of help, examples, tutorials. Also, the developer, Peter, seems to read all the forum posts and will reply to questions.

I will attempt to post more walk-throughs for SOuP as I learn them and use them in a production.

Here is a little shatter effect I created using SOuP ( and a couple of regular particle objects with instanced shard objects).

Thursday, 28 April 2011

Using multiple emFly compounds



When using Eric Mootz's excellent emFly system, it is possible to use multiple emFly compounds.

Let's say you have a complex flight plan and you want two different landing behavours, you will need to use a unique emFly compound for each landing.

Using ICE States, you can plug in a new emFly compound into each State's 'execute once enter' and 'execute every frame'.



I haven't seen this documented anywhere, but it worked for me in Softimage 2011.

Hey, my first Softimage ICE post !

Tuesday, 19 April 2011

nParticle cache creation - use forward slash



When you want to create a nParticle cache in a custom folder, say c:\particles,
enter that folder in the options box, but use the forward slash instead.



I'm not sure if this is a bug, but I found that using a backslash will not work.