dorkhub

three-nebula

WebGL based particle system engine for three.js

creativelifeform
JavaScript1.2k93 forksMITupdated 1 day ago
visit the demogit clone https://github.com/creativelifeform/three-nebula.gitcreativelifeform/three-nebula

react-router

    three-nebula

    WebGL based 3D particle system engine for three

    


CHANGELOG

Three Nebula is a WebGL based 3D particle engine that has been designed to work alongside three.js. Check out the website, examples, the quickstart sandbox and API reference documentation for more.

Features

  • Built and tested against three@0.185.1; supports three >=0.122.0 <1.0.0
  • The ability to instantiate three-nebula particle systems from JSON objects
  • The ability to create particle systems from sprites as well as 3D meshes
  • Many kinds of particle behaviours and initializers

Installation

npm

npm i --save three-nebula

script

<script type='text/javascript' src='node_modules/three-nebula/dist/three-nebula.umd.js'></script>

Usage

three-nebula ships ES module, CommonJS and UMD builds and declares three as a peer dependency, so install both alongside each other:

npm i --save three three-nebula

It works with any bundler (Vite, webpack, Rollup) or straight from a <script> tag — see the examples below. However you build a system, the one thing to remember is to drive it from your render loop by calling system.update() once per frame; nothing animates until you do. For runnable, self-contained examples of every renderer, see the sandbox.

Module

import * as THREE from 'three';

import System, {
  SpriteRenderer,
  Emitter,
  Rate,
  Span,
  Position,
  Mass,
  Radius,
  Life,
  RadialVelocity,
  Vector3D,
  Alpha,
  Scale,
  Color,
  PointZone,
} from 'three-nebula';

const system = new System();
const renderer = new SpriteRenderer(threeScene, THREE);
const emitter = new Emitter();

// Set emitter rate (particles per second) as well as the particle initializers and behaviours
emitter
  .setRate(new Rate(new Span(4, 16), new Span(0.01)))
  .setInitializers([
    new Position(new PointZone(0, 0)),
    new Mass(1),
    new Radius(6, 12),
    new Life(3),
    new RadialVelocity(45, new Vector3D(0, 1, 0), 180),
  ])
  .setBehaviours([
    new Alpha(1, 0),
    new Scale(0.1, 1.3),
    new Color(new THREE.Color(0xff0000), new THREE.Color(0x0000ff)),
  ])
  .emit();

// add the emitter and a renderer to your particle system
system
  .addRenderer(renderer)
  .addEmitter(emitter)
  .emit({
    onStart: () => {},
    onUpdate: () => {},
    onEnd: () => {},
  });

// drive the system from your render loop
const animate = () => {
  system.update();
  requestAnimationFrame(animate);
};
requestAnimationFrame(animate);

You can also instantiate your system from a JSON object

import System from 'three-nebula';

const json = {
  preParticles: 500,
  integrationType: 'euler',
  emitters: [
    {
      rate: {
        particlesMin: 5,
        particlesMax: 7,
        perSecondMin: 0.01,
        perSecondMax: 0.02,
      },
      position: {
        x: 70,
        y: 0,
      },
      initializers: [
        {
          type: 'Mass',
          properties: {
            min: 1,
            max: 1,
          },
        },
        {
          type: 'Life',
          properties: {
            min: 2,
            max: 2,
          },
        },
        {
          type: 'BodySprite',
          properties: {
            texture: './img/dot.png',
          },
        },
        {
          type: 'Radius',
          properties: {
            width: 80,
            height: 80,
          },
        },
      ],
      behaviours: [
        {
          type: 'Alpha',
          properties: {
            alphaA: 1,
            alphaB: 0,
          },
        },
        {
          type: 'Color',
          properties: {
            colorA: '#4F1500',
            colorB: '#0029FF',
          },
        },
        {
          type: 'Scale',
          properties: {
            scaleA: 1,
            scaleB: 0.5,
          },
        },
        {
          type: 'Force',
          properties: {
            fx: 0,
            fy: 0,
            fz: -20,
          },
        },
      ],
    },
    {
      rate: {
        particlesMin: 5,
        particlesMax: 7,
        perSecondMin: 0.01,
        perSecondMax: 0.02,
      },
      position: {
        x: -70,
        y: 0,
      },
      initializers: [
        {
          type: 'Mass',
          properties: {
            min: 1,
            max: 1,
          },
        },
        {
          type: 'Life',
          properties: {
            min: 2,
            max: 2,
          },
        },
        {
          type: 'BodySprite',
          properties: {
            texture: './img/dot.png',
          },
        },
        {
          type: 'Radius',
          properties: {
            width: 80,
            height: 80,
          },
        },
      ],
      behaviours: [
        {
          type: 'Alpha',
          properties: {
            alphaA: 1,
            alphaB: 0,
          },
        },
        {
          type: 'Color',
          properties: {
            colorA: '#004CFE',
            colorB: '#6600FF',
          },
        },
        {
          type: 'Scale',
          properties: {
            scaleA: 1,
            scaleB: 0.5,
          },
        },
        {
          type: 'Force',
          properties: {
            fx: 0,
            fy: 0,
            fz: -20,
          },
        },
      ],
    },
  ],
};

System.fromJSONAsync(json, THREE).then(system => {
  console.log(system);
});

Script Tag

If you are adding three-nebula to your project in the script tag, the only difference to the above example is how you access the classes you need. You can do that like so

const { System, Emitter, Rate, Span } = window.Nebula;
const system = new System();

Development

Sandbox

The sandbox in ./sandbox is a small collection of visual experiments for testing and playing with library changes — the kind of barebones examples that make it easy to dig into a rendering issue or try something new. The experiments aren't permanent; they get added and removed over time.

Run it with

npm run sandbox

This serves the sandbox with Vite (defaults to http://localhost:5000, falling back to the next free port). Pick an experiment from the index page.

Each experiment is a small ES module — there's no build config to think about. Vite resolves three, three/addons/* and three-nebula by name, and three-nebula is aliased to the library source, so editing the library hot-reloads the sandbox with no separate build step.

Adding an experiment is just two files under sandbox/experiments/<name>/.

index.html — the shared styles, a canvas inside an #app container (the harness mounts its FPS panel there and the styles size the canvas), and a module entry point:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="/style/reset.css" />
    <link rel="stylesheet" href="/style/app.css" />
  </head>
  <body>
    <div id="app">
      <canvas id="canvas"></canvas>
    </div>
    <script type="module" src="./index.js"></script>
  </body>
</html>

index.js — build a system and hand it to run:

import * as THREE from 'three';
import System, { Emitter, SpriteRenderer /* … */ } from 'three-nebula';
import { run } from '/common/run.js';

const init = async ({ scene, camera, renderer }) => {
  const system = new System();
  // … set up emitters, initializers and behaviours …
  return system.addRenderer(new SpriteRenderer(scene, THREE));
};

run(init);

run (in sandbox/common/) sets up the scene, camera, renderer and animation loop, calls your init with { scene, camera, renderer }, and drives system.update() every frame — so an experiment only has to describe the system it wants to see.

License

MIT

more like this

lottery

🎉🌟✨🎈年会抽奖程序,基于 Express + Three.js的 3D 球体抽奖程序,奖品🧧🎁,文字,图片,抽奖规则均可配置,😜抽奖人员信息Excel一键导入😍,抽奖结果Excel导出😎,给你的抽奖活动带来全新酷炫体验🚀🚀🚀

JavaScript4.6k

search

search projects, people, and tags