Before/After Runtime Expressions

For a pretty long time differences between runtimeBeforeDynamics and runtimeAfterDynamics particle expressions were pretty vague for me. Well, their names seem to explain everything – first ones are executed before dynamics and second ones – afterwards… But what the hell does this mean and what do I need it for in practice, how could I make use of them?! 🙂

I’ll try to answer that question and as an example to make a setup of particle that formally collides with a surface – returning time, coordinates and other info about a collision – but keeps moving as if nothing had happened, as if it hadn’t collided at all (e.g. bullet goes through an object leaving holes at entry and exit points).

Generally each new frame the following happen:
– non-particle expressions and other animation in the scene get evaluated;
– for each existing particle runtimeBeforeDynamics expression gets evaluated;
– all dynamics in the scene, including new particle generation by emitters, fields influence, goal, collisions etc.;
runtimeAfterDynamics;

So, particles born before or during the dynamics stage would be affected by it right in this frame, i.e. if we create a particle via standard emitter or via emit command in non-particle or runtimeBeforeDynamics expression – it’d appear with dynamics applied already. If emit command gets executed in runtimeAfterDynamics – a particle would appear exactly at the specified position and only next frame it’d be affected be dynamics.

Let’s say, there’s a particle in the scene (id #0), that each frame generates another particle in <<1, 0, 0>> coordinates and all of them are affected by uniform field aimed upwards:

if( particleId == 0 ) {
		emit -o particle1 -pos 1 0 0;
}

If this expression is in runtimeBeforeDynamics, each frame new particle gets born, then it gets influenced by uniform field and then we get the result – a particle appears not at specified <<1, 0, 0>> coordinates, but with respect to the field – a bit higher. If we place this command in runtimeAfterDynamics – each new particle appears without any force applied exactly at <<1, 0, 0>> (only next frame it would be paying respect to it):

Difference between before and after runtime expressions

Difference between before and after runtime expressions

In a lot of cases these differences are unessential, but in some specific ones or for special tasks could matter. For example:

1) rigidBody object quickly falls down, from some of it’s surface points particles get generated lifting upwards – if their generation happens in runtimeBeforeDynamics, trail they build up would be shifted upwards from the emission point all the time since after particle is born it is instantaneously forced upwards and rigidBody downwards. But using runtimeAfterDynamics calculations and emission would happen after rigidBody dynamics and forces application in this frame – the trail would be exactly out of the surface point;

2) particles collide with animated object and each one of them creates a new one at collision. This new one is connected via goal to that surface point (a hole from bullet in the head):

if( collidingParticles.collisionTime > 0 ) {
	float $collPos[] = collidingParticles.collisionPosition;
	float $collUV[] = { collidingParticles.collisionU,
		collidingParticles.collisionV };

	emit -o stickingParticles -pos $collPos[0] $collPos[1] $collPos[2]
		-at "goalU" -fv $collUV[0]
		-at "goalV" -fv $collUV[1];
}

Since collisions are evaluated right between runtimeBeforeDynamics and runtimeAfterDynamics, the soonest place we can use the results is the latest – that way new particles will be born and connected via goal at the same frame collision happens. If expression is in runtimeBeforeDynamics, these particles would appear only at the next frame (collision data reevaluates after runtimeBeforeDynamics, so our particles will stick to the same spots anyway). Everything seems not too bad unless we use some animated values from the scene to generate our particles – let’s say, position in Y of the mentioned animated object defines whether to stick particles or not:

if( collidingParticles.collisionTime > 0 ) {
	float $sphPos[] = `pointPosition -w pSphere1.rotatePivot`;
	if( $sphPos[1] < 10 ) {
		float $collPos[] = collidingParticles.collisionPosition;
		float $collUV[] = { collidingParticles.collisionU,
			collidingParticles.collisionV };
		emit -o stickingParticles -pos $collPos[0] $collPos[1] $collPos[2]
			-at "goalU" -fv $collUV[0]
			-at "goalV" -fv $collUV[1];
	}
}

Since object movements happens after runtimeAfterDynamics but before runtimeBeforeDynamics one frame of particles sticking would be lost if runtimeBeforeDynamics is used in this case. Well, all differences here are related to the order of data evaluation:

Particle generation on collision with before and after runtime expressions

Particle generation on collision with before and after runtime expressions

Now is time for the example mentioned in the beginning – a bullet not just collides with an object leaving a hole in the collision point, but continues to fly unchanged through it leaving exit hole on the other side. We can achieve it this way – since collisions are evaluated between runtimeBeforeDynamics and runtimeAfterDynamics we’ve got values before collision in the first one and after collision in the second. We can store position before dynamics into custom attribute (beforePosition), use it to calculate where the particle should have been save for collision and move it there after dynamics, that leaves us collision data we want:

runtimeBeforeDynamics:

beforePosition = position;

runtimeAfterDynamics:

float $beforePos[] = beforePosition;
vector $accel = acceleration;
float $fps = `currentTimeUnitToFPS`;
float $noColl[] = $accel / pow($fps, 2);

if( collisionTime > 0 ) {
		position = <<($beforePos[0]+$noColl[0]), ($beforePos[1]+$noColl[1]),
			($beforePos[2]+$noColl[2])>>;
}

In this case, we can make everything even simpler using special attribute lastPosition that returns position values of the last but one evaluation and as a result can eleminate the necessity to use custom attribute beforePosition and runtimeBeforeDynamicsexpression:

runtimeAfterDynamics:

float $beforePos[] = lastPosition;
vector $accel = acceleration;
float $fps = `currentTimeUnitToFPS`;
float $noColl[] = $accel / pow($fps, 2);

if( collisionTime > 0 ) {
		position = <<($beforePos[0]+$noColl[0]), ($beforePos[1]+$noColl[1]),
			($beforePos[2]+$noColl[2])>>;
}

The result we need is achieved – collision happens, all collision* attributes we need are calculated, but particle doesn’t change it’s trajectory.

Also I want to mention world* attributes (particularly worldPosition). From what I can see, by default they are calculated once at the end of everything – after runtimeAfterDynamics, but if collision objects are connected to particles additional calculation happens right after dynamics application stage, but without influence of collisions 🙂 I can’t give a reasonable explanation to that, but to use it:

runtimeAfterDynamics:

if( collisionTime > 0 ) {
	position = worldPosition;
}

I’m attaching example scene with bullet penetrating the cube all the way through:

Example scene with bullet penetrating a cube

example_scene

Some examples could be not too interesting and bright, but I hope that I’ve managed to clear up in one way or another the topic of differences between before/after runtime expressions 🙂

2 Responses

Subscribe to comments via RSS

  1. Written by Ruben
    on 4 July 2009 at 1:14
    Permalink

    Hey these tuts are amazing, but could you make some tutorials for beginners? just getting into scrpting got particles

  2. Written by Sagroth
    on 4 July 2009 at 3:25
    Permalink

    Thanks.
    I guess I can, but I think there’re a lot of good tutorials on particle expressions for beginners already. And they are pretty boring to write also 🙂

Subscribe to comments via RSS

Leave a Reply