Giter Club home page Giter Club logo

shaderparticleengine's Introduction

ShaderParticleEngine

A GLSL-focused particle engine for THREE.js. Removes a lot of the heavy lifting away from the CPU and onto the GPU to save precious rendering time in busy scenes.

Pull requests and issue reports welcome. Please see the notes on pull requests at the end of this document.

Version 0.8.2

  • Fix for when a camera is at vec3(0,0,0).

Breaking Changes

  • Version 0.8.0 The inclusion of fog support might break previous versions of THREE.js. I've tested with r69 and r65 and it does seem to be okay, but try to use THREE.js r71+ where possible.

  • Version 0.7.9 The transparent option/property of SPE.Group must be passed as a Boolean (true / false). It would previously accept numeric values (0 for false, 1 for true), but this has been deprecated due to a change in the way THREE.js r71 handles the transparent property in materials.

  • Version 0.7.4 There's a change in the way the total number of particles an emitter has is calculated, and one emitter option rename:

    • SPE.Emitter#particlesPerSecond is now SPE.Emitter#particleCount.
      • Rather than specifying how many particles an emitter will produce per second, you now specify the total number of particles yourself.
    • Renamed SPE.Emitter#emitterDuration to SPE.Emitter#duration.
  • Version 0.7.3 has renamed and added a lot of emitter options. Opacity, color, size, and angle are now consistent. They all have *Start, *Middle, and *End varients, as well as *StartSpread, *MiddleSpread, and *EndSpread varients. As an example:

    • opacityStart, opacityStartSpread,
    • opacityMiddle, opacityMiddleSpread,
    • opacityEnd, opacityEndSpread.
  • Version 0.7.2 packages up the emitter objects (Group, Emitter, utils) into one namespace: SPE.

    • To create a particle group from v0.7.2+: new SPE.Group( ... ).
    • To create a particle emitter from v0.7.2+: new SPE.Emitter( ... ).

About

After experimenting with Stemkoski's particle engine, I was having trouble getting high numbers of particles to render at ~60fps. After digging into the code and doing some benchmarks, it was clear that the bottleneck was coming from applying each particle's movement parameters (velocity += acceleration, and position += velocity). After moving these calculations to the shaders the performance was drastically increased.

Another optimisation I wanted was to be able to 'group' lots of emitters into one THREE.ParticleSystem, so that if I had (for example) 20 particle emitters sharing the same texture, I could send all 20 of those emitters to the GPU at the same time via sharing the same geometry. This is where the basis for the ShaderParticleGroup comes from.

This project requires THREE.js revision 71+. Assuming future THREE.js versions don't remove certain methods without warning of deprecation, it should be future-proof to a certain extent.

Usage

See the ./examples/ folder (or here) for some simple demos.

Assuming you have a basic scene set up using THREE.js and have added the JS to your page, adding a particle emitter is as simple as the following code:

// Create a particle group to add the emitter to.
var particleGroup = new SPE.Group({
	// Give the particles in this group a texture
	texture: THREE.ImageUtils.loadTexture('path/to/your/texture.file'),

	// How long should the particles live for? Measured in seconds.
	maxAge: 5
});

// Create a single emitter
var particleEmitter = new SPE.Emitter({
	type: 'cube',
	position: new THREE.Vector3(0, 0, 0),
	acceleration: new THREE.Vector3(0, 10, 0),
	velocity: new THREE.Vector3(0, 15, 0),
	particlesPerSecond: 100,
	sizeStart: 10,
	sizeEnd: 0,
	opacityStart: 1,
	opacityEnd: 0,
	colorStart: new THREE.Color('blue'),
	colorEnd: new THREE.Color('white')
});

// Add the emitter to the group.
particleGroup.addEmitter( particleEmitter );

// Add the particle group to the scene so it can be drawn.
scene.add( particleGroup.mesh ); // Where `scene` is an instance of `THREE.Scene`.

// ...

// In your frame render function:
// 	Where dt is the time delta
// 	(the time it took to render the last frame.)
particleGroup.tick( dt );

API

####SPE.Group options:####

