Coder Social home page Coder Social logo

creativelifeform / three-nebula Goto Github PK

View Code? Open in Web Editor NEW
899.0 20.0 74.0 16.58 MB

WebGL based particle system engine for three.js

Home Page: https://three-nebula.org/

License: MIT License

JavaScript 94.51% Shell 0.14% HTML 1.92% CSS 0.30% SCSS 3.13%
webgl threejs particles javascript

three-nebula's People

Contributors

bendxr avatar dependabot[bot] avatar manthrax avatar masatomakino avatar rohan-deshpande avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

three-nebula's Issues

Question: Is there a way I can extend a running emitter's lifespan?

Use case: I have an emitter that runs for 10 seconds. I'd like to extend the life of it by another 10 seconds after it's already started. Not reset it but extend its lifespan after it's started. I've tried resetting age and totalEmitTimes to 0 but it doesn't seem to affect run time.

fromJSONAsync while adding three-nebula as a script tag

More a question than an Issue. How can I use fromJSONAsync in pure JS while three-nebula is added with HTML script tag?
I tried few different approach but everything fails:

1.

new System.fromJSONAsync(...

Uncaught ReferenceError: System is not defined

2.

new Nebula.fromJSONAsync(...

Uncaught TypeError: Nebula.fromJSONAsync is not a constructor

3.

system = new Nebula.default();
system.fromJSONAsync(...

Uncaught TypeError: system.fromJSONAsync is not a function

4.

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

Uncaught TypeError: system.fromJSONAsync is not a function

.
Other functions works fine. I can create emitter with particles through code and it works perfectly.

BTW. this library is really awesome :)

Move BehaviourEmitter functionality into base Emitter

There isn't really any reason to have a separate class for an emitter that can have behaviours applied to itself, so to achieve this

  • Add a property to the base emitter class called emitterBehaviours
  • Add methods for adding/removing emitter behaviours
  • Apply all emitter behaviours in the update method of the base emitter

After this you can remove the BehaviourEmitter class completely

Make Proton.destroy method more safe

Currently if you attempt to destroy while animating, bad things can happen because there is no guard to stop updates when destroy is called.

Also need to check to see if the emitter you are attempting to destroy exists before performing this operation.

Better implementation:

  update(delta = DEFAULT_PROTON_DELTA) {
    if (!this.canUpdate) { 
      return Promise.resolve();
    }

    const d = delta || DEFAULT_PROTON_DELTA;

    this.dispatch(PROTON_UPDATE);

    if (d > 0) {
      let i = this.emitters.length;

      while (i--) {
        this.emitters[i].update(d);
      }
    }

    this.dispatch(PROTON_UPDATE_AFTER);

    return Promise.resolve();
  }

  destroy() {
    this.canUpdate = false;
    const length = this.emitters.length;

    for (let i = 0; i < length; i++) {
      this.emitters[i] && this.emitters[i].destroy();
      delete this.emitters[i];
    }

    this.emitters.length = 0;
    this.pool.destroy();
    this.canUpdate = true;
  }

Performance improvements

I've been doing some performance analysis with chrome dev tools because fps was pretty low for my usage.

  1. PUID is really inefficient as it gets called a lot and iterate over the whole array of particles. Replacing the array with a Map looks like a better idea
export default {
    _id: 0,
    _uids: new Map(), //maps objects to IDs
    id: function (functionOrObject) {
        if (this._uids.has(functionOrObject))
            return this._uids.get(functionOrObject);

        const nid = 'PUID_' + this._id++;

        this._uids.set(functionOrObject, nid);

        return nid;
    }
};
  1. Setting rotation for Sprites in MeshRenderer consumes a lot of CPU for nothing... as rotating a Sprite has no effect (you need to rotate the material)
constructor(container, THREE) {
        [...]
        this._THREE = THREE;
    }
[...]
onParticleUpdate(particle) {
        if (particle.target) {
            particle.target.position.copy(particle.position);
            if (!(particle.target instanceof this._THREE.Sprite))
                particle.target.rotation.set(
                    particle.rotation.x,
                    particle.rotation.y,
                    particle.rotation.z
                );
            this.scale(particle);

            if (particle.useAlpha) {
                particle.target.material.opacity = particle.alpha;
                particle.target.material.transparent = true;
            }

            if (particle.useColor) {
                particle.target.material.color.copy(particle.color);
            }
        }
    }

(alternatively, could override the whole function in SpriteRenderer)

Could you fix these or do you need a PR @rohan-deshpande ?

Use consistent us_en spelling

Currently there is a mixture of US and correct English spellings in the lib, let's just settle on using the US spellings and deprecate the correct ones. I think the main offender here is behaviour vs behavior

perfomance vs SPE

spe CODE:

` var particleGroup = new SPE.Group({
texture: {
value: Resources.Load("resource/img/star.png").data
}
});

    var emitter = new SPE.Emitter({
        // maxAge: {
        //     value: 2
        // },
        // position: {
        //     value: new Vector3(0, 0, -50),
        //     spread: new Vector3(0, 0, 0)
        // },

        // acceleration: {
        //     value: new Vector3(0, -10, 0),
        //     spread: new Vector3(10, 0, 10)
        // },

        velocity: {
            value: new Vector3(0, 0, 0),
            spread: new Vector3(100, 75, 100)
        },

        color: {
            randomise:true,
            // value: [new Color('white'), new Color('red')]
        },

        size: {
            value: 100
        },
        alive:0.25,
        particleCount: 10,
    });

    particleGroup.addEmitter(emitter);
    scene.add(particleGroup.mesh);

    render.proton = particleGroup;`

Nebula GPURender code:
` private createNormalNebula(render: SceneRenderGroup, scene: Scene) {

    let proton = new Nebula.System();
    render.proton = proton
    proton.addEmitter(this.createNebulaEmitter());
    //    proton.addRenderer(new Nebula.SpriteRenderer(scene, THREE));
    //@ts-ignore
    proton.addRenderer(new Nebula.GPURenderer(scene, THREE));
}


private createNebulaEmitter() {
    let emitter = new Nebula.Emitter();
    emitter.rate = new Nebula.Rate(10, 0.25);
    // emitter.addInitializer(new Nebula.Mass(1));
    emitter.addInitializer(new Nebula.Radius(100));
    emitter.addInitializer(new Nebula.Life(2));
    emitter.addInitializer(new Nebula.Body(this.createSprite()));
    emitter.addInitializer(new Nebula.Position(new Nebula.BoxZone(100)));
    // emitter.addInitializer(new Nebula.RadialVelocity(200, new Nebula.Vector3D(0, 1, 1), 180));

    // //emitter.addBehaviour(new Proton.RandomDrift(30, 30, 30, .05));
    emitter.addBehaviour(new Nebula.Rotate("random", "random"));
    emitter.addBehaviour(new Nebula.Scale(0.75));
    // emitter.addBehaviour(new Nebula.Alpha(1));

    //emitter.addBehaviour(new Proton.CrossZone(zone2, "bound"));
    //emitter.addBehaviour(new Proton.Collision(emitter,true));
    emitter.addBehaviour(new Nebula.Color(0xff0000, 'random', Infinity));

    emitter.emit();
    return emitter;
}

private createSprite() {
    var map = Resources.Load("resource/img/dot.png").data
    var material = new SpriteMaterial({
        map: map,
        color: 0xff0000,
    });
    return new Sprite(material);
}

`
result:

SPE faster

Nebula
image

SPE
image

any idea to imporve it?

"Nebula.System.update( delta )" affects particle position.

Expected Behavior

Reproduced particle position even if System.update(delta) changes in a variable frame rate environment.

Actual Behavior

When System.update(delta) changes, the particle position not reproduced.

Steps to Reproduce the Problem

  1. get delta time from timestamp of requestAnimationFrame.
  2. Nebula.System.update( delta );
  3. If dropped frames, the position of the particles changes.

codepen

Here is the sample code.
Anyone can change the DELTA_COEFFICIENT value.

delta = 0.0167 (DEFAULT_SYSTEM_DELTA)

delta = 0.00551

Why

Nebula.Emitter.damping is not corrected by delta time.

integrate() function.

Velocity and Acceleration corrected by delta time.

In the sample code, if you change FIX_DAMPING = true, the particle positions will be reproduced.

Specifications

  • Version: three-nebula v5.0.1 + three.js r108
  • Platform: macOS 10.14.6
  • Subsystem: Google Chrome 77.0.3865.90

GPURenderer transparent vs non-transparent texture issue

Currently non transparent textures will be given background colours when the GPURenderer is used in a three WebGLRenderer alpha: true context.

Screen Shot 2020-11-20 at 7 32 58 am

^ Notice how every texture other than the middle one has a black square background.

This can be "solved" in two ways. Firstly, turn alpha: true off for the WebGLRenderer. Not ideal, as the user may want to have a transparent canvas.

Secondly, we could change the fragment shader gl_FragColor calculation from

gl_FragColor = gl_FragColor * texture2D(uTexture, uv)

to

gl_FragColor = gl_FragColor * texture2D(uTexture, uv).rgbr

However this borks transparent textures

Screen Shot 2020-11-20 at 9 04 25 am

^ Notice how the middle texture looks completely different now to the first image.

We do need to support both, so for now, we will leave things as is and ask users to do alpha: false if they are using non transparent textures, saying the alternative is not supported right now.

GPURenderer breaking with [email protected]

The GPURenderer is breaking in [email protected] with the following error

THREE.WebGLProgram: shader error:  0 35715 false gl.getProgramInfoLog invalid shaders�  THREE.WebGLShader: gl.getShaderInfoLog() fragment
ERROR: 0:97: 'texture' : function name expected
�1: #version 300 es
2: #define varying in
3: out highp vec4 pc_fragColor;
4: #define gl_FragColor pc_fragColor
5: #define gl_FragDepthEXT gl_FragDepth
6: #define texture2D texture
7: #define textureCube texture
8: #define texture2DProj textureProj
9: #define texture2DLodEXT textureLod
10: #define texture2DProjLodEXT textureProjLod
11: #define textureCubeLodEXT textureLod
12: #define texture2DGradEXT textureGrad
13: #define texture2DProjGradEXT textureProjGrad
14: #define textureCubeGradEXT textureGrad
15: precision highp float;
16: precision highp int;
17: #define HIGH_PRECISION
18: #define SHADER_NAME ShaderMaterial
19: #define GAMMA_FACTOR 2
20: uniform mat4 viewMatrix;
21: uniform vec3 cameraPosition;
22: uniform bool isOrthographic;
23: 
24: vec4 LinearToLinear( in vec4 value ) {
25: 	return value;
26: }
27: vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {
28: 	return vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );
29: }
30: vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {
31: 	return vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );
32: }
33: vec4 sRGBToLinear( in vec4 value ) {
34: 	return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );
35: }
36: vec4 LinearTosRGB( in vec4 value ) {
37: 	return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
38: }
39: vec4 RGBEToLinear( in vec4 value ) {
40: 	return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );
41: }
42: vec4 LinearToRGBE( in vec4 value ) {
43: 	float maxComponent = max( max( value.r, value.g ), value.b );
44: 	float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );
45: 	return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );
46: }
47: vec4 RGBMToLinear( in vec4 value, in float maxRange ) {
48: 	return vec4( value.rgb * value.a * maxRange, 1.0 );
49: }
50: vec4 LinearToRGBM( in vec4 value, in float maxRange ) {
51: 	float maxRGB = max( value.r, max( value.g, value.b ) );
52: 	float M = clamp( maxRGB / maxRange, 0.0, 1.0 );
53: 	M = ceil( M * 255.0 ) / 255.0;
54: 	return vec4( value.rgb / ( M * maxRange ), M );
55: }
56: vec4 RGBDToLinear( in vec4 value, in float maxRange ) {
57: 	return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );
58: }
59: vec4 LinearToRGBD( in vec4 value, in float maxRange ) {
60: 	float maxRGB = max( value.r, max( value.g, value.b ) );
61: 	float D = max( maxRange / maxRGB, 1.0 );
62: 	D = clamp( floor( D ) / 255.0, 0.0, 1.0 );
63: 	return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );
64: }
65: const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );
66: vec4 LinearToLogLuv( in vec4 value ) {
67: 	vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;
68: 	Xp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );
69: 	vec4 vResult;
70: 	vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
71: 	float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
72: 	vResult.w = fract( Le );
73: 	vResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;
74: 	return vResult;
75: }
76: const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );
77: vec4 LogLuvToLinear( in vec4 value ) {
78: 	float Le = value.z * 255.0 + value.w;
79: 	vec3 Xp_Y_XYZp;
80: 	Xp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );
81: 	Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
82: 	Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
83: 	vec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;
84: 	return vec4( max( vRGB, 0.0 ), 1.0 );
85: }
86: vec4 linearToOutputTexel( vec4 value ) { return LinearToLinear( value ); }
87: 
88: 
89:     uniform vec3 baseColor;
90:     uniform sampler2D texture;
91: 
92:     varying vec3 targetColor;
93:     varying float targetAlpha;
94: 
95:     void main() {
96:       gl_FragColor = vec4(baseColor * targetColor, targetAlpha);
97:       gl_FragColor = gl_FragColor * texture2D(texture, gl_PointCoord);
98:     }
99: 

