neutrinoparticles.js v2.0.2
neutrinoparticles.js
The library allows you to load and simulate particle effects exported from NeutrinoParticles Editor.
This is basically a core library which can update particle effect and give you instructions on how to render this effect.
Available integrations
Below is a list of addons for most popular engines/frameworks. These addons provide integrated renderers for neutrinoparticles.js
.
Full integration. Supports PIXI.js v4 and v5. | |
Full integration. Supports Phaser3 only. | |
Installation
You can install the package with npm
:
> npm install neutrinoparticles.js
Or download pre-built package at Releases page. There are UMD packages which you can use in any environment.
Introduction
NeutrinoParticles Editor exports effect to .js
file. This file contains a class of the effect with all algorithms and data necessary to simulate it. This class is a model of effect. The model is constant object, and you need only one model to have many instances of this effect in your application.
This library contains shared code which exported effects use. In particular, mathematics, turbulence computations etc.
To use the library in your application, first of all, you need to get access to it. Depending on your environment:
- HTML
<script src="path/to/neutrinoparticles.js/dist/neutrinoparticles.umd.js"></script>
- node.js
var Neutrino = require('neutrinoparticles.js')
- ES6
import * as Neutrino from 'neutrinoparticles.js'
Main Context
Main context is a main interface of the library and a shared object for all effects in the application.
To create it:
let neutrino = new Neutrino.Context();
Loading effect model
Files of effects exported by the Editor has to be evaluated to obtain JS objects that can be used in the application.
You can load effect model using main context. It will use HTTP request to load effect by path. And in this case it will make all evaluating by itself and return you ready to use object:
neutrino.loadEffect('path/to/effect.js', function(effectModel) {
// on success
},
function() {
// on fail
});
Or you can somehow load effect file by yourself (or unpack from zip, for example), and when you have a text of the file you can use this simple evaluating function:
function evalEffectModel(effectSource) {
let wrappedScript =
"(function(context) {\n" +
effectSource +"\n" +
"return new NeutrinoEffect(ctx);\n" +
"})(neutrino);";
return eval(wrappedScript);
}
Creating effect instances
When the effect model is loaded, you can create instances of this effect. Each instance is actual entity of effect. It is a state of effect. It has position, rotation and it can be updated (simulated) by time.
Depending on what kind of rendering you want to perform, you can create an instance for:
Canvas rendering:
let effect = effectModel.createCanvas2DInstance(
position, // Array [x, y, z] for starting position of the effect
rotation, // Array [x, y, z, w] for quaternion representing starting rotation
{ // options
paused: false, // Effect paused on start?
generatorsPaused: false // Generators of the effect paused on start?
});
or WebGL rendering:
let effect = effectModel.createWGLInstance(
position,
rotation,
renderBuffer, // Buffer to accept constructed geometry for particles
options
);
Updating effect
You would probably want to update the effect on each frame of your application. And on each update you can set up new position and rotation of the effect:
effect.update(
timeInSeconds, // time to simulate
position, // (optional) new position, if changed
rotation // (optional) new rotation, if changed
);
Rendering effect
Rendering of effect is out of scope of this library. This is because any graphical framework or engine requires custom deep integration and there is no any unified solution.
However, you can find reference renderers in /samples
folder of the repository. There are Canvas and WebGL renderers. They are designed for clean HTML5 environment and can be used as standalone renderers on a web site. Or you can refer to them for creating a custom renderer for your graphical framework.
For PIXI.js you can use neutrinoparticles.pixi.js renderer.
Position and Rotation
Effects accept position and rotation on creating and update.
Position vector is represented by 3D array x, y, z.
Rotation is a quaternion represented by 4D array x, y, z, w.
You can make a rotation quaternion by function:
neutrino.axisangle2quat_(
[x, y, z], // rotation axis
angle // rotation angle in degrees
);
it will make a quaternion by rotating arout an axis.
To react on rotation, effect has to be correcly prepared in the Editor. See "Apply emitter's rotation" switch in Emitter Guide in the Editor.
Using turbulence (or noise)
You need to initialize noise texture before simulating effects which use it. Otherwise, your effects will be without any noise (or turbulence).
You have two options to make that: to generate or to download it.
Generating noise
Generating noise is iterative process and you can spread it for many application frames (to render some progress bar, for example).
Below is an example function that generates the noise in one loop:
function generateNoise() {
let noiseGenerator = new neutrino.NoiseGenerator();
while (!noiseGenerator.step()) { // approx. 5,000 steps
// you can use 'noiseGenerator.progress' to get generating progress from 0.0 to 1.0
}
}
Of course, this function will block execution of the script until finished. So, it's up to you how to make it executed over many frames if necessary.
On modern devices (and mobile as well) above function will be finished in up to 2 seconds.
Please, pay attention to
NoiseGenerator
object. It has to be out of scope after noise is generated to allow GC to free allocated memory.
Download noise
In case you don't want to generate noise texture for a some reason, you can distribute it pre-computed in a binary file with your application. This file is /bin/neutrinoparticles.noise.bin
in the repository.
Then download and initialize with:
neutrino.initializeNoise(
"/path/to/noise/directory/", // path to a directory where "neutrinoparticles.noise.bin" is located
function() {}, // success callback
function() {}, // fail callback
);
HTTP request will be used to download the file. It's size is 768Kb.
Restart effect
To completely restart the effect:
effect.restart(
[x, y, z], // (optional) new position, if changed
[x, y, z, w] // (optional) new rotation, if changed
);
Instant effect position change (teleporting)
When you move your effect by changing it's position or rotation on each update, the effect is moved linearly. And even if it tightly generates particles, there will be a trail of particles from previous frame position to the new one.
In case, you want to change position instantly (teleport it), you need to reset position:
effect.resetPosition(
[x, y, z], // new effect's position (pass null if you don't want to reset position)
[x, y, z, w] // new effect's rotation quaternion (pass null if you don't want to reset rotation)
);
Number of particles
You can request total number of alive particles in topmost emitters (not attached to other emitters):
let numParticles = effect.getNumParticles();
Or request number of particles in a single emitter by name (note underscore before name):
let numEmitterParticles = effect._YourEmitterName.getNumParticles();
Using pause
There are two different kinds of pause for effect:
Pause for whole effect. When all particles freeze and nothing else is generated:
effect.pauseAllEmitters(); ... let isPaused = effect.areAllEmittersPaused(); ... effect.unpauseAllEmitters();
Generators pause. When already generated particles continue to live but new particles are not generated:
effect.pauseGeneratorsInAllEmitters(); ... let isGeneratorsPaused = effect.areGeneratorsInAllEmittersPaused(); ... effect.unpauseGeneratorsInAllEmitters();
Changing emitter's properties
You can control exposed emitter properties from your application. Any emitter property added on Emitter Scheme or Emitter Guide in the Editor is exposed in exported effect.
To change properties in a single emitter, you can access them directly from effect instance (note underscores before names):
effect._EmitterName._YourFloatPropertyName = 10;
effect._EmitterName._YourVector2PropertyName = [10, 20];
effect._EmitterName._YourVector3PropertyName = [10, 20, 30];
effect._EmitterName._YourRotationPropertyName = neutrino.axisangle2quat_([0, 1, 0], 45);
To change properties with a given names for all topmost emitters:
effect.setPropertyInAllEmitters("YourFloatPropertyName", 10);
effect.setPropertyInAllEmitters("YourVector2PropertyName", [10, 20]);
effect.setPropertyInAllEmitters("YourVector3PropertyName", [10, 20, 30]);
effect.setPropertyInAllEmitters("YourRotationPropertyName", neutrino.axisangle2quat_([0, 1, 0], 45));
For example, to control particles generating rate from your application:
1. In the Editor, in Emitter Guide
window, in Generation
section change type of Periodic rate
to Emitter property
Set up property name to
MyParticlesPerSecond
From
Emitters
window remember emitter name to access your propertyExport effect, and after loading in your application you can change the property:
effect._DefaultEmitter._MyParticlesPerSecond = 100;