Przeglądaj źródła

Merge pull request #4984 from TrevorDev/cylinderParticleEmitter

Cylinder particle emitter
David Catuhe 7 lat temu
rodzic
commit
15e46636b4

+ 1 - 0
Tools/Gulp/config.json

@@ -294,6 +294,7 @@
                 "../../src/Particles/babylon.baseParticleSystem.js",
                 "../../src/Particles/babylon.particleSystem.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
+                "../../src/Particles/EmitterTypes/babylon.cylinderParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.hemisphericParticleEmitter.js",

+ 1 - 0
dist/preview release/what's new.md

@@ -107,6 +107,7 @@
 - Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
 - Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
 - BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))
+- Cylinder particle emitter ([TrevorDev](https://github.com/TrevorDev))
 - Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
 - Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
 

+ 138 - 0
src/Particles/EmitterTypes/babylon.cylinderParticleEmitter.ts

@@ -0,0 +1,138 @@
+module BABYLON {
+    /**
+     * Particle emitter emitting particles from the inside of a cylinder.
+     * It emits the particles alongside the cylinder radius. The emission direction might be randomized.
+     */
+    export class CylinderParticleEmitter implements IParticleEmitterType {
+         /**
+         * Creates a new instance CylinderParticleEmitter
+         * @param radius the radius of the emission cylinder (1 by default)
+         * @param height the height of the emission cylinder (1 by default)
+         * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default) 
+         * @param directionRandomizer defines how much to randomize the particle direction [0-1]
+         */
+        constructor(
+            /**
+             * The radius of the emission cylinder.
+             */
+            public radius = 1,
+            /**
+             * The height of the emission cylinder.
+             */
+            public height = 1,
+            /**
+             * The range of emission [0-1] 0 Surface only, 1 Entire Radius.
+             */
+            public radiusRange = 1,
+            /**
+             * 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 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
+         */
+        public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+            var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
+            var randY = Scalar.RandomRange(-this.directionRandomizer/2, this.directionRandomizer/2);
+            
+            var angle = Math.atan2(direction.x, direction.z);
+            angle += Scalar.RandomRange(-Math.PI/2, Math.PI/2)*this.directionRandomizer;
+            
+            direction.y = randY; // set direction y to rand y to mirror normal of cylinder surface
+            direction.x = Math.sin(angle);
+            direction.z = Math.cos(angle);
+            direction.normalize();
+
+            Vector3.TransformNormalFromFloatsToRef(direction.x, direction.y, direction.z, 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
+         */
+        public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+            var yPos = Scalar.RandomRange(-this.height/2, this.height/2);
+            var angle = Scalar.RandomRange(0, 2 * Math.PI);
+
+            // Pick a properly distributed point within the circle https://programming.guide/random-point-within-circle.html
+            var radiusDistribution = Scalar.RandomRange((1-this.radiusRange)*(1-this.radiusRange), 1);
+            var positionRadius = Math.sqrt(radiusDistribution)*this.radius;
+            var xPos = positionRadius*Math.cos(angle);
+            var zPos = positionRadius*Math.sin(angle);
+
+            Vector3.TransformCoordinatesFromFloatsToRef(xPos, yPos, zPos, worldMatrix, positionToUpdate);
+        }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): CylinderParticleEmitter {
+            let newOne = new CylinderParticleEmitter(this.radius, this.directionRandomizer);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }    
+        
+        /**
+         * Called by the {BABYLON.GPUParticleSystem} to setup the update shader
+         * @param effect defines the update shader
+         */        
+        public applyToShader(effect: Effect): void {
+            effect.setFloat("radius", this.radius);
+            effect.setFloat("height", this.height);
+            effect.setFloat("radiusRange", this.radiusRange);
+            effect.setFloat("directionRandomizer", this.directionRandomizer);
+        }    
+        
+        /**
+         * Returns a string to use to update the GPU particles update shader
+         * @returns a string containng the defines string
+         */
+        public getEffectDefines(): string {
+            return "#define CYLINDEREMITTER"
+        }   
+        
+        /**
+         * Returns the string "CylinderParticleEmitter"
+         * @returns a string containing the class name
+         */
+        public getClassName(): string {
+            return "CylinderParticleEmitter";
+        }         
+        
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */        
+        public serialize(): any {
+            var serializationObject: any = {};
+            serializationObject.type = this.getClassName();
+            serializationObject.radius = this.radius;
+            serializationObject.height = this.height;
+            serializationObject.radiusRange = this.radiusRange;
+            serializationObject.directionRandomizer = this.directionRandomizer;
+
+            return serializationObject;
+        }    
+        
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            this.radius = serializationObject.radius;
+            this.height = serializationObject.height;
+            this.radiusRange = serializationObject.radiusRange;
+            this.directionRandomizer = serializationObject.directionRandomizer;
+        }          
+    }
+}

+ 24 - 0
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -48,6 +48,13 @@ uniform float radiusRange;
 #endif
 #endif
 
+#ifdef CYLINDEREMITTER
+uniform float radius;
+uniform float height;
+uniform float radiusRange;
+uniform float directionRandomizer;
+#endif
+
 #ifdef CONEEMITTER
 uniform vec2 radius;
 uniform float coneAngle;
@@ -233,6 +240,23 @@ void main() {
       // Direction
       direction = position + directionRandomizer * randoms3;
     #endif
+#elif defined(CYLINDEREMITTER)
+    vec3 randoms2 = getRandomVec3(seed.y);
+    vec3 randoms3 = getRandomVec3(seed.z);
+
+    // Position on the cylinder
+    float yPos = (randoms2.x - 0.5)*height;
+    float angle = randoms2.y * PI * 2.;
+    float inverseRadiusRangeSquared = ((1.-radiusRange) * (1.-radiusRange));
+    float positionRadius = radius*sqrt(inverseRadiusRangeSquared + (randoms2.z * (1.-inverseRadiusRangeSquared)));
+    float xPos = positionRadius * cos(angle);
+    float zPos = positionRadius * sin(angle);
+    position = vec3(xPos, yPos, zPos);
+
+    // Direction
+    angle = angle + ((randoms3.x-0.5) * PI);
+    direction = vec3(cos(angle), randoms3.y-0.5, sin(angle));
+    direction = normalize(direction);
 #elif defined(CONEEMITTER)
     vec3 randoms2 = getRandomVec3(seed.y);