# particle system math question

Please take a moment to consider if this thread is worth bumping.

## Recommended Posts

math question.
I make a particle system which changes BURST RATE depending on the vehicle throttle. increases when accelerating and decreases when slowing.

there are ten gears and three reverse gears.

how mathematically correct did I make this particular system?
unfortunately I’m not a mathematician or even a scripter. It’s quite difficult for me to judge this.

In principle, everything works, but maybe there is an error? I know that if everything works, it’s better not to touch it, but I still doubt.

```    float rate = llAbs(throttle + 10) / 0.0333;
if (rate > 1) rate = 1;

PSYS_PART_FLAGS, 1287,
PSYS_PART_START_COLOR, < 1, 1, 1 > ,
PSYS_PART_END_COLOR, < 1, 1, 1 > ,
PSYS_PART_START_SCALE, < 0.75, 0.75, 0.00000 > ,
PSYS_PART_END_SCALE, < 1.5, 1.5, 0.00000 > ,
PSYS_SRC_PATTERN, 16,
PSYS_SRC_BURST_RATE, 0.20 * rate,
PSYS_SRC_BURST_PART_COUNT, 3,
PSYS_SRC_BURST_SPEED_MIN, 0.05,
PSYS_SRC_BURST_SPEED_MAX, 0.10,
PSYS_SRC_ANGLE_BEGIN, 0.00,
PSYS_SRC_ANGLE_END, 0.00,
PSYS_SRC_MAX_AGE, 0.0,
PSYS_SRC_TEXTURE, "5748decc-f629-461c-9a36-a35a221fe21f",
PSYS_PART_START_ALPHA, 0.5, // texture transparency
PSYS_PART_END_ALPHA, 0.00,
PSYS_PART_START_GLOW, 0.03, // texture glow start
PSYS_PART_END_GLOW, 0.01
]);```

Edited by Doctor Visage
##### Share on other sites

Personally, I'd probably just have a list of 13 floats, index by throttle+3 (assuming the reverse gears have throttles -3, -2, and -1), and just put numbers in the list that look good by experimentation. Getting it numerically "accurate" is no assurance of it looking good. Most important, of course, is to never update the particle system unless the throttle has changed, that way it won't push an unnecessary object update, and won't restart ongoing particle emission.

• 1
• 1
##### Share on other sites

Some comments, the burst rate depends on your throttle value and the higher value the longer time between burst intervals.

Low throttle would normally be slower burst rate as the engine is idle, so I would reverse the values.

Notice, "Specifying a value of 0.0 will cause the emission of particles as fast as the viewer can do so." and remember particles will always depends on how good the user computer CPU and graphic GPU are, with that in mind is good custom to avoid "over bursting".

A good way to handle engine throttle as above is using logarithmic functions, simplify for example by doing as Qie suggests by using a list for good values.

• 1
##### Share on other sites

Without knowing what your particles represent, it's difficult to know how to drive llParticleSystem(). For something like exhaust smoke, you might change rate, burst count, speed_min, speed_max. angle_begin and angle_end. You'd also probably want to set PSYS_PART_WIND_MASK.

Regardless of what you're trying to do, I see potential errors in your calculation...

```float rate = llAbs(throttle + 10) / 0.0333;
if (rate > 1) rate = 1;```

It seems you want increasing particle emission with acceleration and decreasing with slowing. Your function would do approximately the opposite. We might blame LL for misnaming the PSYS_SRC_BURST_RATE parameter. It should be called PSYS_SRC_BURST_INTERVAL. At zero, "rate" produces bursts of particles as fast as the viewer can go, potentially starving other emitters within view. As rate rises to one (second), particle emission slows to the puff-puff-puff of a steam locomotive pulling out of the station.

You use llAbs(), which suggests to me that you're expecting negative throttle values, probably for reverse as Qie assumed. You add 10 to throttle so that there is some output (exhaust?) at idle. Unfortunately, for a throttle of -10, you'll get a rate of 0.0, which Rachel notes will produce the maximum possible burst rate. You divide the throttle value by 0.0333, which is the same as multiplying by 30, but far less obvious. Your calculation will produce a rate of one for all values of "throttle" outside the range of -9.966 to -10.0333. I don't think that's your intent. You mention both throttle and gears, but I suspect you mean your vehicle has 10 forward velocities, idle(zero), and three reverse velocities. Let's presume throttle ranges from 10 to -3. This might be more like what you want...

```
```

