Explorar el Código

BoxEmitter / Sphere emitte - associated with #2033

David Catuhe hace 7 años
padre
commit
9be0b92b74

+ 11 - 2
src/Engine/babylon.engine.ts

@@ -349,6 +349,7 @@
         private static _TEXTUREFORMAT_R32F = 6;
         private static _TEXTUREFORMAT_RG32F = 7;
         private static _TEXTUREFORMAT_RGB32F = 8;
+        private static _TEXTUREFORMAT_RGBA32F = 9;
 
         private static _TEXTURETYPE_UNSIGNED_INT = 0;
         private static _TEXTURETYPE_FLOAT = 1;
@@ -520,7 +521,14 @@
          */
         public static get TEXTUREFORMAT_RGB32F(): number {
             return Engine._TEXTUREFORMAT_RGB32F;
-        }               
+        }       
+        
+        /**
+         * RGBA32F
+         */
+        public static get TEXTUREFORMAT_RGBA32F(): number {
+            return Engine._TEXTUREFORMAT_RGBA32F;
+        }             
 
         public static get TEXTUREFORMAT_LUMINANCE_ALPHA(): number {
             return Engine._TEXTUREFORMAT_LUMINANCE_ALPHA;
@@ -565,7 +573,7 @@
         }
 
         public static get Version(): string {
-            return "3.2.0-alpha7";
+            return "3.2.0-alpha8";
         }
 
         // Updatable statics so stick with vars here
@@ -3411,6 +3419,7 @@
                     internalFormat = this._gl.RGB;
                     break;
                 case Engine.TEXTUREFORMAT_RGBA:
+                case Engine.TEXTUREFORMAT_RGBA32F:
                     internalFormat = this._gl.RGBA;
                     break;
                 case Engine.TEXTUREFORMAT_R32F:

+ 2 - 0
src/Particles/EmitterTypes/babylon.boxParticleEmitter.ts

@@ -79,6 +79,8 @@ module BABYLON {
         public applyToShader(effect: Effect): void {            
             effect.setVector3("direction1", this.direction1);
             effect.setVector3("direction2", this.direction2);
+            effect.setVector3("minEmitBox", this.minEmitBox);
+            effect.setVector3("maxEmitBox", this.maxEmitBox);
         }
 
         /**

+ 5 - 2
src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts

@@ -88,7 +88,7 @@ module BABYLON {
 
             var randX = radius * Math.sin(s);
             var randZ = radius * Math.cos(s);
-            var randY = h;
+            var randY = h * this._height;
 
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
@@ -110,7 +110,10 @@ module BABYLON {
          * @param effect defines the update shader
          */        
         public applyToShader(effect: Effect): void {
-            
+            effect.setFloat("radius", this.radius);
+            effect.setFloat("angle", this.angle);
+            effect.setFloat("height", this._height);
+            effect.setFloat("directionRandomizer", this.directionRandomizer);
         }
 
         /**

+ 6 - 3
src/Particles/EmitterTypes/babylon.sphereParticleEmitter.ts

@@ -74,7 +74,8 @@ module BABYLON {
          * @param effect defines the update shader
          */        
         public applyToShader(effect: Effect): void {
-            
+            effect.setFloat("radius", this.radius);
+            effect.setFloat("directionRandomizer", this.directionRandomizer);
         }    
         
         /**
@@ -140,14 +141,16 @@ module BABYLON {
          * @param effect defines the update shader
          */        
         public applyToShader(effect: Effect): void {
-            
+            effect.setFloat("radius", this.radius);
+            effect.setVector3("direction1", this.direction1);
+            effect.setVector3("direction2", this.direction2);
         }       
         
         /**
          * Returns a string to use to update the GPU particles update shader
          */
         public getEffectDefines(): string {
-            return "#define SPHEREEMITTER"
+            return "#define SPHEREEMITTER\n#define DIRECTEDSPHEREEMITTER"
         }          
     }
 }

+ 22 - 9
src/Particles/babylon.gpuParticleSystem.ts

@@ -128,10 +128,19 @@
         public gravity = Vector3.Zero();    
 
         /**
+         * Minimum power of emitting particles.
+         */
+        public minEmitPower = 1;
+        /**
+         * Maximum power of emitting particles.
+         */
+        public maxEmitPower = 1;        
+
+        /**
          * The particle emitter type defines the emitter used by the particle system.
          * It can be for example box, sphere, or cone...
          */
