浏览代码

Merge pull request #3453 from IbraheemOsama/Particle2

Adding cone and sphere emitters
David Catuhe 7 年之前
父节点
当前提交
5f2c1b375a

+ 5 - 1
Tools/Gulp/config.json

@@ -228,7 +228,11 @@
         "particles": {
             "files": [
                 "../../src/Particles/babylon.particle.js",
-                "../../src/Particles/babylon.particleSystem.js"
+                "../../src/Particles/babylon.particleSystem.js",
+                "../../src/Particles/babylon.boxParticleEmitter.js",
+                "../../src/Particles/babylon.coneParticleEmitter.js",
+                "../../src/Particles/babylon.sphereParticleEmitter.js",
+                "../../src/Particles/babylon.iParticleEmitterType.js"
             ],
             "dependUpon": [
                 "core"

+ 146 - 26
dist/preview release/babylon.max.js

@@ -45971,13 +45971,6 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
-    var randomNumber = function (min, max) {
-        if (min === max) {
-            return (min);
-        }
-        var random = Math.random();
-        return ((random * (max - min)) + min);
-    };
     var ParticleSystem = /** @class */ (function () {
         // end of sheet animation
         function ParticleSystem(name, capacity, scene, customEffect, _isAnimationSheetEnabled, epsilon) {
@@ -46069,18 +46062,7 @@ var BABYLON;
             this._vertexBuffers[BABYLON.VertexBuffer.ColorKind] = colors;
             this._vertexBuffers["options"] = options;
             // Default behaviors
-            this.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
-                var randX = randomNumber(_this.direction1.x, _this.direction2.x);
-                var randY = randomNumber(_this.direction1.y, _this.direction2.y);
-                var randZ = randomNumber(_this.direction1.z, _this.direction2.z);
-                BABYLON.Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
-            };
-            this.startPositionFunction = function (worldMatrix, positionToUpdate, particle) {
-                var randX = randomNumber(_this.minEmitBox.x, _this.maxEmitBox.x);
-                var randY = randomNumber(_this.minEmitBox.y, _this.maxEmitBox.y);
-                var randZ = randomNumber(_this.minEmitBox.z, _this.maxEmitBox.z);
-                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
-            };
+            this._particleEmitterType = new BABYLON.BoxParticleEmitter(this);
             this.updateFunction = function (particles) {
                 for (var index = 0; index < particles.length; index++) {
                     var particle = particles[index];
@@ -46228,13 +46210,13 @@ var BABYLON;
                     particle = new BABYLON.Particle(this);
                 }
                 this.particles.push(particle);
-                var emitPower = randomNumber(this.minEmitPower, this.maxEmitPower);
-                this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
-                particle.lifeTime = randomNumber(this.minLifeTime, this.maxLifeTime);
-                particle.size = randomNumber(this.minSize, this.maxSize);
-                particle.angularSpeed = randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
-                this.startPositionFunction(worldMatrix, particle.position, particle);
-                var step = randomNumber(0, 1.0);
+                var emitPower = ParticleSystem.randomNumber(this.minEmitPower, this.maxEmitPower);
+                this._particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
+                this._particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                particle.lifeTime = ParticleSystem.randomNumber(this.minLifeTime, this.maxLifeTime);
+                particle.size = ParticleSystem.randomNumber(this.minSize, this.maxSize);
+                particle.angularSpeed = ParticleSystem.randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
+                var step = ParticleSystem.randomNumber(0, 1.0);
                 BABYLON.Color4.LerpToRef(this.color1, this.color2, step, particle.color);
                 this.colorDead.subtractToRef(particle.color, this._colorDiff);
                 this._colorDiff.scaleToRef(1.0 / particle.lifeTime, particle.colorStep);
@@ -46418,6 +46400,29 @@ var BABYLON;
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
         };
+        ParticleSystem.prototype.createSphereEmitter = function (redius) {
+            if (redius === void 0) { redius = 1; }
+            this._particleEmitterType = new BABYLON.SphereParticleEmitter(redius);
+        };
+        ParticleSystem.prototype.createDirectedSphereEmitter = function (redius, direction1, direction2) {
+            if (redius === void 0) { redius = 1; }
+            if (direction1 === void 0) { direction1 = new BABYLON.Vector3(0, 1.0, 0); }
+            if (direction2 === void 0) { direction2 = new BABYLON.Vector3(0, 1.0, 0); }
+            this._particleEmitterType = new BABYLON.SphereDirectedParticleEmitter(redius, direction1, direction2);
+        };
+        ParticleSystem.prototype.createConeEmitter = function (redius, angle) {
+            if (redius === void 0) { redius = 1; }
+            if (angle === void 0) { angle = Math.PI / 4; }
+            this._particleEmitterType = new BABYLON.ConeParticleEmitter(redius, angle);
+        };
+        // this method need to be changed when breaking changes to match the sphere and cone methods and properties direction1,2 and minEmitBox,maxEmitBox to be removed from the system.
+        ParticleSystem.prototype.createBoxEmitter = function (direction1, direction2, minEmitBox, maxEmitBox) {
+            this.direction1 = direction1;
+            this.direction2 = direction2;
+            this.minEmitBox = minEmitBox;
+            this.maxEmitBox = maxEmitBox;
+            this._particleEmitterType = new BABYLON.BoxParticleEmitter(this);
+        };
         // Clone
         ParticleSystem.prototype.clone = function (name, newEmitter) {
             var custom = null;
@@ -46570,6 +46575,13 @@ var BABYLON;
         // Statics
         ParticleSystem.BLENDMODE_ONEONE = 0;
         ParticleSystem.BLENDMODE_STANDARD = 1;
+        ParticleSystem.randomNumber = function (min, max) {
+            if (min === max) {
+                return (min);
+            }
+            var random = Math.random();
+            return ((random * (max - min)) + min);
+        };
         return ParticleSystem;
     }());
     BABYLON.ParticleSystem = ParticleSystem;
@@ -46579,6 +46591,114 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    var BoxParticleEmitter = /** @class */ (function () {
+        // to be updated like the rest of emitters when breaking changes.
+        function BoxParticleEmitter(particleSystem) {
+            this.particleSystem = particleSystem;
+        }
+        BoxParticleEmitter.prototype.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
+            var randX = BABYLON.ParticleSystem.randomNumber(this.particleSystem.direction1.x, this.particleSystem.direction2.x);
+            var randY = BABYLON.ParticleSystem.randomNumber(this.particleSystem.direction1.y, this.particleSystem.direction2.y);
+            var randZ = BABYLON.ParticleSystem.randomNumber(this.particleSystem.direction1.z, this.particleSystem.direction2.z);
+            BABYLON.Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+        };
+        BoxParticleEmitter.prototype.startPositionFunction = function (worldMatrix, positionToUpdate, particle) {
+            var randX = BABYLON.ParticleSystem.randomNumber(this.particleSystem.minEmitBox.x, this.particleSystem.maxEmitBox.x);
+            var randY = BABYLON.ParticleSystem.randomNumber(this.particleSystem.minEmitBox.y, this.particleSystem.maxEmitBox.y);
+            var randZ = BABYLON.ParticleSystem.randomNumber(this.particleSystem.minEmitBox.z, this.particleSystem.maxEmitBox.z);
+            BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
+        };
+        return BoxParticleEmitter;
+    }());
+    BABYLON.BoxParticleEmitter = BoxParticleEmitter;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.boxParticleEmitter.js.map
+
+var BABYLON;
+(function (BABYLON) {
+    var ConeParticleEmitter = /** @class */ (function () {
+        function ConeParticleEmitter(redius, angle) {
+            this.redius = redius;
+            this.angle = angle;
+        }
+        ConeParticleEmitter.prototype.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
+            if (this.angle === 0) {
+                BABYLON.Vector3.TransformNormalFromFloatsToRef(0, emitPower, 0, worldMatrix, directionToUpdate);
+            }
+            else {
+                var phi = BABYLON.ParticleSystem.randomNumber(0, 2 * Math.PI);
+                var theta = BABYLON.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);
+                BABYLON.Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+            }
+        };
+        ConeParticleEmitter.prototype.startPositionFunction = function (worldMatrix, positionToUpdate, particle) {
+            var s = BABYLON.ParticleSystem.randomNumber(0, Math.PI * 2);
+            var redius = BABYLON.ParticleSystem.randomNumber(0, this.redius);
+            var randX = redius * Math.sin(s);
+            var randZ = redius * Math.cos(s);
+            BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(randX, 0, randZ, worldMatrix, positionToUpdate);
+        };
+        return ConeParticleEmitter;
+    }());
+    BABYLON.ConeParticleEmitter = ConeParticleEmitter;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.coneParticleEmitter.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
+    var SphereParticleEmitter = /** @class */ (function () {
+        function SphereParticleEmitter(redius) {
+            this.redius = redius;
+        }
+        SphereParticleEmitter.prototype.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
+            // measure the direction Vector from the emitter to the particle.
+            var direction = particle.position.subtract(worldMatrix.getTranslation());
+            BABYLON.Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
+        };
+        SphereParticleEmitter.prototype.startPositionFunction = function (worldMatrix, positionToUpdate, particle) {
+            var phi = BABYLON.ParticleSystem.randomNumber(0, 2 * Math.PI);
+            var theta = BABYLON.ParticleSystem.randomNumber(0, Math.PI);
+            var randX = this.redius * Math.cos(phi) * Math.sin(theta);
+            var randY = this.redius * Math.cos(theta);
+            var randZ = this.redius * Math.sin(phi) * Math.sin(theta);
+            BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
+        };
+        return SphereParticleEmitter;
+    }());
+    BABYLON.SphereParticleEmitter = SphereParticleEmitter;
+    var SphereDirectedParticleEmitter = /** @class */ (function (_super) {
+        __extends(SphereDirectedParticleEmitter, _super);
+        function SphereDirectedParticleEmitter(redius, direction1, direction2) {
+            var _this = _super.call(this, redius) || this;
+            _this.direction1 = direction1;
+            _this.direction2 = direction2;
+            return _this;
+        }
+        SphereDirectedParticleEmitter.prototype.startDirectionFunction = function (emitPower, worldMatrix, directionToUpdate, particle) {
+            var randX = BABYLON.ParticleSystem.randomNumber(this.direction1.x, this.direction2.x);
+            var randY = BABYLON.ParticleSystem.randomNumber(this.direction1.y, this.direction2.y);
+            var randZ = BABYLON.ParticleSystem.randomNumber(this.direction1.z, this.direction2.z);
+            BABYLON.Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+        };
+        return SphereDirectedParticleEmitter;
+    }(SphereParticleEmitter));
+    BABYLON.SphereDirectedParticleEmitter = SphereDirectedParticleEmitter;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.sphereParticleEmitter.js.map
+
+
+
+//# sourceMappingURL=babylon.iParticleEmitterType.js.map
+
+var BABYLON;
+(function (BABYLON) {
     var GPUParticleSystem = /** @class */ (function () {
         function GPUParticleSystem(name, capacity, scene) {
             this.name = name;

+ 54 - 0
src/Particles/babylon.boxParticleEmitter.ts

@@ -0,0 +1,54 @@
+module BABYLON {
+    export class BoxParticleEmitter implements IParticleEmitterType {
+
+        public get direction1(): Vector3 {
+            return this._particleSystem.direction1;
+        }
+        public set direction1(value: Vector3) {
+            this._particleSystem.direction1 = value;
+        }
+
+        public get direction2(): Vector3 {
+            return this._particleSystem.direction2;
+        }
+        public set direction2(value: Vector3) {
+            this._particleSystem.direction2 = value;
+        }
+
+        public get minEmitBox(): Vector3 {
+            return this._particleSystem.minEmitBox;
+        }
+        public set minEmitBox(value: Vector3) {
+            this._particleSystem.minEmitBox = value;
+        }
+
+        public get maxEmitBox(): Vector3 {
+            return this._particleSystem.maxEmitBox;
+        }
+        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.
+        constructor(private _particleSystem: ParticleSystem) {
+
+        }
+
+        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);
+
+            Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+        }
+
+        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);
+
+            Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
+        }
+    }
+}

+ 29 - 0
src/Particles/babylon.coneParticleEmitter.ts

@@ -0,0 +1,29 @@
+module BABYLON {
+    export class ConeParticleEmitter implements IParticleEmitterType {
+        constructor(public radius: number, public angle: number) {
+        }
+
+        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);
+            }
+        }
+
+        startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+            var s = ParticleSystem.randomNumber(0, Math.PI * 2);
+            var radius = ParticleSystem.randomNumber(0, this.radius);
+            var randX = radius * Math.sin(s);
+            var randZ = radius * Math.cos(s);
+
+            Vector3.TransformCoordinatesFromFloatsToRef(randX, 0, randZ, worldMatrix, positionToUpdate);
+        }
+    }
+}

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