Sprite Rotation

Is there any way to initialize and/or animate Sprite rotation?
Looks like the only way is changing the material.rotation property and Nebula.Rotate is changing the Sprite rotation which has no effect with three.js

Instantiating from JSON needs to set null to Infinity

For systems that are instantiated from JSON, all properties which can be Infinity need to check if the input value is null and if so, set it to Infinity

For behaviours, you can easily set a fallback in the abstract Behaviour constructor:

    /**
     * @desc The life of the behaviour
     * @type {number}
     */
    this.life = life || Infinity;

For emitters, you can set a fallback within the emit method

  emit(totalEmitTimes = Infinity, life = Infinity) {
    this.currentEmitTime = 0;
    this.totalEmitTimes = totalEmitTimes || Infinity;

    if (totalEmitTimes === 1) {
      this.life = totalEmitTimes;
    } else {
      this.life = life || Infinity;
    }

    this.rate.init();

    return this;
  }

Async solution needed for loading the system from JSON

The particle system needs to load asynchronously so that textures can be readied before the system starts. Not doing so causes the following issue to occur

image

The square renders happen because the particle texture hasn't loaded yet. The fromJSONAsync method was an attempt to solve this, but using it causes a three error to occur.

Plan of action should be

  • Port the fromJSONAsync method to the main branch and mark it as experimental, also exclude it from code coverage for now
  • Debug why this method is causing three to throw errors
  • Write tests for it and take it out of experimental status

