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.

Friday, 15 April 2011

Adding variation to per particle attributes that use ramps





Let's say you have a classic particle (not an nParticle) which will use a ramp to assign it's radiusPP.
You want to add some variation to the ramp but have each particle read a unique value and then travel up the ramp over it's lifespan as usual.

Here are the steps:

1. Create the radiusPP via the Add Dynamics Attibutes button
2. Create the ramp by right-clicking in the RadiusPP box
3. Right-click the RadiusPP box again and hold over the menu item until the second menu appears. Choose Create RadiusUPP


4. Once you have the RadiusUPP attribute, give it a random value betweek 0 and 1 via the expression editor


5. To link the UPP value to the ramp, we need to re-make the array mapper. Right-click on the RadiusPP box and delete the arrap mapper (you will want to rename or check the name of the ramp before you do this)

6. Right-click in the RadiusPP box again and click on the Create Ramp options box. Choose RadiusUPP for the input U, leave input V as Particle's Age and then choose the ramp in the Map To list.



Now each particle is going to read a value at a random point across the bottom of the ramp and then move up the ramp over it's lifetime. Now we need to add some variation to the ramp. A quick way to do this is to use the ramp's built in noise functions

Saturday, 9 April 2011

Approximating ConservePP

Wouldn't it be nice sometimes if we could have a per-particle Conserve attribute? Well, a reasonable approximation can be to use the mass attribute instead.

The conserve attribute essentially is a multiplier on the particle's velocity. For example, if a particle has velocity 100 at frame 1 and a conserve of 0.5, then a frame 2 the velocity would be 50, at frame 3 it would be 25, and so on.

So, the conserve attribute acts as a brake on the velocity.

In the physical world, mass (specifically Inertial mass) can be defined as 'resistance to acceleration'. When simulating particle dynamics we can use mass as a dampening effect on the motion of a particle, in a similar way that conserve does. The main difference is that we can define the mass on a per-particle basis: the higher the mass the higher the resistance to motion and the lower the 'conservePP' value we are creating.

Friday, 8 April 2011

Gravity versus Uniform field

In nature, a body is affected by gravity in relation to its mass. Newton's equation of gravity show this:

F= G (M * m) / r^2

Where M and m are the masses of the bodies affected.

Also, Newton's laws of motion (he was a clever guy) show that force is also proportional to mass:

F = m a

If we equate the two forces we see that both sides have the mass, m, which cancel each other out.

So, the acceleration that the body experiences is not proportional to its mass.

This is not true for a Universal force. The strength of a universal force is not linked to the mass of the body and so when we equate it with the law of motion we get something like this:

m a = U

Where U is the arbitrary universal force.

So the acceleration experienced by the body is now (inversely) proportional to its mass.

Maya copies nature in this regard, so if you want to use variable masses to drive your simulations, be aware that the Gravity force will affect all the particles uniformly but a Uniform field will affect them in (inverse) proportion to their mass.