API

Managing Point Cloud Particles

Particle Properties

Once the PCS mesh is built, unless immutable, it can respond to changes in the properties of each particle. Existing properties are shown in the table below.

PropertyTypeDefault
position
Vector3
(0, 0, 0)
rotation
Vector3
(0, 0, 0)
rotationQuaternion
Vector3
undefined
velocity
Vector3
(0, 0, 0)
color
Vector4
(1, 1, 1, 1)
pivot
Vector3
(0, 0, 0)
uvs
Vector2
(0,0)
translateFromPivot
boolean
false
parentId
integer
null
idx
integer (read only)
index of particle
groupId
integer (read only)
group number for a particle

If you set a particle rotation quaternion, its rotation property will then be ignored.

New properties can be initialized.

Note: Since point particles always face the camera, setting the rotation of a particle only has any effect in two cases:

  1. The rotation of a particle parent will rotate its children about itself;
  2. A pivot is set for the particle.

Initialising Particles

When using addPoints, particle properties can be set in the passed function. The addSurfacePoints and addVolumePoints methods obviously set the position and color properties of the particles, but you may still want to set the initial values of other particle properties.

This can be done using initParticles. To do this, iterate over all the particles by using the nbParticles property, and follow the call to this function with a call to setParticles(). For example:

import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { PointColor } from "@babylonjs/core/Particles/pointsCloudSystem";
pcs.initParticles = function () {
for (let p = 0; p < pcs.nbParticles; p++) {
pcs.particles[p].velocity = Vector3.Zero();
pcs.particles[p].acceleration = pcs.particles[p].position.scale(0.01);
}
};
pcs.addSurfacePoints(model, 10000, PointColor.Color);
pcs.buildMeshAsync().then(() => {
model.dispose();
pcs.initParticles();
pcs.setParticles();
});

Updating Particles

Once the appropriate particle properties are initialized, the updateParticles method can be used. Unlike initParticles, this function is called by setParticles and already receives a particle as an argument. The setParticles method will execute only after the PCS mesh has been built, so it can safely be placed inside a render loop to produce an animation. For example:

pcs.updateParticle = function(particle) {
particle.velocity.addInPlace(particle.acceleration);
particle.position.addInPlace(particle.velocity);
}
scene.registerBeforeRender(() => {
pcs.setParticles();
});

Note: All particle positions are expressed in the local space of the PCS mesh.

The particle pivot vector is also in the local space of the PCS mesh. By default, rotations around a pivot are calculated by translating the particle to the pivot point, then rotating it, and then applying the inverse translation. By setting the particle property translateFromPivot to true (default false), rotations are calculated using only the initial translation followed by the rotation, leaving the particle at the translated location.

Simple Animation

In the following playground, the particle pivots in the top PCS are set relative to the particle position, and in the lower one they are set in the same place.

Pivot Animation Example 1

In this playground, the only difference is that the lower PCS has translateFromPivot set to true.

Pivot Animation Example 2

This playground animates the mesh, not the particles.

Immutable Animation

This playground loads meshes from a file, converts them to particles, and animates them.

Loaded Mesh Animation

UVs

While setting and changing particle colors is straightforward, doing the same for UVs is a little more complex. Using BABYLON.PointColor.UV as a parameter within addSurfacepoints or addVolumePoints will set the UVs automatically based on the passed mesh.

You can also set the UV value for each particle using the function passed to addPoints. To make the texture map correctly, the UV values should relate in some way to the positional values for each particle. To apply the texture with these UVs, both the emissiveColor and emissiveTexture for the PCS mesh material must be set after the mesh is built.

Note: Only use emissive.

For example

import { Color3 } from "@babylonjs/core/Maths/math.color";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
var myfunc = function (particle) {
var x = Math.random();
var y = Math.random();
var z = 0;
particle.position = new Vector3(x, y, z);
//Relate uv values to positional values
particle.uv.x = x;
particle.uv.y = y;
};
pcs.addPoints(5000, myfunc);
pcs.buildMeshAsync().then(() => {
pcs.mesh.material.emissiveColor = new Color3(0, 0, 0);
pcs.mesh.material.emissiveTexture = myTexture;
});

It is possible to use a texture atlas, but you need to customize and calculate the more complex relationship between positional and UV values.

UV With Added Points UV With Texture Atlas

Recycling Particles

You can write your own code to recycle particles using recycleParticle, which can be called from within updateParticle. For example:

import { Vector3 } from "@babylonjs/core/Maths/math.vector";
pcs.recycleParticle = function (particle) {
particle.position = Vector3.Zero();
particle.velocity = Vector3.Zero();
particle.heightLim = 4 + 0.5 * Math.random();
};
pcs.updateParticle = function (particle) {
if (particle.position.y > particle.heightLim) {
this.recycleParticle(particle);
}
particle.velocity.addInPlace(particle.acceleration);
particle.position.addInPlace(particle.velocity);
};
Recycling Animations

Particle Parenting

Each particle can be given another particle as a parent.
The parent must be created before the child particle. This means the parent must have a lower index ID (particle.idx) than the current particle. So the first particle in the pool (idx = 0) cannot have a parent. To give a parent to a particle, just set its property parentId to the parent index ID value.

if (particle.idx > 0) {
particle.parentId = particle.idx - 1; // the previous particle becomes the parent of the current one
}

To un-parent a particle, just set .parentId back to null which is the default value.

When a particle has a parent, its position and rotation are then expressed in its parent's local space.

if (particle.idx > 0) {
particle.parentId = particle.idx - 1; // the previous particle becomes the parent of the current one
// the particle position and rotation are expressed in the previous particle space, this one being already
// rotated and translated from the yet previous particle. Etc.
particle.rotation.z = 0.01;
particle.position.x = 1.0;
}
Parent Animation

Particle Intersections

The PCS provides a simple way to deal with intersections between a particle and other meshes. As this feature consumes more memory and CPU, do not include it unless necessary.

To use it, call the method intersectsMesh(target) (target is a mesh) for any particle to check whether it intersects the target.
It will simply return true or false depending on whether the particle intersects the target.

if (particle.intersectsMesh(anyMesh)) {
// change properties of particle
}

By default, the check is carried out on the mesh's (AABB) bounding box. If you want to use the mesh's bounding sphere, add the parameter true.

if (particle.intersectsMesh(mesh, true) {
// change properties of particle
};
Recycling Particle Collisions Mesh Colliding With Point Cloud