Nebula.Color: Passing 0 as a color value causes a crash.

Version: 4.0.1.

Adding a Color behaviour to an emitter with 0 or 0x0 as a colour causes it to crash:
TypeError: Cannot read property 'getValue' of null.
0x000001 works.

Reason:
In src/math/ColorSpan.js Line 60 - you check if you have a colours object. 0 will return false therefore returning null.

Support material blending options

The BodySprite.fromJSON method currently isn't going to really work for changes to blending options as the blending key requires a specific three constant (which is a number) to be set.

In order to achieve this, you'll need a way to map strings to these constant such as

withBlendingConstantSetFromString = materialProperties => ({ ...materialProperties, blending: THREE[materialProperties.blending] });

You should call this within the fromJSON method but you should also create a new constant DEFAULT_JSON_MATERIAL_PROPERTIES which has the blending key set to a string for consistency

Update window.System to window.Nebula in docs for script tag usage, window.System is no longer defined

Hey there,

trying to use the script tag as per the documentation at the bottom of the main github page of three-nebula (see minimum working example below), but it leads to this error:

Firefox: "Uncaught TypeError: window.System is undefined"
Edge: "Uncaught TypeError: Cannot destructure property 'System' of 'window.System' as it is undefined."

This is the example code I am testing:

<html>
<head><title>Test</title></head>
<body>
    <script type='text/javascript' src="js/three.js"></script>
    <script type='text/javascript' src='js/three-nebula.js'></script>
    <script>
        const { System, Emitter, Rate, Span } = window.System;
        const system = new System();
    </script>