@@ -0,0 +1,6 @@
+module BABYLON {
+    export interface IParticleEmitterType {
+        startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void;
+        startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void;
+    }
+}

+ 60 - 33
src/Particles/babylon.particleSystem.ts

@@ -1,18 +1,8 @@
 module BABYLON {
-    var randomNumber = (min: number, max: number): number => {
-        if (min === max) {
-            return (min);
-        }
-
-        var random = Math.random();
-
-        return ((random * (max - min)) + min);
-    }
-
     export interface IParticleSystem {
         id: string;
         name: string;
-        emitter: Nullable<AbstractMesh | Vector3>; 
+        emitter: Nullable<AbstractMesh | Vector3>;
         renderingGroupId: number;
         layerMask: number;
         isStarted(): boolean;
@@ -93,6 +83,7 @@
         public color2 = new Color4(1.0, 1.0, 1.0, 1.0);
         public colorDead = new Color4(0, 0, 0, 1.0);
         public textureMask = new Color4(1.0, 1.0, 1.0, 1.0);
+        public particleEmitterType: IParticleEmitterType;
         public startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle) => void;
         public startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle) => void;
 
@@ -172,21 +163,7 @@
             this._vertexBuffers["options"] = options;
 
             // Default behaviors
-            this.startDirectionFunction = (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void => {
-                var randX = randomNumber(this.direction1.x, this.direction2.x);
-                var randY = randomNumber(this.direction1.y, this.direction2.y);
-                var randZ = randomNumber(this.direction1.z, this.direction2.z);
-
-                Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
-            }
-
-            this.startPositionFunction = (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void => {
-                var randX = randomNumber(this.minEmitBox.x, this.maxEmitBox.x);
-                var randY = randomNumber(this.minEmitBox.y, this.maxEmitBox.y);
-                var randZ = randomNumber(this.minEmitBox.z, this.maxEmitBox.z);
-
-                Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
-            }
+            this.particleEmitterType = new BoxParticleEmitter(this);
 
             this.updateFunction = (particles: Particle[]): void => {
                 for (var index = 0; index < particles.length; index++) {
@@ -345,18 +322,28 @@
 
                 this.particles.push(particle);
 
-                var emitPower = randomNumber(this.minEmitPower, this.maxEmitPower);
+                var emitPower = ParticleSystem.randomNumber(this.minEmitPower, this.maxEmitPower);
 
-                this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                if (this.startDirectionFunction) {
+                    this.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                }
+                else {
+                    this.particleEmitterType.startDirectionFunction(emitPower, worldMatrix, particle.direction, particle);
+                }
 
-                particle.lifeTime = randomNumber(this.minLifeTime, this.maxLifeTime);
+                if (this.startPositionFunction) {
+                    this.startPositionFunction(worldMatrix, particle.position, particle);
+                }
+                else {
+                    this.particleEmitterType.startPositionFunction(worldMatrix, particle.position, particle);
+                }
 
-                particle.size = randomNumber(this.minSize, this.maxSize);
-                particle.angularSpeed = randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
+                particle.lifeTime = ParticleSystem.randomNumber(this.minLifeTime, this.maxLifeTime);
 
-                this.startPositionFunction(worldMatrix, particle.position, particle);
+                particle.size = ParticleSystem.randomNumber(this.minSize, this.maxSize);
+                particle.angularSpeed = ParticleSystem.randomNumber(this.minAngularSpeed, this.maxAngularSpeed);
 
-                var step = randomNumber(0, 1.0);
+                var step = ParticleSystem.randomNumber(0, 1.0);
 
                 Color4.LerpToRef(this.color1, this.color2, step, particle.color);
 
@@ -593,6 +580,46 @@
             this.onDisposeObservable.clear();
         }
 
+        public createSphereEmitter(radius = 1): SphereParticleEmitter {
+            var particleEmitter = new SphereParticleEmitter(radius);
+            this.particleEmitterType = particleEmitter;
+            return particleEmitter;
+        }
+
+        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;
+        }
+
+        public createConeEmitter(radius = 1, angle = Math.PI / 4): ConeParticleEmitter {
+            var particleEmitter = new ConeParticleEmitter(radius, angle);
+            this.particleEmitterType = particleEmitter;
+            return particleEmitter;
+        }
+
+        // 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.
+        public createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter {
+            var particleEmitter = new BoxParticleEmitter(this);
+            this.direction1 = direction1;
+            this.direction2 = direction2;
+            this.minEmitBox = minEmitBox;
+            this.maxEmitBox = maxEmitBox;
+            this.particleEmitterType = particleEmitter;
+            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
         public clone(name: string, newEmitter: any): ParticleSystem {
             var custom: Nullable<Effect> = null;

+ 35 - 0
src/Particles/babylon.sphereParticleEmitter.ts

@@ -0,0 +1,35 @@
+module BABYLON {
+    export class SphereParticleEmitter implements IParticleEmitterType {
+        constructor(public radius: number) {
+
+        }
+
+        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());
+            Vector3.TransformNormalFromFloatsToRef(direction.x * emitPower, direction.y * emitPower, direction.z * emitPower, worldMatrix, directionToUpdate);
+        }
+
+        startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+            var phi = ParticleSystem.randomNumber(0, 2 * Math.PI);
+            var theta = ParticleSystem.randomNumber(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);
+            Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
+        }
+    }
+
+    export class SphereDirectedParticleEmitter extends SphereParticleEmitter {
+        constructor(radius: number, public direction1: Vector3, public direction2: Vector3) {
+            super(radius);
+        }
+
+        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);
+            Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
+        }
+    }
+}