-        public particleEmitterType: IParticleEmitterType;        
+        public particleEmitterType: Nullable<IParticleEmitterType>;        
 
         /**
          * Gets the maximum number of particles supported by this system
@@ -203,7 +212,8 @@
 
             this._updateEffectOptions = {
                 attributes: ["position", "age", "life", "seed", "size", "color", "direction"],
-                uniformsNames: ["currentCount", "timeDelta", "generalRandoms", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "gravity", "direction1", "direction2"],
+                uniformsNames: ["currentCount", "timeDelta", "generalRandoms", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "gravity", "emitPower",
+                                "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "angle"],
                 uniformBuffersNames: [],
                 samplers:["randomSampler"],
                 defines: "",
@@ -226,13 +236,11 @@
                 d.push(Math.random());
                 d.push(Math.random());
                 d.push(Math.random());
+                d.push(Math.random());
             }
-            this._randomTexture = new RawTexture(new Float32Array(d), maxTextureSize, 1, Engine.TEXTUREFORMAT_RGB32F, this._scene, false, false, Texture.NEAREST_SAMPLINGMODE, Engine.TEXTURETYPE_FLOAT)
+            this._randomTexture = new RawTexture(new Float32Array(d), maxTextureSize, 1, Engine.TEXTUREFORMAT_RGBA32F, this._scene, false, false, Texture.NEAREST_SAMPLINGMODE, Engine.TEXTURETYPE_FLOAT)
             this._randomTexture.wrapU = Texture.WRAP_ADDRESSMODE;
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
-
-            // Default emitter type
-            this.particleEmitterType = new BoxParticleEmitter();            
         }
 
         /**
@@ -349,7 +357,9 @@
          * @returns the current number of particles
          */
         public render(): number {
-            this._recreateUpdateEffect(this.particleEmitterType.getEffectDefines());
+            if (this.particleEmitterType) {
+                this._recreateUpdateEffect(this.particleEmitterType.getEffectDefines());
+            }
 
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
@@ -374,15 +384,18 @@
             
             this._updateEffect.setFloat("currentCount", this._currentActiveCount);
             this._updateEffect.setFloat("timeDelta", this._timeDelta);
-            this._updateEffect.setFloat2("generalRandoms", Math.random(), Math.random());
+            this._updateEffect.setFloat3("generalRandoms", Math.random(), Math.random(), Math.random());
             this._updateEffect.setTexture("randomSampler", this._randomTexture);
             this._updateEffect.setFloat2("lifeTime", this.minLifeTime, this.maxLifeTime);
+            this._updateEffect.setFloat2("emitPower", this.minEmitPower, this.maxEmitPower);
             this._updateEffect.setDirectColor4("color1", this.color1);
             this._updateEffect.setDirectColor4("color2", this.color2);
             this._updateEffect.setFloat2("sizeRange", this.minSize, this.maxSize);
             this._updateEffect.setVector3("gravity", this.gravity);
 
-            this.particleEmitterType.applyToShader(this._updateEffect);
+            if (this.particleEmitterType) {
+                this.particleEmitterType.applyToShader(this._updateEffect);
+            }
 
             let emitterWM: Matrix;
             if ((<AbstractMesh>this.emitter).position) {

+ 92 - 8
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -1,10 +1,13 @@
 #version 300 es
 
+#define PI 3.14159
+
 uniform float currentCount;
 uniform float timeDelta;
-uniform vec2 generalRandoms;
+uniform vec3 generalRandoms;
 uniform mat4 emitterWM;
 uniform vec2 lifeTime;
+uniform vec2 emitPower;
 uniform vec2 sizeRange;
 uniform vec4 color1;
 uniform vec4 color2;
@@ -14,6 +17,25 @@ uniform sampler2D randomSampler;
 #ifdef BOXEMITTER
 uniform vec3 direction1;
 uniform vec3 direction2;
+uniform vec3 minEmitBox;
+uniform vec3 maxEmitBox;
+#endif
+
+#ifdef SPHEREEMITTER
+uniform float radius;
+  #ifdef DIRECTEDSPHEREEMITTER
+  uniform vec3 direction1;
+  uniform vec3 direction2;
+  #else
+  uniform float directionRandomizer;
+  #endif
+#endif
+
+#ifdef CONEEMITTER
+uniform float radius;
+uniform float angle;
+uniform float height;
+uniform float directionRandomizer;
 #endif
 
 // Particles state
@@ -38,14 +60,18 @@ vec3 getRandomVec3(float offset) {
   return texture(randomSampler, vec2(float(gl_VertexID) * offset / currentCount, 0)).rgb;
 }
 
+vec4 getRandomVec4(float offset) {
+  return texture(randomSampler, vec2(float(gl_VertexID) * offset / currentCount, 0));
+}
+
+
 void main() {
   if (age >= life) {
-    // Create the particle at origin
-    outPosition = (emitterWM * vec4(0., 0., 0., 1.)).xyz;
+    vec3 position;
+    vec3 direction;
 
     // Let's get some random values
-    vec3 randoms = getRandomVec3(generalRandoms.x);
-    vec3 randoms2 = getRandomVec3(generalRandoms.y);
+    vec4 randoms = getRandomVec4(generalRandoms.x);
 
     // Age and life
     outAge = 0.0;
@@ -60,12 +86,70 @@ void main() {
     // Color
     outColor = color1 + (color2 - color1) * randoms.b;
 
-    // Direction
+    // Position / Direction (based on emitter type)
 #ifdef BOXEMITTER
-    outDirection = direction1 + (direction2 - direction1) * randoms2;
+    vec3 randoms2 = getRandomVec3(generalRandoms.y);
+    vec3 randoms3 = getRandomVec3(generalRandoms.z);
+
+    position = minEmitBox + (maxEmitBox - minEmitBox) * randoms2;
+
+    direction = direction1 + (direction2 - direction1) * randoms3;
+#elif defined(SPHEREEMITTER)
+    vec3 randoms2 = getRandomVec3(generalRandoms.y);
+    vec3 randoms3 = getRandomVec3(generalRandoms.z);
+
+    // Position on the sphere surface
+    float phi = 2.0 * PI * randoms2.x;
+    float theta = PI * randoms2.y;
+    float randX = cos(phi) * sin(theta);
+    float randY = cos(theta);
+    float randZ = sin(phi) * sin(theta);
+
+    position = radius * vec3(randX, randY, randZ);
+
+    #ifdef DIRECTEDSPHEREEMITTER
+      direction = direction1 + (direction2 - direction1) * randoms3;
+    #else
+        // Direction
+        direction = position + directionRandomizer * randoms3;
+    #endif
+#elif defined(CONEEMITTER)
+    vec3 randoms2 = getRandomVec3(generalRandoms.y);
+
+    float s = 2.0 * PI * randoms2.x;
+    float h = randoms2.y;
+    
+    // Better distribution in a cone at normal angles.
+    h = 1. - h * h;
+    float lRadius = radius * randoms2.z;
+    lRadius = lRadius * h / height;
+
+    float randX = lRadius * sin(s);
+    float randZ = lRadius * cos(s);
+    float randY = h  * height;
+
+    position = vec3(randX, randY, randZ); 
+
+    // Direction
+    if (angle == 0.) {
+      direction = vec3(0., 1.0, 0.);
+    } else {
+      vec3 randoms3 = getRandomVec3(generalRandoms.z);
+      direction = position + directionRandomizer * randoms3;
+    }
 #else    
-    outDirection = 2.0 * (getRandomVec3(seed) - vec3(0.5, 0.5, 0.5));
+    // Create the particle at origin
+    position = vec3(0., 0., 0.);
+
+    // Spread in all directions
+    direction = 2.0 * (getRandomVec3(seed) - vec3(0.5, 0.5, 0.5));
 #endif
+
+    float power = emitPower.x + (emitPower.y - emitPower.x) * randoms.a;
+
+    outPosition = (emitterWM * vec4(position, 1.)).xyz;
+    outDirection = (emitterWM * vec4(normalize(direction) * power, 0.)).xyz;
+
   } else {   
     outPosition = position + (direction + gravity) * timeDelta;
     outAge = age + timeDelta;