瀏覽代碼

Merge pull request #3562 from sebavan/master

Particle System Update
sebavan 7 年之前
父節點
當前提交
5099e295ac

+ 9 - 1
.vscode/settings.json

@@ -11,7 +11,15 @@
         "**/node_modules": true,
         "**/temp": true,
         "**/.temp": true,
-        "**/*.d.ts": true,
+        "src/**/*.d.ts": true,
+        "gui/**/*.d.ts": true,
+        "inspector/**/*.d.ts": true,
+        "loaders/**/*.d.ts": true,
+        "materialsLibrary/**/*.d.ts": true,
+        "postProcessesLibrary/**/*.d.ts": true,
+        "proceduralTexturesLibrary/**/*.d.ts": true,
+        "serielazers/**/*.d.ts": true,
+        "viewer/**/*.d.ts": true,
         "**/*.js.map": true,
         "**/*.js.fx": true,
         "**/*.js": { 

文件差異過大導致無法顯示
+ 0 - 1544
dist/preview release/typedocValidationBaseline.json


+ 23 - 1
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,20 +1,38 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
+    /**
+     * This is a camera specifically designed to react to device orientation events such as a modern mobile device 
+     * being tilted forward or back and left or right.
+     */
     export class DeviceOrientationCamera extends FreeCamera {
 
         private _initialQuaternion: Quaternion;
         private _quaternionCache: Quaternion;
 
+        /**
+         * Creates a new device orientation camera. @see DeviceOrientationCamera
+         * @param name The name of the camera
+         * @param position The starts position camera
+         * @param scene The scene the camera belongs to
+         */
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
             this._quaternionCache = new Quaternion();
             this.inputs.addDeviceOrientation();
         }
 
+        /**
+         * Gets the current instance class name ("DeviceOrientationCamera").
+         * This helps avoiding instanceof at run time.
+         * @returns the class name
+         */
         public getClassName(): string {
             return "DeviceOrientationCamera";
         }
 
+        /**
+         * Checks and applies the current values of the inputs to the camera. (Internal use only)
+         */
         public _checkInputs(): void {
             super._checkInputs();
             this._quaternionCache.copyFrom(this.rotationQuaternion);
@@ -23,7 +41,11 @@ module BABYLON {
             }
         }
 
-        public resetToCurrentRotation(axis: Axis = Axis.Y) {
+        /**
+         * Reset the camera to its default orientation on the specified axis only.
+         * @param axis The axis to reset
+         */
+        public resetToCurrentRotation(axis: Axis = Axis.Y): void {
             //can only work if this camera has a rotation quaternion already.
             if (!this.rotationQuaternion) return;
 

+ 51 - 6
src/Particles/babylon.boxParticleEmitter.ts

@@ -1,52 +1,97 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a box.
+     * It emits the particles randomly between 2 given directions. 
+     */
     export class BoxParticleEmitter implements IParticleEmitterType {
 
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public get direction1(): Vector3 {
             return this._particleSystem.direction1;
         }
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public set direction1(value: Vector3) {
             this._particleSystem.direction1 = value;
         }
 
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public get direction2(): Vector3 {
             return this._particleSystem.direction2;
         }
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public set direction2(value: Vector3) {
             this._particleSystem.direction2 = value;
         }
 
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public get minEmitBox(): Vector3 {
             return this._particleSystem.minEmitBox;
         }
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public set minEmitBox(value: Vector3) {
             this._particleSystem.minEmitBox = value;
         }
 
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public get maxEmitBox(): Vector3 {
             return this._particleSystem.maxEmitBox;
         }
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public set maxEmitBox(value: Vector3) {
             this._particleSystem.maxEmitBox = value;
         }
         
         // to be updated like the rest of emitters when breaking changes.
         // all property should be come public variables and passed through constructor.
+        /**
+         * Creates a new instance of @see BoxParticleEmitter
+         * @param _particleSystem the particle system associated with the emitter
+         */
         constructor(private _particleSystem: ParticleSystem) {
 
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.direction1.x, this.direction2.x);
-            var randY = ParticleSystem.randomNumber(this.direction1.y, this.direction2.y);
-            var randZ = ParticleSystem.randomNumber(this.direction1.z, this.direction2.z);
+            var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+            var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+            var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
 
             Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.minEmitBox.x, this.maxEmitBox.x);
-            var randY = ParticleSystem.randomNumber(this.minEmitBox.y, this.maxEmitBox.y);
-            var randZ = ParticleSystem.randomNumber(this.minEmitBox.z, this.maxEmitBox.z);
+            var randX = Scalar.RandomRange(this.minEmitBox.x, this.maxEmitBox.x);
+            var randY = Scalar.RandomRange(this.minEmitBox.y, this.maxEmitBox.y);
+            var randZ = Scalar.RandomRange(this.minEmitBox.z, this.maxEmitBox.z);
 
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }

+ 77 - 10
src/Particles/babylon.coneParticleEmitter.ts

@@ -1,29 +1,96 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a cone.
+     * It emits the particles alongside the cone volume from the base to the particle. 
+     * The emission direction might be randomized.
+     */
     export class ConeParticleEmitter implements IParticleEmitterType {
-        constructor(public radius: number, public angle: number) {
+        private _radius: number;
+        private _height: number;
+
+        /**
+         * Gets the radius of the emission cone.
+         */
+        public get radius(): number {
+            return this._radius;
+        }
+
+        /**
+         * Sets the radius of the emission cone.
+         */
+        public set radius(value: number) {
+            this._radius = value;
+            if (this.angle !== 0) {
+                this._height = value / Math.tan(this.angle / 2);
+            }
+            else {
+                this._height = 1;
+            }
+        }
+
+        /**
+         * Creates a new instance of @see ConeParticleEmitter
+         * @param radius the radius of the emission cone
+         * @param angles the cone base angle
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         */
+        constructor(radius: number, 
+            /**
+             * The radius of the emission cone.
+             */
+            public angle: number, 
+            /**
+             * The cone base angle.
+             */
+            public directionRandomizer = 0) {
+            this.radius = radius;
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             if (this.angle === 0) {
                 Vector3.TransformNormalFromFloatsToRef(0, emitPower, 0, worldMatrix, directionToUpdate);
             }
             else {
-                var phi = ParticleSystem.randomNumber(0, 2 * Math.PI);
-                var theta = ParticleSystem.randomNumber(0, this.angle);
-                var randX = Math.cos(phi) * Math.sin(theta);
-                var randY = Math.cos(theta);
-                var randZ = Math.sin(phi) * Math.sin(theta);
-                Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+                // measure the direction Vector from the emitter to the particle.
+                var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
+                var randX = Scalar.RandomRange(0, this.directionRandomizer);
+                var randY = Scalar.RandomRange(0, this.directionRandomizer);
+                var randZ = Scalar.RandomRange(0, this.directionRandomizer);
+                direction.x += randX;
+                direction.y += randY;
+                direction.z += randZ;
+                direction.normalize();
+
+                Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
             }
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var s = ParticleSystem.randomNumber(0, Math.PI * 2);
-            var radius = ParticleSystem.randomNumber(0, this.radius);
+            var s = Scalar.RandomRange(0, Math.PI * 2);
+            var h = Scalar.RandomRange(0, 1);
+            // Better distribution in a cone at normal angles.
+            h = 1 - h * h;
+            var radius = Scalar.RandomRange(0, this._radius);
+            radius = radius * h / this._height;
+
             var randX = radius * Math.sin(s);
             var randZ = radius * Math.cos(s);
+            var randY = h;
 
-            Vector3.TransformCoordinatesFromFloatsToRef(randX, 0, randZ, worldMatrix, positionToUpdate);
+            Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
     }
 }

+ 72 - 7
src/Particles/babylon.gpuParticleSystem.ts

@@ -1,10 +1,34 @@
 module BABYLON {
+    /**
+     * This represents a GPU particle system in Babylon.
+     * This os the fastest particle system in Babylon as it uses the GPU to update the individual particle data.
+     */
     export class GPUParticleSystem implements IDisposable, IParticleSystem {
-        // Members
+        /**
+         * The id of the Particle system.
+         */
         public id: string;
-        public emitter: Nullable<AbstractMesh | Vector3> = null;       
-        public renderingGroupId = 0;        
+
+        /**
+         * The friendluname of the Particle system.
+         */
+        public name: string;
+
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
+        public emitter: Nullable<AbstractMesh | Vector3> = null;
+
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
+        public renderingGroupId = 0;
+
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         public layerMask: number = 0x0FFFFFFF; // TODO
+
         private _capacity: number;
         private _renderEffect: Effect;
         private _updateEffect: Effect;
@@ -29,24 +53,41 @@
 
         /**
         * An event triggered when the system is disposed.
-        * @type {BABYLON.Observable}
         */
         public onDisposeObservable = new Observable<GPUParticleSystem>();
 
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
         public isStarted(): boolean {
             return this._started;
-        }     
+        }
 
+        /**
+         * Starts the particle system and begins to emit.
+         */
         public start(): void {
             this._started = true;
         }
 
+        /**
+         * Stops the particle system.
+         */
         public stop(): void {
             this._started = false;
-        }        
+        }
 
-        constructor(public name: string, capacity: number, scene: Scene) {
+        /**
+         * Instantiates a GPU particle system.
+         * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+         * @param name The name of the particle system
+         * @param capacity The max number of particles alive at the same time
+         * @param scene The scene the particle system belongs to
+         */
+        constructor(name: string, capacity: number, scene: Scene) {
             this.id = name;
+            this.name = name;
             this._scene = scene || Engine.LastCreatedScene;
             this._capacity = capacity;
             this._engine = this._scene.getEngine();
@@ -72,6 +113,9 @@
             this._updateEffect = new Effect("gpuUpdateParticles", updateEffectOptions, this._scene.getEngine());   
         }
 
+        /**
+         * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
+         */
         public animate(): void {
             // Do nothing
         }
@@ -126,6 +170,10 @@
             this._targetBuffer = this._renderBuffer;
         }
 
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         public render(): number {
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
@@ -178,10 +226,16 @@
             return 0;
         }
 
+        /**
+         * Rebuilds the particle system
+         */
         public rebuild(): void {
             
         }
 
+        /**
+         * Disposes the particle system and free the associated resources.
+         */
         public dispose(): void {
             var index = this._scene.particleSystems.indexOf(this);
             if (index > -1) {
@@ -196,10 +250,21 @@
         }
 
         //TODO: Clone / Parse / serialize
+
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         public clone(name: string, newEmitter: any): Nullable<GPUParticleSystem> {
             return null;
         }
 
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         public serialize(): any {
         }
     }

+ 18 - 0
src/Particles/babylon.iParticleEmitterType.ts

@@ -1,6 +1,24 @@
 module BABYLON {
+    /**
+     * Particle emitter represents a volume emitting particles.
+     * This is the responsibility of the implementation to define the volume shape like cone/sphere/box.
+     */
     export interface IParticleEmitterType {
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void;
+
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void;
     }
 }

+ 56 - 1
src/Particles/babylon.particle.ts

@@ -1,19 +1,66 @@
 module BABYLON {
 
+    /**
+     * A particle represents one of the element emitted by a particle system.
+     * This is mainly define by its coordinates, direction, velocity and age.
+     */
     export class Particle {
+        /**
+         * The world position of the particle in the scene.
+         */
         public position = Vector3.Zero();
+
+        /**
+         * The world direction of the particle in the scene.
+         */
         public direction = Vector3.Zero();
+
+        /**
+         * The color of the particle.
+         */
         public color = new Color4(0, 0, 0, 0);
+
+        /**
+         * The color change of the particle per step.
+         */
         public colorStep = new Color4(0, 0, 0, 0);
+
+        /**
+         * Defines how long will the life of the particle be.
+         */
         public lifeTime = 1.0;
+
+        /**
+         * The current age of the particle.
+         */
         public age = 0;
+
+        /**
+         * The current size of the particle.
+         */
         public size = 0;
+
+        /**
+         * The current angle of the particle.
+         */
         public angle = 0;
+
+        /**
+         * Defines how fast is the angle changing.
+         */
         public angularSpeed = 0;
 
-        private _currentFrameCounter = 0;
+        /**
+         * Defines the cell index used by the particle to be rendered from a sprite.
+         */
         public cellIndex: number = 0;
 
+        private _currentFrameCounter = 0;
+
+        /**
+         * Creates a new instance of @see Particle
+         * @param particleSystem the particle system the particle belongs to
+         */
         constructor(private particleSystem: ParticleSystem) {
             if (!this.particleSystem.isAnimationSheetEnabled) {
                 return;
@@ -29,6 +76,10 @@
             }
         }
 
+        /**
+         * Defines how the sprite cell index is updated for the particle. This is 
+         * defined as a callback.
+         */
         public updateCellIndex: (scaledUpdateSpeed: number) => void;
 
         private updateCellIndexWithSpeedCalculated(scaledUpdateSpeed: number): void {
@@ -63,6 +114,10 @@
             }
         }
 
+        /**
+         * Copy the properties of particle to another one.
+         * @param other the particle to copy the information to.
+         */
         public copyTo(other: Particle) {
             other.position.copyFrom(this.position);
             other.direction.copyFrom(this.direction);

+ 375 - 80
src/Particles/babylon.particleSystem.ts

@@ -1,94 +1,321 @@
 module BABYLON {
+    /**
+     * Interface representing a particle system in Babylon.
+     * This groups the common functionalities that needs to be implemented in order to create a particle system.
+     * A particle system represents a way to manage particles (@see Particle) from their emission to their animation and rendering.
+     */
     export interface IParticleSystem {
+        /**
+         * The id of the Particle system.
+         */
         id: string;
+        /**
+         * The name of the Particle system.
+         */
         name: string;
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
         emitter: Nullable<AbstractMesh | Vector3>;
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
         renderingGroupId: number;
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         layerMask: number;
+        /**
+         * Gets if the particle system has been started.
+         * @return true if the system has been started, otherwise false.
+         */
         isStarted(): boolean;
+        /**
+         * Animates the particle system for this frame.
+         */
         animate(): void;
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         render(): number;
+        /**
+         * Dispose the particle system and frees its associated resources.
+         */
         dispose(): void;
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         clone(name: string, newEmitter: any): Nullable<IParticleSystem>;
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         serialize(): any;
-
+        /**
+         * Rebuild the particle system
+         */
         rebuild(): void
     }
 
+    /**
+     * This represents a particle system in Babylon.
+     * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+     * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
+     * @example https://doc.babylonjs.com/babylon101/particles
+     */
     export class ParticleSystem implements IDisposable, IAnimatable, IParticleSystem {
-        // Statics
+        /**
+         * Source color is added to the destination color without alpha affecting the result.
+         */
         public static BLENDMODE_ONEONE = 0;
+        /**
+         * Blend current color and particle color using particle’s alpha.
+         */
         public static BLENDMODE_STANDARD = 1;
 
-        // Members
+        /**
+         * List of animations used by the particle system.
+         */
         public animations: Animation[] = [];
 
+        /**
+         * The id of the Particle system.
+         */
         public id: string;
+
+        /**
+         * The friendly name of the Particle system.
+         */
+        public name: string;
+
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
         public renderingGroupId = 0;
+
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
         public emitter: Nullable<AbstractMesh | Vector3> = null;
+
+        /**
+         * The density of particles, the rate of particle flow
+         */
         public emitRate = 10;
+
+        /**
+         * If you want to launch only a few particles at once, that can be done, as well.
+         */
         public manualEmitCount = -1;
+
+        /**
+         * The overall motion speed (0.01 is default update speed, faster updates = faster animation)
+         */
         public updateSpeed = 0.01;
+
+        /**
+         * The amount of time the particle system is running (depends of the overall speed above).
+         */
         public targetStopDuration = 0;
+
+        /**
+         * Specifies whether the particle system will be disposed once it reaches the end of the animation.
+         */
         public disposeOnStop = false;
 
+        /**
+         * Minimum power of emitting particles.
+         */
         public minEmitPower = 1;
+        /**
+         * Maximum power of emitting particles.
+         */
         public maxEmitPower = 1;
 
+        /**
+         * Minimum life time of emitting particles.
+         */
         public minLifeTime = 1;
+        /**
+         * Maximum life time of emitting particles.
+         */
         public maxLifeTime = 1;
 
+        /**
+         * Minimum Size of emitting particles.
+         */
         public minSize = 1;
+        /**
+         * Maximum Size of emitting particles.
+         */
         public maxSize = 1;
+
+        /**
+         * Minimum angular speed of emitting particles (Z-axis rotation for each particle).
+         */
         public minAngularSpeed = 0;
+        /**
+         * Maximum angular speed of emitting particles (Z-axis rotation for each particle).
+         */
         public maxAngularSpeed = 0;
 
+        /**
+         * The texture used to render each particle. (this can be a spritesheet)
+         */
         public particleTexture: Nullable<Texture>;
 
+        /**
+         * The layer mask we are rendering the particles through.
+         */
         public layerMask: number = 0x0FFFFFFF;
 
+        /**
+         * This can help using your own shader to render the particle system.
+         * The according effect will be created 
+         */
         public customShader: any = null;
-        public preventAutoStart: boolean = false;
-
-        private _epsilon: number;
-
 
         /**
-        * An event triggered when the system is disposed.
-        * @type {BABYLON.Observable}
-        */
-        public onDisposeObservable = new Observable<ParticleSystem>();
-
-        private _onDisposeObserver: Nullable<Observer<ParticleSystem>>;
-        public set onDispose(callback: () => void) {
-            if (this._onDisposeObserver) {
-                this.onDisposeObservable.remove(this._onDisposeObserver);
-            }
-            this._onDisposeObserver = this.onDisposeObservable.add(callback);
-        }
+         * By default particle system starts as soon as they are created. This prevents the 
+         * automatic start to happen and let you decide when to start emitting particles.
+         */
+        public preventAutoStart: boolean = false;
 
+        /**
+         * This function can be defined to provide custom update for active particles.
+         * This function will be called instead of regular update (age, position, color, etc.).
+         * Do not forget that this function will be called on every frame so try to keep it simple and fast :)
+         */
         public updateFunction: (particles: Particle[]) => void;
+
+        /**
+         * Callback triggered when the particle animation is ending.
+         */
         public onAnimationEnd: Nullable<() => void> = null;
 
+        /**
+         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE or ParticleSystem.BLENDMODE_STANDARD.
+         */
         public blendMode = ParticleSystem.BLENDMODE_ONEONE;
 
+        /**
+         * Forces the particle to write their depth information to the depth buffer. This can help preventing other draw calls
+         * to override the particles.
+         */
         public forceDepthWrite = false;
 
+        /**
+         * You can use gravity if you want to give an orientation to your particles.
+         */
         public gravity = Vector3.Zero();
+
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public direction1 = new Vector3(0, 1.0, 0);
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         */
         public direction2 = new Vector3(0, 1.0, 0);
+
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public minEmitBox = new Vector3(-0.5, -0.5, -0.5);
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         */
         public maxEmitBox = new Vector3(0.5, 0.5, 0.5);
+
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
         public color1 = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
         public color2 = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * Color the particle will have at the end of its lifetime.
+         */
         public colorDead = new Color4(0, 0, 0, 1.0);
+
+        /**
+         * An optional mask to filter some colors out of the texture, or filter a part of the alpha channel.
+         */
         public textureMask = new Color4(1.0, 1.0, 1.0, 1.0);
+
+        /**
+         * The particle emitter type defines the emitter used by the particle system.
+         * It can be for example box, sphere, or cone...
+         */
         public particleEmitterType: IParticleEmitterType;
+
+        /**
+         * This function can be defined to specify initial direction for every new particle.
+         * It by default use the emitterType defined function.
+         */
         public startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle) => void;
+        /**
+         * This function can be defined to specify initial position for every new particle.
+         * It by default use the emitterType defined function.
+         */
         public startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle) => void;
 
-        private particles = new Array<Particle>();
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines if the sprite animation should loop between startSpriteCellID and endSpriteCellID or not.
+         */
+        public spriteCellLoop = true;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the speed of the sprite loop.
+         */
+        public spriteCellChangeSpeed = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the first sprite cell to display.
+         */
+        public startSpriteCellID = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled) and spriteCellLoop defines the last sprite cell to display.
+         */
+        public endSpriteCellID = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell width to use.
+         */
+        public spriteCellWidth = 0;
+        /**
+         * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell height to use.
+         */
+        public spriteCellHeight = 0;
+
+        /**
+        * An event triggered when the system is disposed.
+        */
+        public onDisposeObservable = new Observable<ParticleSystem>();
 
+        private _onDisposeObserver: Nullable<Observer<ParticleSystem>>;
+        /**
+         * Sets a callback that will be triggered when the system is disposed.
+         */
+        public set onDispose(callback: () => void) {
+            if (this._onDisposeObserver) {
+                this.onDisposeObservable.remove(this._onDisposeObserver);
+            }
+            this._onDisposeObserver = this.onDisposeObservable.add(callback);
+        }
+
+        /**
+         * Gets wether an animation sprite sheet is enabled or not on the particle system.
+         */
+        public get isAnimationSheetEnabled(): Boolean {
+            return this._isAnimationSheetEnabled;
+        }
+
+        private _particles = new Array<Particle>();
+        private _epsilon: number;
         private _capacity: number;
         private _scene: Scene;
         private _stockParticles = new Array<Particle>();
@@ -100,40 +327,38 @@
         private _effect: Effect;
         private _customEffect: Nullable<Effect>;
         private _cachedDefines: string;
-
         private _scaledColorStep = new Color4(0, 0, 0, 0);
         private _colorDiff = new Color4(0, 0, 0, 0);
         private _scaledDirection = Vector3.Zero();
         private _scaledGravity = Vector3.Zero();
         private _currentRenderId = -1;
-
         private _alive: boolean;
         private _started = false;
         private _stopped = false;
         private _actualFrame = 0;
         private _scaledUpdateSpeed: number;
-
-        // sheet animation
-        public startSpriteCellID = 0;
-        public endSpriteCellID = 0;
-        public spriteCellLoop = true;
-        public spriteCellChangeSpeed = 0;
-
-        public spriteCellWidth = 0;
-        public spriteCellHeight = 0;
         private _vertexBufferSize = 11;
+        private _isAnimationSheetEnabled: boolean;
 
-        public get isAnimationSheetEnabled(): Boolean {
-            return this._isAnimationSheetEnabled;
-        }
-        // end of sheet animation
-
-        constructor(public name: string, capacity: number, scene: Scene, customEffect: Nullable<Effect> = null, private _isAnimationSheetEnabled: boolean = false, epsilon: number = 0.01) {
+        /**
+         * Instantiates a particle system.
+         * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
+         * @param name The name of the particle system
+         * @param capacity The max number of particles alive at the same time
+         * @param scene The scene the particle system belongs to
+         * @param customEffect a custom effect used to change the way particles are rendered by default
+         * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
+         * @param epsilon Offset used to render the particles
+         */
+        constructor(name: string, capacity: number, scene: Scene, customEffect: Nullable<Effect> = null, isAnimationSheetEnabled: boolean = false, epsilon: number = 0.01) {
             this.id = name;
+            this.name = name;
+
             this._capacity = capacity;
 
             this._epsilon = epsilon;
-            if (_isAnimationSheetEnabled) {
+            this._isAnimationSheetEnabled = isAnimationSheetEnabled;
+            if (isAnimationSheetEnabled) {
                 this._vertexBufferSize = 12;
             }
 
@@ -214,8 +439,13 @@
             this._indexBuffer = this._scene.getEngine().createIndexBuffer(indices);
         }
 
+        /**
+         * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
+         * Its lifetime will start back at 0.
+         * @param particle The particle to recycle
+         */
         public recycleParticle(particle: Particle): void {
-            var lastParticle = <Particle>this.particles.pop();
+            var lastParticle = <Particle>this._particles.pop();
 
             if (lastParticle !== particle) {
                 lastParticle.copyTo(particle);
@@ -223,30 +453,49 @@
             }
         }
 
+        /**
+         * Gets the maximum number of particles active at the same time.
+         * @returns The max number of active particles.
+         */
         public getCapacity(): number {
             return this._capacity;
         }
 
+        /**
+         * Gets Wether there are still active particles in the system.
+         * @returns True if it is alive, otherwise false.
+         */
         public isAlive(): boolean {
             return this._alive;
         }
 
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
         public isStarted(): boolean {
             return this._started;
         }
 
+        /**
+         * Starts the particle system and begins to emit.
+         */
         public start(): void {
             this._started = true;
             this._stopped = false;
             this._actualFrame = 0;
         }
 
+        /**
+         * Stops the particle system.
+         */
         public stop(): void {
             this._stopped = true;
         }
 
-        // animation sheet
-
+        /**
+         * @ignore (for internal use only)
+         */
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
             var offset = index * this._vertexBufferSize;
             this._vertexData[offset] = particle.position.x;
@@ -262,8 +511,10 @@
             this._vertexData[offset + 10] = offsetY;
         }
 
+        /**
+         * @ignore (for internal use only)
+         */
         public _appendParticleVertexWithAnimation(index: number, particle: Particle, offsetX: number, offsetY: number): void {
-
             if (offsetX === 0)
                 offsetX = this._epsilon;
             else if (offsetX === 1)
@@ -291,9 +542,9 @@
 
         private _update(newParticles: number): void {
             // Update current
-            this._alive = this.particles.length > 0;
+            this._alive = this._particles.length > 0;
 
-            this.updateFunction(this.particles);
+            this.updateFunction(this._particles);
 
             // Add new ones
             var worldMatrix;
@@ -308,7 +559,7 @@
 
             var particle: Particle;
             for (var index = 0; index < newParticles; index++) {
-                if (this.particles.length === this._capacity) {
+                if (this._particles.length === this._capacity) {
                     break;
                 }
 
@@ -320,30 +571,30 @@
                     particle = new Particle(this);
                 }
 
-                this.particles.push(particle);
+                this._particles.push(particle);
 
-                var emitPower = ParticleSystem.randomNumber(this.minEmitPower, this.maxEmitPower);
+                var emitPower = Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
 
-                if (this.startDirectionFunction) {
-                    this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                if (this.startPositionFunction) {
+                    this.startPositionFunction(worldMatrix, particle.position, particle);
                 }
                 else {
-                    this.particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                    this.particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
                 }
 
-                if (this.startPositionFunction) {
-                    this.startPositionFunction(worldMatrix, particle.position, particle);
+                if (this.startDirectionFunction) {
+                    this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
                 }
                 else {
-                    this.particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
+                    this.particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
                 }
 
-                particle.lifeTime = ParticleSystem.randomNumber(this.minLifeTime, this.maxLifeTime);
+                particle.lifeTime = Scalar.RandomRange(this.minLifeTime, this.maxLifeTime);
 
-                particle.size = ParticleSystem.randomNumber(this.minSize, this.maxSize);
-                particle.angularSpeed = ParticleSystem.randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
+                particle.size = Scalar.RandomRange(this.minSize, this.maxSize);
+                particle.angularSpeed = Scalar.RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
 
-                var step = ParticleSystem.randomNumber(0, 1.0);
+                var step = Scalar.RandomRange(0, 1.0);
 
                 Color4.LerpToRef(this.color1, this.color2, step, particle.color);
 
@@ -394,6 +645,9 @@
             return this._effect;
         }
 
+        /**
+         * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
+         */
         public animate(): void {
             if (!this._started)
                 return;
@@ -457,17 +711,17 @@
 
             // Animation sheet
             if (this._isAnimationSheetEnabled) {
-                this.appendParticleVertexes = this.appenedParticleVertexesWithSheet;
+                this._appendParticleVertexes = this._appenedParticleVertexesWithSheet;
             }
             else {
-                this.appendParticleVertexes = this.appenedParticleVertexesNoSheet;
+                this._appendParticleVertexes = this._appenedParticleVertexesNoSheet;
             }
 
             // Update VBO
             var offset = 0;
-            for (var index = 0; index < this.particles.length; index++) {
-                var particle = this.particles[index];
-                this.appendParticleVertexes(offset, particle);
+            for (var index = 0; index < this._particles.length; index++) {
+                var particle = this._particles[index];
+                this._appendParticleVertexes(offset, particle);
                 offset += 4;
             }
 
@@ -476,22 +730,25 @@
             }
         }
 
-        public appendParticleVertexes: Nullable<(offset: number, particle: Particle) => void> = null;
+        private _appendParticleVertexes: Nullable<(offset: number, particle: Particle) => void> = null;
 
-        private appenedParticleVertexesWithSheet(offset: number, particle: Particle) {
+        private _appenedParticleVertexesWithSheet(offset: number, particle: Particle) {
             this._appendParticleVertexWithAnimation(offset++, particle, 0, 0);
             this._appendParticleVertexWithAnimation(offset++, particle, 1, 0);
             this._appendParticleVertexWithAnimation(offset++, particle, 1, 1);
             this._appendParticleVertexWithAnimation(offset++, particle, 0, 1);
         }
 
-        private appenedParticleVertexesNoSheet(offset: number, particle: Particle) {
+        private _appenedParticleVertexesNoSheet(offset: number, particle: Particle) {
             this._appendParticleVertex(offset++, particle, 0, 0);
             this._appendParticleVertex(offset++, particle, 1, 0);
             this._appendParticleVertex(offset++, particle, 1, 1);
             this._appendParticleVertex(offset++, particle, 0, 1);
         }
 
+        /**
+         * Rebuilds the particle system.
+         */
         public rebuild(): void {
             this._createIndexBuffer();
 
@@ -500,11 +757,15 @@
             }
         }
 
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles.
+         */
         public render(): number {
             var effect = this._getEffect();
 
             // Check
-            if (!this.emitter || !effect.isReady() || !this.particleTexture || !this.particleTexture.isReady() || !this.particles.length)
+            if (!this.emitter || !effect.isReady() || !this.particleTexture || !this.particleTexture.isReady() || !this._particles.length)
                 return 0;
 
             var engine = this._scene.getEngine();
@@ -547,12 +808,15 @@
                 engine.setDepthWrite(true);
             }
 
-            engine.drawElementsType(Material.TriangleFillMode, 0, this.particles.length * 6);
+            engine.drawElementsType(Material.TriangleFillMode, 0, this._particles.length * 6);
             engine.setAlphaMode(Engine.ALPHA_DISABLE);
 
-            return this.particles.length;
+            return this._particles.length;
         }
 
+        /**
+         * Disposes the particle system and free the associated resources.
+         */
         public dispose(): void {
             if (this._vertexBuffer) {
                 this._vertexBuffer.dispose();
@@ -580,18 +844,36 @@
             this.onDisposeObservable.clear();
         }
 
+        /**
+         * Creates a Sphere Emitter for the particle system. (emits along the sphere radius)
+         * @param radius The radius of the sphere to emit from
+         * @returns the emitter
+         */
         public createSphereEmitter(radius = 1): SphereParticleEmitter {
             var particleEmitter = new SphereParticleEmitter(radius);
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         }
 
+        /**
+         * Creates a Directed Sphere Emitter for the particle system. (emits between direction1 and direction2)
+         * @param radius The radius of the sphere to emit from
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @returns the emitter
+         */
         public createDirectedSphereEmitter(radius = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)): SphereDirectedParticleEmitter {
             var particleEmitter = new SphereDirectedParticleEmitter(radius, direction1, direction2)
             this.particleEmitterType = particleEmitter;
             return particleEmitter;
         }
 
+        /**
+         * Creates a Cone Emitter for the particle system. (emits from the cone to the particle position)
+         * @param radius The radius of the cone to emit from
+         * @param angle The base angle of the cone
+         * @returns the emitter
+         */
         public createConeEmitter(radius = 1, angle = Math.PI / 4): ConeParticleEmitter {
             var particleEmitter = new ConeParticleEmitter(radius, angle);
             this.particleEmitterType = particleEmitter;
@@ -599,6 +881,14 @@
         }
 
         // this method needs to be changed when breaking changes will be allowed to match the sphere and cone methods and properties direction1,2 and minEmitBox,maxEmitBox to be removed from the system.
+        /**
+         * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @param maxEmitBox  Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @returns the emitter
+         */
         public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter {
             var particleEmitter = new BoxParticleEmitter(this);
             this.direction1 = direction1;
@@ -609,18 +899,12 @@
             return particleEmitter;
         }
 
-        public static randomNumber(min: number, max: number): number {
-            if (min === max) {
-                return (min);
-            }
-
-            var random = Math.random();
-
-            return ((random * (max - min)) + min);
-        }
-
-
-        // Clone
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
         public clone(name: string, newEmitter: any): ParticleSystem {
             var custom: Nullable<Effect> = null;
             var program: any = null;
@@ -650,6 +934,10 @@
             return result;
         }
 
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
         public serialize(): any {
             var serializationObject: any = {};
 
@@ -711,6 +999,13 @@
             return serializationObject;
         }
 
+        /**
+         * Parses a JSON object to create a particle system.
+         * @param parsedParticleSystem The JSON object to parse
+         * @param scene The scene to create the particle system in
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the Parsed particle system
+         */
         public static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string): ParticleSystem {
             var name = parsedParticleSystem.name;
             var custom: Nullable<Effect> = null;

+ 216 - 112
src/Particles/babylon.solidParticle.ts

@@ -1,119 +1,223 @@
 module BABYLON {
-    
-        export class SolidParticle {
-            public idx: number = 0;                                             // particle global index
-            public color: Nullable<Color4> = new Color4(1.0, 1.0, 1.0, 1.0);    // color
-            public position: Vector3 = Vector3.Zero();                                   // position
-            public rotation: Vector3 = Vector3.Zero();                                   // rotation
-            public rotationQuaternion: Nullable<Quaternion>;                    // quaternion, will overwrite rotation
-            public scaling: Vector3 = Vector3.One();                                     // scaling
-            public uvs: Vector4 = new Vector4(0.0, 0.0, 1.0, 1.0);                       // uvs
-            public velocity: Vector3 = Vector3.Zero();                                   // velocity
-            public pivot: Vector3 = Vector3.Zero();                                      // pivot point in the particle local space
-            public alive: boolean = true;                                                // alive
-            public isVisible: boolean = true;                                            // visibility
-            public _pos: number = 0;                                            // index of this particle in the global "positions" array
-            public _ind: number = 0;                                            // index of this particle in the global "indices" array
-            public _model: ModelShape;                                          // model shape reference
-            public shapeId: number = 0;                                         // model shape id
-            public idxInShape: number = 0;                                      // index of the particle in its shape id
-            public _modelBoundingInfo: BoundingInfo;                            // reference to the shape model BoundingInfo object
-            public _boundingInfo: BoundingInfo;                                 // particle BoundingInfo
-            public _sps: SolidParticleSystem;                                   // reference to the SPS what the particle belongs to
-            public _stillInvisible: boolean = false;                            // still set as invisible in order to skip useless computations
-    
-            /**
-             * Creates a Solid Particle object.
-             * Don't create particles manually, use instead the Solid Particle System internal tools like _addParticle()
-             * `particleIndex` (integer) is the particle index in the Solid Particle System pool. It's also the particle identifier.  
-             * `positionIndex` (integer) is the starting index of the particle vertices in the SPS "positions" array.
-             * `indiceIndex` (integer) is the starting index of the particle indices in the SPS "indices" array.
-             * `model` (ModelShape) is a reference to the model shape on what the particle is designed.  
-             * `shapeId` (integer) is the model shape identifier in the SPS.
-             * `idxInShape` (integer) is the index of the particle in the current model (ex: the 10th box of addShape(box, 30))
-             * `modelBoundingInfo` is the reference to the model BoundingInfo used for intersection computations.
-             */
-            constructor(particleIndex: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
-                this.idx = particleIndex;
-                this._pos = positionIndex;
-                this._ind = indiceIndex;
-                this._model = <ModelShape>model;
-                this.shapeId = shapeId;
-                this.idxInShape = idxInShape;
-                this._sps = sps;
-                if (modelBoundingInfo) {
-                    this._modelBoundingInfo = modelBoundingInfo;
-                    this._boundingInfo = new BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
-                }
-            }
-    
-            /**
-             * legacy support, changed scale to scaling
-             */
-            public get scale(): Vector3 {
-                return this.scaling;
-            }
-    
-            public set scale(scale: Vector3) {
-                this.scaling = scale;
-            }
-    
-            /**
-             * legacy support, changed quaternion to rotationQuaternion
-             */ 
-            public get quaternion(): Nullable<Quaternion> {
-                return this.rotationQuaternion;
-            }
-    
-            public set quaternion(q: Nullable<Quaternion>) {
-                this.rotationQuaternion = q;
-            }
-    
-            /**
-             * Returns a boolean. True if the particle intersects another particle or another mesh, else false.
-             * The intersection is computed on the particle bounding sphere and Axis Aligned Bounding Box (AABB)
-             * `target` is the object (solid particle or mesh) what the intersection is computed against.
-             */
-            public intersectsMesh(target: Mesh | SolidParticle): boolean {
-                if (!this._boundingInfo || !target._boundingInfo) {
-                    return false;
-                }
-                if (this._sps._bSphereOnly) {
-                    return BoundingSphere.Intersects(this._boundingInfo.boundingSphere, target._boundingInfo.boundingSphere);
-                }
-                return this._boundingInfo.intersects(target._boundingInfo, false);
+    /**
+     * Represents one particle of a solid particle system.
+     * @see SolidParticleSystem
+     */
+    export class SolidParticle {
+        /**
+         * particle global index
+         */
+        public idx: number = 0;
+        /**
+         * The color of the particle
+         */
+        public color: Nullable<Color4> = new Color4(1.0, 1.0, 1.0, 1.0);
+        /**
+         * The world space position of the particle.
+         */
+        public position: Vector3 = Vector3.Zero();
+        /**
+         * The world space rotation of the particle. (Not use if rotationQuaternion is set)
+         */
+        public rotation: Vector3 = Vector3.Zero();
+        /**
+         * The world space rotation quaternion of the particle.
+         */
+        public rotationQuaternion: Nullable<Quaternion>;
+        /**
+         * The scaling of the particle.
+         */
+        public scaling: Vector3 = Vector3.One();
+        /**
+         * The uvs of the particle.
+         */
+        public uvs: Vector4 = new Vector4(0.0, 0.0, 1.0, 1.0);
+        /**
+         * The current speed of the particle.
+         */
+        public velocity: Vector3 = Vector3.Zero();
+        /**
+         * The pivot point in the particle local space.
+         */
+        public pivot: Vector3 = Vector3.Zero();
+        /**
+         * Is the particle active or not ?
+         */
+        public alive: boolean = true;
+        /**
+         * Is the particle visible or not ?
+         */
+        public isVisible: boolean = true;
+        /**
+         * Index of this particle in the global "positions" array (Internal use)
+         */
+        public _pos: number = 0;
+        /**
+         * Index of this particle in the global "indices" array (Internal use)
+         */
+        public _ind: number = 0;
+        /**
+         * ModelShape of this particle (Internal use)
+         */
+        public _model: ModelShape;
+        /**
+         * ModelShape id of this particle
+         */
+        public shapeId: number = 0;
+        /**
+         * Index of the particle in its shape id (Internal use)
+         */
+        public idxInShape: number = 0;
+        /**
+         * Reference to the shape model BoundingInfo object (Internal use)
+         */
+        public _modelBoundingInfo: BoundingInfo;
+        /**
+         * Particle BoundingInfo object (Internal use)
+         */
+        public _boundingInfo: BoundingInfo;
+        /**
+         * Reference to the SPS what the particle belongs to (Internal use)
+         */
+        public _sps: SolidParticleSystem;
+        /**
+         * Still set as invisible in order to skip useless computations (Internal use)
+         */
+        public _stillInvisible: boolean = false;
+
+        /**
+         * Creates a Solid Particle object.
+         * Don't create particles manually, use instead the Solid Particle System internal tools like _addParticle()
+         * @param particleIndex (integer) is the particle index in the Solid Particle System pool. It's also the particle identifier.  
+         * @param positionIndex (integer) is the starting index of the particle vertices in the SPS "positions" array.
+         * @param indiceIndex (integer) is the starting index of the particle indices in the SPS "indices" array.
+         * @param model (ModelShape) is a reference to the model shape on what the particle is designed.  
+         * @param shapeId (integer) is the model shape identifier in the SPS.
+         * @param idxInShape (integer) is the index of the particle in the current model (ex: the 10th box of addShape(box, 30))
+         * @param modelBoundingInfo is the reference to the model BoundingInfo used for intersection computations.
+         */
+        constructor(particleIndex: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
+            this.idx = particleIndex;
+            this._pos = positionIndex;
+            this._ind = indiceIndex;
+            this._model = <ModelShape>model;
+            this.shapeId = shapeId;
+            this.idxInShape = idxInShape;
+            this._sps = sps;
+            if (modelBoundingInfo) {
+                this._modelBoundingInfo = modelBoundingInfo;
+                this._boundingInfo = new BoundingInfo(modelBoundingInfo.minimum, modelBoundingInfo.maximum);
             }
         }
-    
-        export class ModelShape {
-            public shapeID: number;
-            public _shape: Vector3[];                   // flat array of model positions
-            public _shapeUV: number[];                  // flat array of model UVs
-            public _indicesLength: number = 0;          // length of the shape in the model indices array
-            public _positionFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>;
-            public _vertexFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>;
-    
-            /**
-             * Creates a ModelShape object. This is an internal simplified reference to a mesh used as for a model to replicate particles from by the SPS.
-             * SPS internal tool, don't use it manually.  
-             */
-            constructor(id: number, shape: Vector3[], indicesLength: number, shapeUV: number[], 
-                            posFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>, vtxFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>) {
-                this.shapeID = id;
-                this._shape = shape;
-                this._indicesLength = indicesLength;
-                this._shapeUV = shapeUV;
-                this._positionFunction = posFunction;
-                this._vertexFunction = vtxFunction;
+
+        /**
+         * Legacy support, changed scale to scaling
+         */
+        public get scale(): Vector3 {
+            return this.scaling;
+        }
+
+        /**
+         * Legacy support, changed scale to scaling
+         */
+        public set scale(scale: Vector3) {
+            this.scaling = scale;
+        }
+
+        /**
+         * Legacy support, changed quaternion to rotationQuaternion
+         */
+        public get quaternion(): Nullable<Quaternion> {
+            return this.rotationQuaternion;
+        }
+
+        /**
+         * Legacy support, changed quaternion to rotationQuaternion
+         */
+        public set quaternion(q: Nullable<Quaternion>) {
+            this.rotationQuaternion = q;
+        }
+
+        /**
+         * Returns a boolean. True if the particle intersects another particle or another mesh, else false.
+         * The intersection is computed on the particle bounding sphere and Axis Aligned Bounding Box (AABB)
+         * @param target is the object (solid particle or mesh) what the intersection is computed against.
+         * @returns true if it intersects
+         */
+        public intersectsMesh(target: Mesh | SolidParticle): boolean {
+            if (!this._boundingInfo || !target._boundingInfo) {
+                return false;
             }
+            if (this._sps._bSphereOnly) {
+                return BoundingSphere.Intersects(this._boundingInfo.boundingSphere, target._boundingInfo.boundingSphere);
+            }
+            return this._boundingInfo.intersects(target._boundingInfo, false);
         }
-    
-        export class DepthSortedParticle {
-            public ind: number = 0;                      // index of the particle in the "indices" array
-            public indicesLength: number = 0;            // length of the particle shape in the "indices" array
-            public sqDistance: number = 0.0;             // squared distance from the particle to the camera
+    }
+
+    /**
+     * Represents the shape of the model used by one particle of a solid particle system.
+     * SPS internal tool, don't use it manually.
+     * @see SolidParticleSystem
+     */
+    export class ModelShape {
+        /**
+         * The shape id.
+         */
+        public shapeID: number;
+        /**
+         * flat array of model positions (internal use)
+         */
+        public _shape: Vector3[];
+        /**
+         * flat array of model UVs (internal use)
+         */
+        public _shapeUV: number[];
+        /**
+         * length of the shape in the model indices array (internal use)
+         */
+        public _indicesLength: number = 0;
+        /**
+         * Custom position function (internal use)
+         */
+        public _positionFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>;
+        /**
+         * Custom vertex function (internal use)
+         */
+        public _vertexFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>;
+
+        /**
+         * Creates a ModelShape object. This is an internal simplified reference to a mesh used as for a model to replicate particles from by the SPS.
+         * SPS internal tool, don't use it manually.
+         * @ignore
+         */
+        constructor(id: number, shape: Vector3[], indicesLength: number, shapeUV: number[], 
+                        posFunction: Nullable<(particle: SolidParticle, i: number, s: number) => void>, vtxFunction: Nullable<(particle: SolidParticle, vertex: Vector3, i: number) => void>) {
+            this.shapeID = id;
+            this._shape = shape;
+            this._indicesLength = indicesLength;
+            this._shapeUV = shapeUV;
+            this._positionFunction = posFunction;
+            this._vertexFunction = vtxFunction;
         }
     }
-    
-    
-    
+
+    /**
+     * Represents a Depth Sorted Particle in the solid particle system.
+     * @see SolidParticleSystem
+     */
+    export class DepthSortedParticle {
+        /**
+         * Index of the particle in the "indices" array
+         */
+        public ind: number = 0;
+        /**
+         * Length of the particle shape in the "indices" array
+         */
+        public indicesLength: number = 0;
+        /**
+         * Squared distance from the particle to the camera
+         */
+        public sqDistance: number = 0.0;
+    }
+}

+ 208 - 170
src/Particles/babylon.solidParticleSystem.ts

@@ -1,60 +1,72 @@
 module BABYLON {
-    
         /**
-        * Full documentation here : http://doc.babylonjs.com/overviews/Solid_Particle_System
-        */
+         * The SPS is a single updatable mesh. The solid particles are simply separate parts or faces fo this big mesh.
+         *As it is just a mesh, the SPS has all the same properties than any other BJS mesh : not more, not less. It can be scaled, rotated, translated, enlighted, textured, moved, etc.
+
+         * The SPS is also a particle system. It provides some methods to manage the particles.
+         * However it is behavior agnostic. This means it has no emitter, no particle physics, no particle recycler. You have to implement your own behavior.
+         * 
+         * Full documentation here : http://doc.babylonjs.com/overviews/Solid_Particle_System
+         */
         export class SolidParticleSystem implements IDisposable {
-            // public members
             /**
-            *  The SPS array of Solid Particle objects. Just access each particle as with any classic array.
-            *  Example : var p = SPS.particles[i];
-            */
+             *  The SPS array of Solid Particle objects. Just access each particle as with any classic array.
+             *  Example : var p = SPS.particles[i];
+             */
             public particles: SolidParticle[] = new Array<SolidParticle>();
             /**
-            * The SPS total number of particles. Read only. Use SPS.counter instead if you need to set your own value.
-            */
+             * The SPS total number of particles. Read only. Use SPS.counter instead if you need to set your own value.
+             */
             public nbParticles: number = 0;
             /**
-            * If the particles must ever face the camera (default false). Useful for planar particles.
-            */
+             * If the particles must ever face the camera (default false). Useful for planar particles.
+             */
             public billboard: boolean = false;
             /**
              * Recompute normals when adding a shape
              */
             public recomputeNormals: boolean = true;
             /**
-            * This a counter ofr your own usage. It's not set by any SPS functions.
-            */
+             * This a counter ofr your own usage. It's not set by any SPS functions.
+             */
             public counter: number = 0;
             /**
-            * The SPS name. This name is also given to the underlying mesh.
-            */
+             * The SPS name. This name is also given to the underlying mesh.
+             */
             public name: string;
             /**
-            * The SPS mesh. It's a standard BJS Mesh, so all the methods from the Mesh class are avalaible.
-            */
+             * The SPS mesh. It's a standard BJS Mesh, so all the methods from the Mesh class are avalaible.
+             */
             public mesh: Mesh;
             /**
-            * This empty object is intended to store some SPS specific or temporary values in order to lower the Garbage Collector activity.
-            * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#garbage-collector-concerns
-            */
+             * This empty object is intended to store some SPS specific or temporary values in order to lower the Garbage Collector activity.
+             * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#garbage-collector-concerns
+             */
             public vars: any = {};
             /**
-            * This array is populated when the SPS is set as 'pickable'.  
-            * Each key of this array is a `faceId` value that you can get from a pickResult object.  
-            * Each element of this array is an object `{idx: int, faceId: int}`.  
-            * `idx` is the picked particle index in the `SPS.particles` array  
-            * `faceId` is the picked face index counted within this particle.  
-            * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#pickable-particles  
-            */
+             * This array is populated when the SPS is set as 'pickable'.  
+             * Each key of this array is a `faceId` value that you can get from a pickResult object.  
+             * Each element of this array is an object `{idx: int, faceId: int}`.  
+             * `idx` is the picked particle index in the `SPS.particles` array  
+             * `faceId` is the picked face index counted within this particle.  
+             * Please read : http://doc.babylonjs.com/overviews/Solid_Particle_System#pickable-particles  
+             */
             public pickedParticles: { idx: number; faceId: number }[];
             /**
-            * This array is populated when `enableDepthSort` is set to true.  
-            * Each element of this array is an instance of the class DepthSortedParticle.  
-            */
+             * This array is populated when `enableDepthSort` is set to true.  
+             * Each element of this array is an instance of the class DepthSortedParticle.  
+             */
             public depthSortedParticles: DepthSortedParticle[];
-    
-            // private members
+
+            /**
+             * If the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster). (Internal use only)
+             */
+            public _bSphereOnly: boolean = false;
+            /**
+             * A number to multiply the boundind sphere radius by in order to reduce it for instance. (Internal use only)
+             */
+            public _bSphereRadiusFactor: number = 1.0;
+
             private _scene: Scene;
             private _positions: number[] = new Array<number>();
             private _indices: number[] = new Array<number>();
@@ -121,22 +133,19 @@
                     return (p2.sqDistance - p1.sqDistance);
                 };
             private _needs32Bits: boolean = false;
-            public _bSphereOnly: boolean = false;
-            public _bSphereRadiusFactor: number = 1.0;
-    
-    
+
             /**
-            * Creates a SPS (Solid Particle System) object.
-            * `name` (String) is the SPS name, this will be the underlying mesh name.  
-            * `scene` (Scene) is the scene in which the SPS is added.  
-            * `updatable` (optional boolean, default true) : if the SPS must be updatable or immutable.  
-            * `isPickable` (optional boolean, default false) : if the solid particles must be pickable.  
-            * `enableDepthSort` (optional boolean, default false) : if the solid particles must be sorted in the geometry according to their distance to the camera.  
-            * `particleIntersection` (optional boolean, default false) : if the solid particle intersections must be computed.    
-            * `boundingSphereOnly` (optional boolean, default false) : if the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster).  
-            * `bSphereRadiusFactor` (optional float, default 1.0) : a number to multiply the boundind sphere radius by in order to reduce it for instance. 
-            *  Example : bSphereRadiusFactor = 1.0 / Math.sqrt(3.0) => the bounding sphere exactly matches a spherical mesh.  
-            */
+             * Creates a SPS (Solid Particle System) object.
+             * @param name (String) is the SPS name, this will be the underlying mesh name.  
+             * @param scene (Scene) is the scene in which the SPS is added.  
+             * @param updatable (optional boolean, default true) : if the SPS must be updatable or immutable.  
+             * @param isPickable (optional boolean, default false) : if the solid particles must be pickable.  
+             * @param enableDepthSort (optional boolean, default false) : if the solid particles must be sorted in the geometry according to their distance to the camera.  
+             * @param particleIntersection (optional boolean, default false) : if the solid particle intersections must be computed.    
+             * @param boundingSphereOnly (optional boolean, default false) : if the particle intersection must be computed only with the bounding sphere (no bounding box computation, so faster).
+             * @param bSphereRadiusFactor (optional float, default 1.0) : a number to multiply the boundind sphere radius by in order to reduce it for instance. 
+             * @example bSphereRadiusFactor = 1.0 / Math.sqrt(3.0) => the bounding sphere exactly matches a spherical mesh.  
+             */
             constructor(name: string, scene: Scene, options?: { updatable?: boolean; isPickable?: boolean; enableDepthSort?: boolean; particleIntersection?: boolean; boundingSphereOnly?: boolean; bSphereRadiusFactor?: number }) {
                 this.name = name;
                 this._scene = scene || Engine.LastCreatedScene;
@@ -158,11 +167,12 @@
                     this.depthSortedParticles = [];
                 }
             }
-    
+
             /**
-            * Builds the SPS underlying mesh. Returns a standard Mesh.
-            * If no model shape was added to the SPS, the returned mesh is just a single triangular plane.
-            */
+             * Builds the SPS underlying mesh. Returns a standard Mesh.
+             * If no model shape was added to the SPS, the returned mesh is just a single triangular plane.
+             * @returns the created mesh
+             */
             public buildMesh(): Mesh {
                 if (this.nbParticles === 0) {
                     var triangle = MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
@@ -214,14 +224,15 @@
             }
     
             /**
-            * Digests the mesh and generates as many solid particles in the system as wanted. Returns the SPS.  
-            * These particles will have the same geometry than the mesh parts and will be positioned at the same localisation than the mesh original places.
-            * Thus the particles generated from `digest()` have their property `position` set yet.  
-            * `mesh` ( Mesh ) is the mesh to be digested  
-            * `facetNb` (optional integer, default 1) is the number of mesh facets per particle, this parameter is overriden by the parameter `number` if any
-            * `delta` (optional integer, default 0) is the random extra number of facets per particle , each particle will have between `facetNb` and `facetNb + delta` facets
-            * `number` (optional positive integer) is the wanted number of particles : each particle is built with `mesh_total_facets / number` facets
-            */
+             * Digests the mesh and generates as many solid particles in the system as wanted. Returns the SPS.  
+             * These particles will have the same geometry than the mesh parts and will be positioned at the same localisation than the mesh original places.
+             * Thus the particles generated from `digest()` have their property `position` set yet.  
+             * @param mesh ( Mesh ) is the mesh to be digested  
+             * @param options {facetNb} (optional integer, default 1) is the number of mesh facets per particle, this parameter is overriden by the parameter `number` if any
+             * {delta} (optional integer, default 0) is the random extra number of facets per particle , each particle will have between `facetNb` and `facetNb + delta` facets
+             * {number} (optional positive integer) is the wanted number of particles : each particle is built with `mesh_total_facets / number` facets
+             * @returns the current SPS
+             */
             public digest(mesh: Mesh, options?: { facetNb?: number; number?: number; delta?: number }): SolidParticleSystem {
                 var size: number = (options && options.facetNb) || 1;
                 var number: number = (options && options.number) || 0;
@@ -487,13 +498,14 @@
             }
     
             /**
-            * Adds some particles to the SPS from the model shape. Returns the shape id.   
-            * Please read the doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#create-an-immutable-sps
-            * `mesh` is any Mesh object that will be used as a model for the solid particles.
-            * `nb` (positive integer) the number of particles to be created from this model
-            * `positionFunction` is an optional javascript function to called for each particle on SPS creation. 
-            * `vertexFunction` is an optional javascript function to called for each vertex of each particle on SPS creation
-            */
+             * Adds some particles to the SPS from the model shape. Returns the shape id.   
+             * Please read the doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#create-an-immutable-sps
+             * @param mesh is any Mesh object that will be used as a model for the solid particles.
+             * @param nb (positive integer) the number of particles to be created from this model
+             * @param options {positionFunction} is an optional javascript function to called for each particle on SPS creation.
+             * {vertexFunction} is an optional javascript function to called for each vertex of each particle on SPS creation
+             * @returns the number of shapes in the system
+             */
             public addShape(mesh: Mesh, nb: number, options?: { positionFunction?: any; vertexFunction?: any }): number {
                 var meshPos = <FloatArray>mesh.getVerticesData(VertexBuffer.PositionKind);
                 var meshInd = <IndicesArray>mesh.getIndices();
@@ -594,11 +606,11 @@
                 particle.scaling.y = 1.0;
                 particle.scaling.z = 1.0;
             }
-    
+
             /**
-            * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.  
-            * Returns the SPS.  
-            */
+             * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.  
+             * @returns the SPS.
+             */
             public rebuildMesh(): SolidParticleSystem {
                 for (var p = 0; p < this.particles.length; p++) {
                     this._rebuildParticle(this.particles[p]);
@@ -606,17 +618,16 @@
                 this.mesh.updateVerticesData(VertexBuffer.PositionKind, this._positions32, false, false);
                 return this;
             }
-    
-    
+
             /**
-            *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
-            *  This method calls `updateParticle()` for each particle of the SPS.
-            *  For an animated SPS, it is usually called within the render loop.
-            * @param start The particle index in the particle array where to start to compute the particle property values _(default 0)_
-            * @param end The particle index in the particle array where to stop to compute the particle property values _(default nbParticle - 1)_
-            * @param update If the mesh must be finally updated on this call after all the particle computations _(default true)_   
-            * Returns the SPS.  
-            */
+             *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
+             *  This method calls `updateParticle()` for each particle of the SPS.
+             *  For an animated SPS, it is usually called within the render loop.
+             * @param start The particle index in the particle array where to start to compute the particle property values _(default 0)_
+             * @param end The particle index in the particle array where to stop to compute the particle property values _(default nbParticle - 1)_
+             * @param update If the mesh must be finally updated on this call after all the particle computations _(default true)_   
+             * @returns the SPS.
+             */
             public setParticles(start: number = 0, end: number = this.nbParticles - 1, update: boolean = true): SolidParticleSystem {
                 if (!this._updatable) {
                     return this;
@@ -970,8 +981,7 @@
             }
     
             /**
-            * Disposes the SPS.  
-            * Returns nothing.  
+            * Disposes the SPS.
             */
             public dispose(): void {
                 this.mesh.dispose();
@@ -990,12 +1000,12 @@
                 (<any>this._colors32) = null;
                 (<any>this.pickedParticles) = null;
             }
-    
+
             /**
-            * Visibilty helper : Recomputes the visible size according to the mesh bounding box
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility   
-            * Returns the SPS.  
-            */
+             * Visibilty helper : Recomputes the visible size according to the mesh bounding box
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility   
+             * @returns the SPS.
+             */
             public refreshVisibleSize(): SolidParticleSystem {
                 if (!this._isVisibilityBoxLocked) {
                     this.mesh.refreshBoundingInfo();
@@ -1004,35 +1014,37 @@
             }
     
             /** 
-            * Visibility helper : Sets the size of a visibility box, this sets the underlying mesh bounding box.
-            * @param size the size (float) of the visibility box
-            * note : this doesn't lock the SPS mesh bounding box.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Visibility helper : Sets the size of a visibility box, this sets the underlying mesh bounding box.
+             * @param size the size (float) of the visibility box
+             * note : this doesn't lock the SPS mesh bounding box.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public setVisibilityBox(size: number): void {
                 var vis = size / 2;
                 this.mesh._boundingInfo = new BoundingInfo(new Vector3(-vis, -vis, -vis), new Vector3(vis, vis, vis));
             }
-    
-    
-            // getter and setter
+
+            /**
+             * Gets whether the SPS as always visible or not
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public get isAlwaysVisible(): boolean {
                 return this._alwaysVisible;
             }
     
             /**
-            * Sets the SPS as always visible or not
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Sets the SPS as always visible or not
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public set isAlwaysVisible(val: boolean) {
                 this._alwaysVisible = val;
                 this.mesh.alwaysSelectAsActiveMesh = val;
             }
-    
+
             /**
-            * Sets the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
-            */
+             * Sets the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public set isVisibilityBoxLocked(val: boolean) {
                 this._isVisibilityBoxLocked = val;
 
@@ -1040,145 +1052,171 @@
 
                 boundingInfo.isLocked = val;
             }
-    
+
+            /**
+             * Gets if the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#sps-visibility
+             */
             public get isVisibilityBoxLocked(): boolean {
                 return this._isVisibilityBoxLocked;
             }
-    
-            // Optimizer setters
+
             /**
-            * Tells to `setParticles()` to compute the particle rotations or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
-            */
+             * Tells to `setParticles()` to compute the particle rotations or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
+             */
             public set computeParticleRotation(val: boolean) {
                 this._computeParticleRotation = val;
             }
             /**
-            * Tells to `setParticles()` to compute the particle colors or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
-            */
+             * Tells to `setParticles()` to compute the particle colors or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
+             */
             public set computeParticleColor(val: boolean) {
                 this._computeParticleColor = val;
             }
-            /**
-            * Tells to `setParticles()` to compute the particle textures or not.
-            * Default value : true. The SPS is faster when it's set to false.
-            * Note : the particle textures are stored values, so setting `computeParticleTexture` to false will keep yet the last colors set.
-            */
+            
             public set computeParticleTexture(val: boolean) {
                 this._computeParticleTexture = val;
             }
             /**
-            * Tells to `setParticles()` to call the vertex function for each vertex of each particle, or not.
-            * Default value : false. The SPS is faster when it's set to false.
-            * Note : the particle custom vertex positions aren't stored values.
-            */
+             * Tells to `setParticles()` to call the vertex function for each vertex of each particle, or not.
+             * Default value : false. The SPS is faster when it's set to false.
+             * Note : the particle custom vertex positions aren't stored values.
+             */
             public set computeParticleVertex(val: boolean) {
                 this._computeParticleVertex = val;
             }
             /**
-            * Tells to `setParticles()` to compute or not the mesh bounding box when computing the particle positions.
-            */
+             * Tells to `setParticles()` to compute or not the mesh bounding box when computing the particle positions.
+             */
             public set computeBoundingBox(val: boolean) {
                 this._computeBoundingBox = val;
             }
             /**
-            * Tells to `setParticles()` to sort or not the distance between each particle and the camera.  
-            * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
-            * Default : `true`  
-            */
+             * Tells to `setParticles()` to sort or not the distance between each particle and the camera.  
+             * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
+             * Default : `true`  
+             */
             public set depthSortParticles(val: boolean) {
                 this._depthSortParticles = val;
             }
-            // getters
+
+            /**
+             * Gets if `setParticles()` computes the particle rotations or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle rotations aren't stored values, so setting `computeParticleRotation` to false will prevents the particle to rotate.
+             */
             public get computeParticleRotation(): boolean {
                 return this._computeParticleRotation;
             }
-    
+            /**
+             * Gets if `setParticles()` computes the particle colors or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle colors are stored values, so setting `computeParticleColor` to false will keep yet the last colors set.
+             */
             public get computeParticleColor(): boolean {
                 return this._computeParticleColor;
             }
-    
+            /**
+             * Gets if `setParticles()` computes the particle textures or not.
+             * Default value : true. The SPS is faster when it's set to false.
+             * Note : the particle textures are stored values, so setting `computeParticleTexture` to false will keep yet the last colors set.
+             */
             public get computeParticleTexture(): boolean {
                 return this._computeParticleTexture;
             }
-    
+            /**
+             * Gets if `setParticles()` calls the vertex function for each vertex of each particle, or not.
+             * Default value : false. The SPS is faster when it's set to false.
+             * Note : the particle custom vertex positions aren't stored values.
+             */
             public get computeParticleVertex(): boolean {
                 return this._computeParticleVertex;
             }
-    
+            /**
+             * Gets if `setParticles()` computes or not the mesh bounding box when computing the particle positions.
+             */
             public get computeBoundingBox(): boolean {
                 return this._computeBoundingBox;
             }
-    
+            /**
+             * Gets if `setParticles()` sorts or not the distance between each particle and the camera.  
+             * Skipped when `enableDepthSort` is set to `false` (default) at construction time.
+             * Default : `true`  
+             */
             public get depthSortParticles(): boolean {
                 return this._depthSortParticles;
             }
     
             // =======================================================================
             // Particle behavior logic
-            // these following methods may be overwritten by the user to fit his needs
-    
+            // these following methods may be overwritten by the user to fit his needs    
     
             /**
-            * This function does nothing. It may be overwritten to set all the particle first values.
-            * The SPS doesn't call this function, you may have to call it by your own.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            */
+             * This function does nothing. It may be overwritten to set all the particle first values.
+             * The SPS doesn't call this function, you may have to call it by your own.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             */
             public initParticles(): void {
             }
     
             /**
-            * This function does nothing. It may be overwritten to recycle a particle.
-            * The SPS doesn't call this function, you may have to call it by your own.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            */
+             * This function does nothing. It may be overwritten to recycle a particle.
+             * The SPS doesn't call this function, you may have to call it by your own.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             * @param particle The particle to recycle
+             * @returns the recycled particle
+             */
             public recycleParticle(particle: SolidParticle): SolidParticle {
                 return particle;
             }
     
             /**
-            * Updates a particle : this function should  be overwritten by the user.
-            * It is called on each particle by `setParticles()`. This is the place to code each particle behavior.
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
-            * ex : just set a particle position or velocity and recycle conditions
-            */
+             * Updates a particle : this function should  be overwritten by the user.
+             * It is called on each particle by `setParticles()`. This is the place to code each particle behavior.
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#particle-management
+             * @example : just set a particle position or velocity and recycle conditions
+             * @param particle The particle to update
+             * @returns the updated particle
+             */
             public updateParticle(particle: SolidParticle): SolidParticle {
                 return particle;
             }
     
             /**
-            * Updates a vertex of a particle : it can be overwritten by the user.
-            * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
-            * @param particle the current particle
-            * @param vertex the current index of the current particle
-            * @param pt the index of the current vertex in the particle shape
-            * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#update-each-particle-shape
-            * ex : just set a vertex particle position
-            */
+             * Updates a vertex of a particle : it can be overwritten by the user.
+             * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
+             * @param particle the current particle
+             * @param vertex the current index of the current particle
+             * @param pt the index of the current vertex in the particle shape
+             * doc : http://doc.babylonjs.com/overviews/Solid_Particle_System#update-each-particle-shape
+             * @example : just set a vertex particle position
+             * @returns the updated vertex
+             */
             public updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3 {
                 return vertex;
             }
     
             /**
-            * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
-            * This does nothing and may be overwritten by the user.
-            * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param update the boolean update value actually passed to setParticles()
-            */
+             * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
+             * This does nothing and may be overwritten by the user.
+             * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param update the boolean update value actually passed to setParticles()
+             */
             public beforeUpdateParticles(start?: number, stop?: number, update?: boolean): void {
             }
             /**
-            * This will be called  by `setParticles()` after all the other treatments and just before the actual mesh update.
-            * This will be passed three parameters.
-            * This does nothing and may be overwritten by the user.
-            * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
-            * @param update the boolean update value actually passed to setParticles()
-            */
+             * This will be called  by `setParticles()` after all the other treatments and just before the actual mesh update.
+             * This will be passed three parameters.
+             * This does nothing and may be overwritten by the user.
+             * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+             * @param update the boolean update value actually passed to setParticles()
+             */
             public afterUpdateParticles(start?: number, stop?: number, update?: boolean): void {
             }
         }

+ 73 - 9
src/Particles/babylon.sphereParticleEmitter.ts

@@ -1,18 +1,56 @@
 module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a sphere.
+     * It emits the particles alongside the sphere radius. The emission direction might be randomized.
+     */
     export class SphereParticleEmitter implements IParticleEmitterType {
-        constructor(public radius: number) {
+
+        /**
+         * Creates a new instance of @see SphereParticleEmitter
+         * @param radius the radius of the emission sphere
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         */
+        constructor(
+            /**
+             * The radius of the emission sphere.
+             */
+            public radius: number, 
+            /**
+             * How much to randomize the particle direction [0-1].
+             */
+            public directionRandomizer = 0) {
 
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            // measure the direction Vector from the emitter to the particle.
-            var direction = particle.position.subtract(worldMatrix.getTranslation());
+            var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
+            var randX = Scalar.RandomRange(0, this.directionRandomizer);
+            var randY = Scalar.RandomRange(0, this.directionRandomizer);
+            var randZ = Scalar.RandomRange(0, this.directionRandomizer);
+            direction.x += randX;
+            direction.y += randY;
+            direction.z += randZ;
+            direction.normalize();
+
             Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
         }
 
+        /**
+         * Called by the particle System when the position is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param positionToUpdate is the position vector to update with the result
+         * @param particle is the particle we are computed the position for
+         */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
-            var phi = ParticleSystem.randomNumber(0, 2 * Math.PI);
-            var theta = ParticleSystem.randomNumber(0, Math.PI);
+            var phi = Scalar.RandomRange(0, 2 * Math.PI);
+            var theta = Scalar.RandomRange(0, Math.PI);
             var randX = this.radius * Math.cos(phi) * Math.sin(theta);
             var randY = this.radius * Math.cos(theta);
             var randZ = this.radius * Math.sin(phi) * Math.sin(theta);
@@ -20,15 +58,41 @@ module BABYLON {
         }
     }
 
+    /**
+     * Particle emitter emitting particles from the inside of a sphere.
+     * It emits the particles randomly between two vectors.
+     */
     export class SphereDirectedParticleEmitter extends SphereParticleEmitter {
-        constructor(radius: number, public direction1: Vector3, public direction2: Vector3) {
+
+        /**
+         * Creates a new instance of @see SphereDirectedParticleEmitter
+         * @param radius the radius of the emission sphere
+         * @param direction1 the min limit of the emission direction
+         * @param direction2 the max limit of the emission direction
+         */
+        constructor(radius: number, 
+            /**
+             * The min limit of the emission direction.
+             */
+            public direction1: Vector3, 
+            /**
+             * The max limit of the emission direction.
+             */
+            public direction2: Vector3) {
             super(radius);
         }
 
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param emitPower is the power of the particle (speed)
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
         startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
-            var randX = ParticleSystem.randomNumber(this.direction1.x, this.direction2.x);
-            var randY = ParticleSystem.randomNumber(this.direction1.y, this.direction2.y);
-            var randZ = ParticleSystem.randomNumber(this.direction1.z, this.direction2.z);
+            var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+            var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+            var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
             Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
         }
     }