From there, you'd use "count" to set PSYS_SRC_BURST_PART_COUNT and you'd set PSYS_SRC_BURST_RATE to something reasonable, like 0.2 (five bursts/second).

• 1
• 1
##### Share on other sites

16 hours ago, Qie Niangao said:

Personally, I'd probably just have a list of 13 floats, index by throttle+3 (assuming the reverse gears have throttles -3, -2, and -1), and just put numbers in the list that look good by experimentation.

11 hours ago, Rachel1206 said:

A good way to handle engine throttle as above is using logarithmic functions, simplify for example by doing as Qie suggests by using a list for good values.

9 hours ago, Madelaine McMasters said:

From there, you'd use "count" to set PSYS_SRC_BURST_PART_COUNT and you'd set PSYS_SRC_BURST_RATE to something reasonable, like 0.2 (five bursts/second).

Hello! thanks a lot! Have I changed the system correctly according to your recommendations?

EDIT: I discovered an error while testing and changed float to integer

```    startParticles(integer link)
{
// PARTICLE COUNT LIST
integer count = 0;

if (throttle == 10) count = 1;
else if (throttle == 20) count = 2;
else if (throttle == 30) count = 3;
else if (throttle == 40) count = 4;
else if (throttle == 50) count = 5;
else if (throttle == 60) count = 6;
else if (throttle == 70) count = 7;
else if (throttle == 80) count = 8;
else if (throttle == 90) count = 9;
else if (throttle == 100) count = 10;

PSYS_PART_FLAGS, 1287,
PSYS_PART_START_COLOR, < 1, 1, 1 > ,
PSYS_PART_END_COLOR, < 1, 1, 1 > ,
PSYS_PART_START_SCALE, < 0.75, 0.75, 0.00000 > ,
PSYS_PART_END_SCALE, < 1.5, 1.5, 0.00000 > ,
PSYS_SRC_PATTERN, 16,
PSYS_SRC_BURST_RATE, 0.20,
PSYS_SRC_BURST_PART_COUNT, count, // CHANGED FROM RATE TO COUNT
PSYS_SRC_BURST_SPEED_MIN, 0.05,
PSYS_SRC_BURST_SPEED_MAX, 0.10,
PSYS_SRC_ANGLE_BEGIN, 0.00,
PSYS_SRC_ANGLE_END, 0.00,
PSYS_SRC_MAX_AGE, 0.0,
PSYS_SRC_TEXTURE, "5748decc-f629-461c-9a36-a35a221fe21f",
PSYS_PART_START_ALPHA, 0.5,
PSYS_PART_END_ALPHA, 0.00,
PSYS_PART_START_GLOW, 0.03,
PSYS_PART_END_GLOW, 0.01
]);
}```

Edited by Doctor Visage
##### Share on other sites

The only thing that bothers me is this column.

```    if (throttle == 10) count = 1;
else if (throttle == 20) count = 2;
else if (throttle == 30) count = 3;
else if (throttle == 40) count = 4;
else if (throttle == 50) count = 5;
else if (throttle == 60) count = 6;
else if (throttle == 70) count = 7;
else if (throttle == 80) count = 8;
else if (throttle == 90) count = 9;
else if (throttle == 100) count = 10;```

Is it possible to simplify it to some kind of mathematical formula?
besides in my script the same column is already found only for other purposes. I tried to combine them, but the script grows to 10-20 lines ...

##### Share on other sites

With these particular values you could just divide the throttle value by ten to get the count, but I'm super doubtful that these counts will look good for those throttle values -- that really needs experimentation. Presumably the point of increasing particles is to maintain a kind of steady density as the vehicle speeds away. Or maybe that's not how you're trying to make it look. Anyway, I'm not confident that you'll want to keep using these throttle values either, so I think it's better to shift to a look-up table list (instead of just indexing into the list by gear or throttle or whatever). So, it might look something like this:

```integer saveThrottle;
integer throttle;

{
list THROTTLE_PARTICLE_COUNT = // tuples: throttle, count
[ 0, 0
, 10, 1
, 20, 2
, 30, 3
, 40, 4
, 50, 5
, 60, 6
, 70, 7
, 80, 8
, 90, 9
, 100, 10
];
if (throttle == saveThrottle)
return; // don't update particle system if throttle hasn't changed
saveThrottle = throttle;
integer index = llListFindList(THROTTLE_PARTICLE_COUNT, [throttle]);
if (-1 == index)
{
llWhisper(DEBUG_CHANNEL, "unknown throttle setting: "+(string)throttle);
return;
}
integer count = llList2Integer(THROTTLE_PARTICLE_COUNT, index+1);
llOwnerSay((string)count);  // testing only
PSYS_PART_FLAGS, 1287,
PSYS_PART_START_COLOR, < 1, 1, 1 > ,
PSYS_PART_END_COLOR, < 1, 1, 1 > ,
PSYS_PART_START_SCALE, < 0.75, 0.75, 0.00000 > ,
PSYS_PART_END_SCALE, < 1.5, 1.5, 0.00000 > ,
PSYS_SRC_PATTERN, 16,
PSYS_SRC_BURST_RATE, 0.20,
PSYS_SRC_BURST_PART_COUNT, count, // CHANGED FROM RATE TO COUNT
PSYS_SRC_BURST_SPEED_MIN, 0.05,
PSYS_SRC_BURST_SPEED_MAX, 0.10,
PSYS_SRC_ANGLE_BEGIN, 0.00,
PSYS_SRC_ANGLE_END, 0.00,
PSYS_SRC_MAX_AGE, 0.0,
PSYS_SRC_TEXTURE, "5748decc-f629-461c-9a36-a35a221fe21f",
PSYS_PART_START_ALPHA, 0.5,
PSYS_PART_END_ALPHA, 0.00,
PSYS_PART_START_GLOW, 0.03,
PSYS_PART_END_GLOW, 0.01
]);
}

default // for testing only
{
state_entry()
{
while (TRUE)
{
// generate some multiple-of-ten throttle settings to test:
throttle = 10 * (integer)llFrand(11.0);
maybeUpdateParticles(0);
llSleep(3.0);
}
}
}```

It may not be obvious that this THROTTLE_PARTICLE_COUNT list is a constant that's defined at compile time, so it uses no time when the program runs. The look-up does use some time, but it's a lot faster than a whole string of if/else conditionals.

Oh, also, note that the "count" variable needs to be an integer to be used at the value of the PSYS_SRC_BURST_PART_COUNT parameter. (It could be a float that gets cast to an integer when used, but that's extra work.)

• 1
##### Share on other sites

4 hours ago, Doctor Visage said:

The only thing that bothers me is this column.

```
if (throttle == 10) count = 1;
else if (throttle == 20) count = 2;
else if (throttle == 30) count = 3;
else if (throttle == 40) count = 4;
else if (throttle == 50) count = 5;
else if (throttle == 60) count = 6;
else if (throttle == 70) count = 7;
else if (throttle == 80) count = 8;
else if (throttle == 90) count = 9;
else if (throttle == 100) count = 10;```

Is it possible to simplify it to some kind of mathematical formula?
besides in my script the same column is already found only for other purposes. I tried to combine them, but the script grows to 10-20 lines ...

if (throttle>0)
integer count= llRound(throttle/10);

• 1
##### Share on other sites

a tiny performance improvement. Multiplication is fractionally faster than division. In this case multiply by 0.1 rather than divide by 10

`integer count = llRound(throttle * 0.1);`

this said, I recommend Qie's approach of a list stride for each throttle setting, as when we start evolving our vehicles to move in ways other than forward/backward then we kinda evolve into wanting different particle effects accordingly

like doing donuts: throttle wide open, front brake on, 360 degree angular movement. Particles more drifting up, rather than more vertically as when straight lining

with the list design, as our vehicles evolve we can also start adding tuples to the stride (record) like:  motion, velocity, throttle, count

where motion is a descriptor like: Linear Forward, Linear Back, Angular Left, Angular Right.  etc

and velocity is the velocity/speed of the vehicle, which may not be the same as the throttle setting.  Donuts, alley oops, etc

then as we get deeper into it then more parameter tuples in addition to count. speed, angle, age, rate, etc

• 1
##### Share on other sites

19 hours ago, Qie Niangao said:

It may not be obvious that this THROTTLE_PARTICLE_COUNT list is a constant that's defined at compile time, so it uses no time when the program runs. The look-up does use some time, but it's a lot faster than a whole string of if/else conditionals.

Oh, also, note that the "count" variable needs to be an integer to be used at the value of the PSYS_SRC_BURST_PART_COUNT parameter. (It could be a float that gets cast to an integer when used, but that's extra work.)

Thanks a lot! finally managed to conduct tests, your method works perfectly!

• 2