</body>

I am a hobby programmer, so there is probably something obvious I am missing - however, I cant find it.

The three.js implementation works without issues, the script files are definitely accessible.

Any help would be appreciated :)

MeshZone currently does not support BufferGeometry

MeshZone will currently break if a mesh's geometry is a BufferGeometry due to these geoms not having a vertices property which is accessed directly in the getPosition method of the class

  getPosition() {
    var vertices = this.geometry.vertices;
    var rVector = vertices[(vertices.length * Math.random()) >> 0];

    this.vector.x = rVector.x * this.scale;
    this.vector.y = rVector.y * this.scale;
    this.vector.z = rVector.z * this.scale;

    return this.vector;
  }

Seems like BufferGeometry stores its vertices in a different place ie., for the mesh it'll be at mesh.geometry.attributes.position.array

Move examples/docs site to create-react-app

The examples are getting to be a real pain to manage in terms of development as we are duplicating code all over the place. Updating them and adding new ones is simply not going to scale.

Moving them to be managed inside a single app with a module like system will make things a great deal easier.

Babel is causing issues with the PointsRenderer example

Very weird and hard to solve issue, it seems the latest version of babel is causing issues with the points renderer example where performance slows to a crawl while rendering. The issue arose in 28c9357 where babel was upgraded to 7.8.4 from 7.5.0.