// All possible parameters for the SPE.Group constructor.
// - Default values for each key are as given below if the key is [OPTIONAL].
var particleGroup = new SPE.Group({

	// [REQUIRED] Give the particles in this group a texture.
	texture: THREE.ImageUtils.loadTexture('path/to/your/texture.file'),

	// [OPTIONAL] How long should the particles live for? Measured in seconds.
	maxAge: 3,

	// [OPTIONAL] Should the particles have perspective applied when drawn?
	hasPerspective: true,

	// [OPTIONAL] Should the particles in this group have a color applied?
	colorize: true,

	// [OPTIONAL] What blending style should be used?
	// THREE.NoBlending
	// THREE.NormalBlending
	// THREE.AdditiveBlending
	// THREE.SubtractiveBlending
	// THREE.MultiplyBlending
	blending: THREE.AdditiveBlending,

	// [OPTIONAL] Should transparency be applied?
	// As of 0.7.9+, this property can only be of type Boolean. Numeric
	// values will not be accepted and `transparent` value will default to
	// true.
	transparent: true,

	// [OPTIONAL] What threshold should be used to test the alpha channel?
	alphaTest: 0.5,

	// [OPTIONAL] Should this particle group be written to the depth buffer?
	depthWrite: false,

	// [OPTIONAL] Should a depth test be performed on this group?
	depthTest: true,

	// [OPTIONAL] Specify a fixed time-step value if you're more bothered
	// about smooth performance. Only use this if necessary. Measured in seconds.
	fixedTimeStep: 0.016,

	// [OPTIONAL] Whether this group should be affected by Fog.
	fog: true
});

####SPE.Emitter settings:

// All possible parameters for the SPE.Emitter constructor
// - Default values for each key are as given below if the key is [OPTIONAL]
var particleEmitter = new SPE.Emitter({

	// [OPTIONAL] Emitter shape.
	// 	'cube', 'sphere', or 'disk'
	// 		When using 'sphere' or 'disk' shape, use `radius` and `speed` parameters.
	// 		When using 'cube' shape, use `acceleration` and `velocity` parameters.
	type: 'cube',


	// [OPTIONAL] Base position for the emitter. Can be changed over time.
	position: new THREE.Vector3(0, 0, 0),

	// [OPTIONAL] Particle start position variance.
	positionSpread: new THREE.Vector3(0, 0, 0),


	// [OPTIONAL] Acceleration base vector.
	acceleration: new THREE.Vector3(0, 0, 0),

	// [OPTIONAL] Acceleration variance.
	accelerationSpread: new THREE.Vector3(0, 0, 0),


	// [OPTIONAL] Velocity base vector.
	velocity: new THREE.Vector3(0, 0, 0),

	// [OPTIONAL] Velocity variance.
	velocitySpread: new THREE.Vector3(0, 0, 0),


	// [OPTIONAL - Sphere type] Starting position radius.
	radius: 10,

	// [OPTIONAL - Sphere type] Starting position radius scale.
	radiusScale: new THREE.Vector3(1, 1, 1),

	// [OPTIONAL - Sphere type] Particle speed.
	speed: 0,

	// [OPTIONAL - Sphere type] Particle speed variance.
	speedSpread: 0,


	// [OPTIONAL] Particle start size.
	sizeStart: 10,

	// [OPTIONAL] Particle start size variance.
	sizeStartSpread: 0,

	// [OPTIONAL] Particle middle size.
	// If not specified, it will be set to halfway between the
	// `sizeStart` and `sizeEnd` values.
	sizeMiddle: 10,

	// [OPTIONAL] Particle middle size variance.
	sizeMiddleSpread: 0,

	// [OPTIONAL] Particle end size.
	sizeEnd: 10,

	// [OPTIONAL] Particle end size variance.
	sizeEndSpread: 0,


	// [OPTIONAL] Particle rotation start angle (radians).
	angleStart: 0,

	// [OPTIONAL] Particle rotation start angle spread (radians).
	angleStartSpread: 0,

	// [OPTIONAL] Particle rotation middle angle (radians).
	angleMiddle: 0,

	// [OPTIONAL] Particle rotation middle angle spread (radians).
	angleMiddleSpread: 0,

	// [OPTIONAL] Particle rotation end angle (radians).
	angleEnd: 0,

	// [OPTIONAL] Particle rotation end angle spread (radians).
	angleEndSpread: 0,

	// [OPTIONAL] Align particle angle along its velocity vector
	// If this property is set to `true`, then all other angle properties
	// are ignored.
	angleAlignVelocity: false,


	// [OPTIONAL] Particle start colour.
	colorStart: new THREE.Color( 'white' ),

	// [OPTIONAL] Particle start colour variance.
	colorStartSpread: new THREE.Vector3(0, 0, 0),

	// [OPTIONAL] Particle middle colour.
	// If not specified, it will be set to halfway between the
	// `colorStart` and `colorEnd` values.
	colorMiddle: new THREE.Color( 'white' ),

	// [OPTIONAL] Particle middle colour variance.
	colorMiddleSpread: new THREE.Vector3(0, 0, 0),

	// [OPTIONAL] Particle end colour.
	colorEnd: new THREE.Color( 'blue' ),

	// [OPTIONAL] Particle end colour variance.
	colorEndSpread: new THREE.Vector3(0, 0, 0),



	// [OPTIONAL] Particle start opacity.
	opacityStart: 1,

	// [OPTIONAL] Particle start opacity variance.
	opacityStartSpread: 0,

	// [OPTIONAL] Particle middle opacity.
	// The opacity value at half a particle's lifecycle.
	// If not specified, it will be set to halfway between the
	// `opacityStart` and `opacityEnd` values.
	opacityMiddle: 0.5,

	// [OPTIONAL] Particle middle opacity variance.
	opacityMiddleSpread: 0,

	// [OPTIONAL] Particle end opacity.
	opacityEnd: 0,

	// [OPTIONAL] Particle end opacity variance.
	opacityEndSpread: 0,


	// [OPTIONAL] The number of particles emitted per second.
	particlesPerSecond: 100,

	// [OPTIONAL] Emitter duration. Measured in seconds.
	// 	A null value indicates an infinite duration.
	emitterDuration: null,

	// [OPTIONAL] What percentage of `particleCount` particles should be emitted?
	// 0 being no particles, 1 being 100% of `particleCount`.
	alive: 1.0,

	// [OPTIONAL] New in v0.4.0. If you want a huge amount of particles, and
	// they aren't going to be moving, then set this property to `1`. This will
	// take the start values for color, opacity, and size (with spreads applied),
	// not add the emitter from its group's tick function, and so will be static.
	// See the static.html file in the examples directory for more.
	isStatic: 0
});

