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.