Currently, commenting out the following lines from the webpack config (ie., removing babel entirely) seems to resolve the issue

      {
        test: /(\.jsx|\.js)$/,
        loader: 'babel-loader',
        exclude: /(node_modules)/,
      },

Doing this and then running

npm run build
cd website 
rm -rf node_modules/three-nebula
npm run link-src
npm run dev

And navigating to http://localhost:3000/examples/point-zone will show that the example is working as normal. If you run it with babel-loader the example grinds to a halt.

I've tried upgrading all babel dependencies to see if the issue has been subsequently fixed, but it seems it is still a problem.

Obviously I'd love to be able to solve this from the library's source code itself, but it's really hard right now to know exactly what is causing it. This could be related to babel/babel#11356

Right now there's a few options

  • Downgrade babel back to when it worked
  • Try to find whatever is causing this issue in the source code and fix it
  • Try to figure out what transformer in preset-env is causing the issue
  • If the linked babel issue is the problem, then dropping IE11 support would mean that the lib wouldn't need to transform ES6 classes into functions and dropping support would mean that this transformer could be excluded

Consider renaming

The library has diverged from the fork quite a bit now, might be a good time to rename it as it is kind of its own beast.

Possible names

  • three-neutron (kind of an homage to where this lib came from)
  • three-nebula

Will add more if I think of any

Request : Please make the Behaviour class public

Current behavior

The Behaviour class is not accessible from the public. And the Behaviour class cannot be extended.

Expected behavior

The Behaviour class is accessible from the public.

Motivation / Use Case

Third party developers will be able to create custom behaviors.

Background

Currently, the Color behavior in three-nebula has two variables, ColorA and ColorB.

I want to set the transparency to a more granular level. For this reason, I have prototyped a custom behavior with the color of the Canvas element as a variable.

https://github.com/MasatoMakino/three-nebula-behaviour-plugin
https://masatomakino.github.io/three-nebula-behaviour-plugin/demo/

This is a color behavior with canvas elements and png images as variables.

This prototype works in 5.1.0 and does not work in 5.1.1.

Why it doesn't work

This prototype is a custom class that extends the Behavior class in the src directory.

From this commit, the src folder has been removed from the npm package.
That's why I can't extend the Behavior class from src/behaviour/Behaviour.js.

Additional information

If getEasingByName() and SUPPORTED_JSON_BEHAVIOUR_TYPES are public, third party developers can customize the fromJson() function.

However, the public SUPPORTED_JSON_BEHAVIOUR_TYPES has a Side effects. If the behavior has a duplicate TYPE, fromJson will not work. You can't limit what TYPE to third party developers.

I've thought of several ideas. They are not the best, but I hope they will help you.

  1. keep SUPPORTED_JSON_BEHAVIOUR_TYPES private.
  2. make the function for registering TYPE.

Environment

macOS 10.15.2
three-nebula 5.1.0 - 5.1.1
webpack 4.43.0

Thank you.

three.nebula.js containing a copy of all three.js code makes three.js included twice in webpack bundle

Hi, I have noticed that since three-nebula package has a dependency on three.js, bundling applications that also have root dependencies to three.js causes three.js library to be included twice in the final bundle, one for the depedency on three-nebula and one for root dependencies on three.js.

Considering for example the following package.json dependencies:

"dependencies": {
    "three": "^0.104.0",
    "three-nebula": "^4.0.3",
  },

And the following js file:

import { Scene, PerspectiveCamera, Mesh } from "three"

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

Building this file using WebPack results in a file of 1.4 MB (threejs library packed alone is about 650 KB).

To include three.js only once in the bundle, the thing that works for me was to modify the file three-nebula/src/core/three.js to point directly to the root package ./node_modules/three/build/three.module.js (instead of ./node_modules/three-nebula/node_modules/three) and make imports from ./node_modules/three-nebula/src/index.js instead.
In that case the final bundle size is around 800 KB.

Replace Pool with deepool

The core/Pool class is pretty confusing. I don't really like the API. After having a look for other JavaScript object pool implementations, I found https://www.npmjs.com/package/deepool which has a nice, simple API.

Here's how the change would have to work

  • The main Proton instance will need to have a particlePool property set, this will be set like this.particlePool = deepool.create(() => new Particle()) you could also consider moving this to being a property of the Emitter instance
  • Inside the emitter's createParticle method, you can then simply call this.parent or this.particlePool.use()
  • Then instead of the expire method, simply call this.particlePool.recycle(particle.reset())