####"Public" Methods for SPE.Group:####

- .addEmitter( emitter ) Adds an instance of SPE.Emitter to the particle group.

- .tick( dt ) Call this function once per frame. If no dt argument is given, the SPE.Group instance will use its .fixedTimeStep value as dt.

- .addPool( numEmitters, emitterSettings, createNewEmitterIfPoolRunsOut ) Automatically create a pool of emitters for easy triggering in the future.

- .triggerPoolEmitter( numEmittersToActivate, positionVector ) Turn on a given number of emitters that live in a pool created using the method above. You can also pass a THREE.Vector3 instance to dictate where this emitter will sit.

Changelog

Version 0.8.1

  • Further speed improvements to the GLSL code. It's now running a few milliseconds quicker, which will make all the difference in busy scenes.

Version 0.8.0

  • A big one: almost all parameters of an emitter can now be changed at runtime. Position, velocity, acceleration, speed, opacity, color, size, and angle, including all their relative spread properties, are all supported. This was an often requested feature and I'm happy to announce support for it. Big thanks to all the testers.
  • SPE.Group#hasPerspective now takes boolean values as well as numbers. Makes more sense this way.
  • SPE.Group#colorize now takes boolean values as well as numbers as well.
  • SPE.Group#colorize does not ignore opacity values if set to false.
  • SPE.Group#fog is now supported! Note: Only tested with THREE.js r71.

Version 0.7.9

  • Fixed an issue with THREE.js r71. See breaking changes notes directly below. Please update if you're planning to use THREE.js r71+.

Version 0.7.8

  • Hot-fix for when no particles are due to be emitted during a given frame, a particle's age might be set to NaN. Please update if you're using 0.7.7!

Version 0.7.7

  • Implemented a fix for emitters not smoothly emitting when frame rates aren't completely stable. Hopefully if you happen to have an issue with emitters not looking as 'smooth' as they should, and some particles are clumping together, then try updating to this version and it should make the situation a little bit better.

