While reading about particles in Docs, I found this PG. It inspired me and I thought if it’s possible to do the same, but with rectangular shape of emitter. To make it look somewhat like portal of old good Quake.
The first simple solution may look like this.
out.x = BABYLON.Scalar.RandomRange(-5, 5);
out.y = BABYLON.Scalar.RandomRange(-5, 5);
But in this case the particles will spawn on the whole square, but I wanted to make the frame only to emit the particles. For this purpose, I wanted to use the formula of rectangular motion instead of circle motion. But there is a problem. The formula of rectangular motion doesn’t exist. At least not in a simple form. So, I needed to create my own function that will simulate rectangular motion. And I really wanted to make a cyclic continuous function.
Before we start, let’s introduce some variables.
let width = 10; // size of rectangle (for now only squares are supported).
let resolution = 0.05; // step between emission points on the frame. The smaller value the denser frame will be.
You want the ratio width/resolution
to be a whole number. If it’s not, the portal will be asymmetric. However, it still will work.
The final computation algorithm looks like that:
let id = 0;
let width = 10;
let resolution = 0.05;
function getNextCoordinate() {
let pointN = id % (4 * width);
if (pointN < width) {
return [pointN - width / 2, width / 2];
}
else if (pointN < 2 * width) {
return [width / 2, 1.5 * width - pointN];
}
else if (pointN < 3 * width) {
return [2.5 * width - pointN, -width / 2];
}
else {
return [-width / 2, -(3.5 * width - pointN)];
}
}
customEmitter.particlePositionGenerator = (index, particle, out) => {
let value = getNextCoordinate();
out.x = value[0];
out.y = value[1];
out.z = 0;
id += resolution;
}
It doesn’t look overwhelming, but I spent hours with paper and pen drawing rectangles and trying to figure out the formula.
To make things look more pretty you may also want to increase emitRate
, activeParticleCount
and capacity
of particle system. Especially with smaller resolution
values.
One more thing. This algorithm literally circles along perimeter step by step. It doesn’t look bad, but the frame looks like dotted line a bit. To make it look more uniform, we can randomize a bit instead of relying on external counter id
.
if (randomize) {
pointN = BABYLON.Scalar.RandomRange(0, 4 * width);
}
Final result: https://playground.babylonjs.com/#GFMBMS#1.
Ways for improvements:
- Move randomization out of
getNextCoordinate
function and acceptid
as parameter to make things moreSOLID
and lessimpure
. - Support true rectangles with different
width
andheight
. - Make
getNextCoordinate
as generatorfunction*
(just for fun). - Support cubic shape with different
width
,height
anddepth
(task for high tier predators only :D).
Actually…
Custom rectangle version is here: https://playground.babylonjs.com/#GFMBMS#3
a) You may want the ratio width/resolution
and height/resolution
to be a whole number. For symmetry.
b) In randomization section you can use smaller range to create a fractured portal. Still works and looks like charm. Try for example 60% of perimeter: pointN = BABYLON.Scalar.RandomRange(0, 0.6*perimeter);
.
May not work as good with non-GPU particles. I didn’t test much, honestly. Use powerfull PC.