This should really be all there is to it. There'll be similar changes to be done inside the zones/MeshRenderer class and any others that use the core/Pool class.

v2.0.0

Here's a bunch of things that should be done as part of the v2.0.0 release

  • Remove all behaviour reset methods and move logic to the constructors. I don't see a reason for these methods at all as they are not called internally anywhere and they are just making the API more confusing than it needs to be (Descoped, while I think these are a bit unnecessary, happy to leave this as it is for now)
  • Fix initializer/Position constructor and function doc blocks so they do not have argument mismatches
  • Fix up all TODO comments (Resolved by #26)
  • Create Proton.fromJSON static method that can create an entire system from JSON (Resolved by #21)
  • Remove all methods which use the initialize suffix. These have been replaced by methods that use the initializer suffix (Resolved by #20)
  • Remove the renderer/*Render compatibility classes, remove all methods which use the render suffix. These have been replaced by methods that use the renderer suffix (Resolved by #20)
  • Create VectorVelocity initializer and port tests (Resolved by #22)
  • Create RadialVelocity initializer and port tests (Resolved by #22)
  • Create PolarVelocity initializer and port tests (Resolved by #22)
  • Rename name property on all classes to type to align with three. Create a utility method to set the type on the class to the constructor name
  • Update p, v, and a, props on the Particle class to position, velocity, acceleration in the interest of self documenting code (Resolved by #25)
  • Rename math/ArraySpan to math/ColorSpan, remove the color specific stuff from math/ArraySpan, it simply returns a random item from its internal array, it shouldn't have specific color logic in it (Resolved by #23)
  • Replace core/Pool with deePool (descoped, see #16)
  • Replace events/EventDispatcher with EventEmitter (descoped, see #17)
  • Set the integrator as a property on the core Proton instance and reference this in the emitter via this.parent.integrator (Resolved by #21)

Add more stuff to npmignore

You need the following things to be ignored by npm, right now the package size is huge and codesandbox is complaining

docs/
scripts/
src/
test/
website/

Port to ES6/7

Shouldn't be too hard to do, but let's port this to a modern format. Let's add

  • webpack
  • eslint config
  • .babelrc
  • .editorconfig

Test coverage

  • All particle behaviours
  • All particle initializers
  • core/Proton
  • core/Particle
  • core/Pool
  • emitter/Emitter

Sprite.geometry seems to get cached

When creating new Sprite() particles with modified geometry (UV coordinates) the system seems to cache the geometry. Subsequent new particles will use the existing modified geometry. We're using a sprite sheet so need to modify UVs to apply the correct texture to the sprite.

Performance issues appear when used in create-react-app

Currently this is a bit of a mystery to me but when including three-nebula in a create-react-app app - performance seems to be significantly impacted. The issue can be rectified by including the lib in a script tag rather than as a dependency.

If included as a dependency via npm install three-nebula, GPU rendered systems which clock in at a rock solid 60FPS normally are maxing out at 40FPS.

If the lib is included as a script tag in public/index.html and Nebula is accessed via the window everything is fine.

Perhaps this is related to #94. You can't modify the babel config in CRA apps without ejecting so that solution is not going to work.

Ideally what would have to happen would be to investigate what function in particular was causing the issue and fix it.

image (5)

@manthrax has done some investigating and noticed that the performance profiles for an identical system look totally different in the different environments.

Note that this doesn't seem to be happening in the GPURenderer example for an app built with next so it more than likely is something odd in the create-react-app config.

Instantiate three geometries when hydrating mesh zones from JSON

As highlighted here, there needs to be some extra logic and steps in the Position initialiser to detect if the intention is to instantiate a MeshZone for this to work the following needs to happen in the Position.fromJSON method

  • Detect if the zone is a MeshZone
  • If so, extract a geometryType prop from the provided JSON
  • Instantiate the correct three geometry from this prop and other provided props
  • Pass this geometry to the zone constructor as its first argument

You will need to choose a range of three geometries to support, there's a bunch of cool ones that could give some pretty cool shapes to the particle systems.

Add API and event for detecting when a particle system has reached EOL

Right now there is no way for a dependent application to know when a particle system has reached its end of life, that is, when all of its emitters’ particles are dead = true.

This of course can never happen if any of the emitters have their life set to Infinity so this needs to be considered when creating the API.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.