Version 0.7.6

  • Renamed THREE.ParticleSystem to THREE.PointCloud
  • Fully tested on THREE r69.
  • Ensured references to SPE.Emitter#particleCount are correct in all example files.

Version 0.7.5

  • SPE.Emitter#alive: Values between 0 and 1 now control the percentage of particles that are alive at a given moment. If you have an emitter with a particleCount of 1000 and you set alive to be 0.1, only 100 particles will be emitted (1000 * 0.1 === 100).

Version 0.7.4

  • The latest release has jumped from 0.5.1 to 0.7.4. There are no release versions in between - the party was all on the dev branch. A full log of the changes between these versions is available in the changelog towards the end of this document. There have been a lot of changes since 0.5.1, so if you're updating, please check the Breaking Changes and Changelog to play catchup.

  • In between 0.5.1 and 0.7.4, there have been some contributions from the community to the library:

    • @DelvarWorld) has kindly brought this library into a much fitter state than it was before, and feature contributions from @stemkoski) have been combined into the 0.7.4 release.
  • Deprecated SPE.Emitter#particlesPerSecond in favour of SPE.Emitter#particleCount.

  • Renamed SPE.Emitter#emitterDuration to SPE.Emitter#duration.

Version 0.7.3

  • Added the following properties:
    • sizeEndSpread, opacityEndSpread, colorEndSpread
    • sizeMiddleSpread, opacityMiddleSpread, colorMiddleSpread
    • angleStart (replaces angle), angleStartSpread,
    • angleMiddle, angleMiddleSpread,
    • angleEnd, angleEndSpread

Version 0.7.2

  • Moved ShaderParticleGroup, ShaderParticleEmitter, and shaderParticleUtils to a shared object. SPE.Group, SPE.Emitter, and SPE.utils respectively.

Version 0.7.1

  • Changed the attribute model. Size attributes, opacity attributes, and angle attributes are all squashed into shared attributes using various vector types.
  • Added sizeMiddle functionality.

Version 0.7.0

  • new ShaderParticleUtils object (alpha) to share functions between the Group and Emitter constructors.
  • ShaderParticleGroup.removeEmitter()
  • ShaderParticleEmitter.angle
  • ShaderParticleEmitter.angleAlignVelocity

Version 0.6.0

  • To adjust particle sizes, please use sizeStart instead of the old size property.
  • Particle angles are now supported, thanks to Stemkoski.

Version 0.5.1

  • Fixed some issues with parseFloat and accidental globals. Thanks to DelvarWorld for noticing these.

Version 0.5.0

  • The latest update sees the addition of the ShaderParticleGroup.addPool() method. This allows for much easier control of emitter pools. See the pool example for an example.
  • There are also quite a few bug fixes courtesy of Stemkoski.
  • I've also added quite a few more comments to the source-code, so it should be easier to get your head around should you want/need to dig into the internals.

Building

This project uses Grunt to create the distributions, one dev build (not minimized) and one production build (minimized). If you make changes and want to build it, follow these steps:

If you don't have grunt installed, first make sure you've got NodeJS and NPM installed, then install Grunt CLI. You might have to do this as root:

npm install -g grunt-cli

Now you can install the local grunt package:

cd [projectFolder] && npm install && grunt

The output of grunt will sit in the build folder.

Known Bugs

  • There is an issue using SPE.Emitter#angleAlignVelocity if your emitter isn't positioned at origin (0, 0, 0). This is being investigated.

See the issues page for any known other bugs. Please open an issue if you find anything not behaving properly.

Submitting Pull Requests

Just a couple of notes about submitting pull requests:

  • Indentation: 4 spaces.
  • Whitespace: No trailing whitespace.
  • JSHint: If you can, please run JSHint over your forked copy before submitting to make sure there are no common mistakes.
  • Description: Please provide a full description of your changes.
  • Comments: Follow existing commenting conventions.
  • Parentheses: 1 space before and after parentheses.
  • A .jsbeautifyrc file is included for easy formatting.

Thanks :)

Thanks

Huge thanks are extended to Stemkoski for his initial particle engine, and to Mr Doob, AlteredQualia, et. al for their awesome work on THREE.js.

shaderparticleengine's People

Contributors

squarefeet avatar stemkoski avatar andrewraycode avatar brianchirls avatar

Watchers

James Cloos avatar J.D.Song avatar

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.