ソースを参照

Fix particle direction issue

David Catuhe 7 年 前
コミット
22f2dc335b

ファイルの差分が大きいため隠しています
+ 1791 - 1793
dist/preview release/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 8 - 8
dist/preview release/babylon.js


ファイルの差分が大きいため隠しています
+ 74 - 22
dist/preview release/babylon.max.js


ファイルの差分が大きいため隠しています
+ 74 - 22
dist/preview release/babylon.no-module.max.js


ファイルの差分が大きいため隠しています
+ 8 - 8
dist/preview release/babylon.worker.js


ファイルの差分が大きいため隠しています
+ 74 - 22
dist/preview release/es6.js


ファイルの差分が大きいため隠しています
+ 8 - 8
dist/preview release/viewer/babylon.viewer.js


ファイルの差分が大きいため隠しています
+ 74 - 22
dist/preview release/viewer/babylon.viewer.max.js


+ 81 - 42
src/Particles/babylon.gpuParticleSystem.ts

@@ -57,7 +57,7 @@
 
         private _randomTexture: RawTexture;
 
-        private readonly _attributesStrideSize = 19;
+        private _attributesStrideSize = 18;
         private _updateEffectOptions: EffectCreationOptions;
 
         private _randomTextureSize: number;
@@ -359,6 +359,8 @@
             }
 
             this._isBillboardBased = value;
+
+            this._releaseBuffers();
         }          
 
         /**
@@ -390,7 +392,7 @@
             this._scene.particleSystems.push(this);
 
             this._updateEffectOptions = {
-                attributes: ["position", "age", "life", "seed", "size", "color", "direction", "angle"],
+                attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle"],
                 uniformsNames: ["currentCount", "timeDelta", "generalRandoms", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange","gravity", "emitPower",
                                 "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor", 
                                 "angleRange", "radiusRange"],
@@ -402,7 +404,7 @@
                 onError: null,
                 indexParameters: null,
                 maxSimultaneousLights: 0,                                                      
-                transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection", "outAngle"]
+                transformFeedbackVaryings: []
             };
 
             // Random data
@@ -430,8 +432,15 @@
             updateVertexBuffers["seed"] = source.createVertexBuffer("seed", 5, 1);
             updateVertexBuffers["size"] = source.createVertexBuffer("size", 6, 3);
             updateVertexBuffers["color"] = source.createVertexBuffer("color", 9, 4);
-            updateVertexBuffers["direction"] = source.createVertexBuffer("direction", 13, 4);
-            updateVertexBuffers["angle"] = source.createVertexBuffer("angle", 17, 2);
+            updateVertexBuffers["direction"] = source.createVertexBuffer("direction", 13, 3);
+
+            let offset = 16;
+            if (!this._isBillboardBased) {
+                updateVertexBuffers["initialDirection"] = source.createVertexBuffer("initialDirection", offset, 3);
+                offset += 3;
+            }
+
+            updateVertexBuffers["angle"] = source.createVertexBuffer("angle", offset, 2);
            
             let vao = this._engine.recordVertexArrayObject(updateVertexBuffers, null, this._updateEffect);
             this._engine.bindArrayBuffer(null);
@@ -446,8 +455,13 @@
             renderVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1, this._attributesStrideSize, true);
             renderVertexBuffers["size"] = source.createVertexBuffer("size", 6, 3, this._attributesStrideSize, true);           
             renderVertexBuffers["color"] = source.createVertexBuffer("color", 9, 4, this._attributesStrideSize, true);
-            renderVertexBuffers["direction"] = source.createVertexBuffer("direction", 13, 4, this._attributesStrideSize, true);
-            renderVertexBuffers["angle"] = source.createVertexBuffer("angle", 17, 2, this._attributesStrideSize, true);
+
+            let offset = 16;
+            if (!this._isBillboardBased) {
+                renderVertexBuffers["initialDirection"] = source.createVertexBuffer("initialDirection", offset, 3, this._attributesStrideSize, true);
+                offset += 3;
+            }
+            renderVertexBuffers["angle"] = source.createVertexBuffer("angle", offset, 2, this._attributesStrideSize, true);
 
             renderVertexBuffers["offset"] = spriteSource.createVertexBuffer("offset", 0, 2);
             renderVertexBuffers["uv"] = spriteSource.createVertexBuffer("uv", 2, 2);
@@ -465,39 +479,50 @@
 
             let engine = this._scene.getEngine();
             var data = new Array<float>();
+
+            if (!this.isBillboardBased) {
+                this._attributesStrideSize = 21;
+            }
+
             for (var particleIndex = 0; particleIndex < this._capacity; particleIndex++) {
-              // position
-              data.push(0.0);
-              data.push(0.0);
-              data.push(0.0);
-
-              // Age and life
-              data.push(0.0); // create the particle as a dead one to create a new one at start
-              data.push(0.0);
-
-              // Seed
-              data.push(Math.random());
-
-              // Size
-              data.push(0.0);
-              data.push(0.0);
-              data.push(0.0);
-
-              // color
-              data.push(0.0);
-              data.push(0.0);
-              data.push(0.0);                     
-              data.push(0.0); 
-
-              // direction
-              data.push(0.0);
-              data.push(0.0);
-              data.push(0.0);  
-              data.push(0.0);    
-              
-              // angle
-              data.push(0.0);  
-              data.push(0.0); 
+                // position
+                data.push(0.0);
+                data.push(0.0);
+                data.push(0.0);
+
+                // Age and life
+                data.push(0.0); // create the particle as a dead one to create a new one at start
+                data.push(0.0);
+
+                // Seed
+                data.push(Math.random());
+
+                // Size
+                data.push(0.0);
+                data.push(0.0);
+                data.push(0.0);
+
+                // color
+                data.push(0.0);
+                data.push(0.0);
+                data.push(0.0);                     
+                data.push(0.0); 
+
+                // direction
+                data.push(0.0);
+                data.push(0.0);
+                data.push(0.0);  
+
+                if (!this.isBillboardBased) {
+                    // initialDirection
+                    data.push(0.0);
+                    data.push(0.0);
+                    data.push(0.0);  
+                }
+
+                // angle
+                data.push(0.0);  
+                data.push(0.0); 
             }
 
             // Sprite data
@@ -530,9 +555,23 @@
         /** @hidden */
         public _recreateUpdateEffect() {
             let defines = this.particleEmitterType ? this.particleEmitterType.getEffectDefines() : "";
+
+            if (this._isBillboardBased) {
+                defines += "\n#define BILLBOARD";
+            }   
+
             if (this._updateEffect && this._updateEffectOptions.defines === defines) {
                 return;
             }
+
+            this._updateEffectOptions.transformFeedbackVaryings = ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection"];           
+
+            if (!this._isBillboardBased) {
+                this._updateEffectOptions.transformFeedbackVaryings.push("outInitialDirection");
+            }
+
+            this._updateEffectOptions.transformFeedbackVaryings.push("outAngle");
+
             this._updateEffectOptions.defines = defines;
             this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
         }
@@ -545,7 +584,7 @@
             }
 
             if (this._isBillboardBased) {
-                defines = "\n#define BILLBOARD";
+                defines += "\n#define BILLBOARD";
             }            
 
             if (this._renderEffect && this._renderEffect.defines === defines) {
@@ -553,7 +592,7 @@
             }
 
             this._renderEffect = new Effect("gpuRenderParticles", 
-                                            ["position", "age", "life", "size", "color", "offset", "uv", "direction", "angle"], 
+                                            ["position", "age", "life", "size", "color", "offset", "uv", "initialDirection", "angle"], 
                                             ["view", "projection", "colorDead", "invView", "vClipPlane"], 
                                             ["textureSampler"], this._scene.getEngine(), defines);
         }        
@@ -595,7 +634,7 @@
             this._currentRenderId = this._scene.getRenderId();      
             
             // Get everything ready to render
-            this. _initialize();
+            this._initialize();
 
             this._currentActiveCount = Math.min(this._activeCount, this._currentActiveCount + (this.emitRate * this._timeDelta) | 0);
             

+ 13 - 6
src/Particles/babylon.particle.ts

@@ -58,15 +58,13 @@
         /**
          * Defines the cell index used by the particle to be rendered from a sprite.
          */
-        public cellIndex: number = 0;
-
-        /**
-         * Defines the energy applied to the particle direction.
-         */
-        public emitPower = 0;        
+        public cellIndex: number = 0;  
 
         private _currentFrameCounter = 0;
 
+        /** @hidden */
+        public _initialDirection: Nullable<Vector3>;
+
         /**
          * Creates a new instance Particle
          * @param particleSystem the particle system the particle belongs to
@@ -138,6 +136,15 @@
          */
         public copyTo(other: Particle) {
             other.position.copyFrom(this.position);
+            if (this._initialDirection) {
+                if (other._initialDirection) {
+                    other._initialDirection.copyFrom(this._initialDirection);
+                } else {
+                    other._initialDirection = this._initialDirection.clone();
+                }
+            } else {
+                other._initialDirection = null;
+            }
             other.direction.copyFrom(this.direction);
             other.color.copyFrom(this.color);
             other.colorStep.copyFrom(this.colorStep);

+ 25 - 7
src/Particles/babylon.particleSystem.ts

@@ -459,7 +459,7 @@
                         continue;
                     }
                     else {
-                        if (this._colorGradients) {
+                        if (this._colorGradients && this._colorGradients.length > 0) {
                             let ratio = particle.age / particle.lifeTime;
 
                             for (var gradientIndex = 0; gradientIndex < this._colorGradients.length - 1; gradientIndex++) {
@@ -483,7 +483,7 @@
                         }
                         particle.angle += particle.angularSpeed * this._scaledUpdateSpeed;
 
-                        particle.direction.scaleToRef(this._scaledUpdateSpeed * particle.emitPower, this._scaledDirection);
+                        particle.direction.scaleToRef(this._scaledUpdateSpeed, this._scaledDirection);
                         particle.position.addInPlace(this._scaledDirection);
 
                         this.gravity.scaleToRef(this._scaledUpdateSpeed, this._scaledGravity);
@@ -715,9 +715,15 @@
             }
 
             if (!this._isBillboardBased) {
-                this._vertexData[offset++] = particle.direction.x;
-                this._vertexData[offset++] = particle.direction.y;
-                this._vertexData[offset++] = particle.direction.z;
+                if (particle._initialDirection) {
+                    this._vertexData[offset++] = particle._initialDirection.x;
+                    this._vertexData[offset++] = particle._initialDirection.y;
+                    this._vertexData[offset++] = particle._initialDirection.z;
+                } else {
+                    this._vertexData[offset++] = particle.direction.x;
+                    this._vertexData[offset++] = particle.direction.y;
+                    this._vertexData[offset++] = particle.direction.z;
+                }
             }
 
             if (!this._useInstancing) {
@@ -828,7 +834,7 @@
 
                 this._particles.push(particle);
 
-                particle.emitPower = Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
+                let emitPower = Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
 
                 if (this.startPositionFunction) {
                     this.startPositionFunction(worldMatrix, particle.position, particle);
@@ -844,13 +850,25 @@
                     this.particleEmitterType.startDirectionFunction(worldMatrix, particle.direction, particle);
                 }
 
+                if (emitPower === 0) {
+                    if (!particle._initialDirection) {
+                        particle._initialDirection = particle.direction.clone();
+                    } else {
+                        particle._initialDirection.copyFrom(particle.direction);
+                    }
+                } else {
+                    particle._initialDirection = null;
+                }
+
+                particle.direction.scaleInPlace(emitPower);
+
                 particle.lifeTime = Scalar.RandomRange(this.minLifeTime, this.maxLifeTime);
 
                 particle.size = Scalar.RandomRange(this.minSize, this.maxSize);
                 particle.scale.copyFromFloats(Scalar.RandomRange(this.minScaleX, this.maxScaleX), Scalar.RandomRange(this.minScaleY, this.maxScaleY));
                 particle.angularSpeed = Scalar.RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
 
-                if (!this._colorGradients) {
+                if (!this._colorGradients || this._colorGradients.length === 0) {
                     var step = Scalar.RandomRange(0, 1.0);
 
                     Color4.LerpToRef(this.color1, this.color2, step, particle.color);

+ 5 - 3
src/Shaders/gpuRenderParticles.vertex.fx

@@ -10,10 +10,12 @@ in float age;
 in float life;
 in vec3 size;
 in vec4 color;
+#ifndef BILLBOARD
+in vec3 initialDirection;
+#endif
+in vec2 angle;
 in vec2 offset;
 in vec2 uv;
-in vec4 direction;
-in vec2 angle;
 
 out vec2 vUV;
 out vec4 vColor;
@@ -50,7 +52,7 @@ void main() {
 	rotatedCorner.y = 0.;
 	rotatedCorner.z = cornerPos.x * sin(angle.x) + cornerPos.y * cos(angle.x);
 
-	vec3 yaxis = normalize(direction.xyz);
+	vec3 yaxis = normalize(initialDirection);
 	vec3 xaxis = normalize(cross(vec3(0., 1.0, 0.), yaxis));
 	vec3 zaxis = normalize(cross(yaxis, xaxis));
 

+ 22 - 7
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -49,7 +49,10 @@ in float life;
 in float seed;
 in vec3 size;
 in vec4 color;
-in vec4 direction;
+in vec3 direction;
+#ifndef BILLBOARD
+in vec3 initialDirection;
+#endif
 in vec2 angle;
 
 // Output
@@ -59,7 +62,10 @@ out float outLife;
 out float outSeed;
 out vec3 outSize;
 out vec4 outColor;
-out vec4 outDirection;
+out vec3 outDirection;
+#ifndef BILLBOARD
+out vec3 outInitialDirection;
+#endif
 out vec2 outAngle;
 
 vec3 getRandomVec3(float offset) {
@@ -80,6 +86,9 @@ void main() {
       outSeed = seed;
       outColor = vec4(0.,0.,0.,0.);
       outSize = vec3(0., 0., 0.);
+#ifndef BILLBOARD        
+      outInitialDirection = initialDirection;
+#endif      
       outDirection = direction;
       outAngle = angle;
       return;
@@ -168,20 +177,26 @@ void main() {
     direction = 2.0 * (getRandomVec3(seed) - vec3(0.5, 0.5, 0.5));
 #endif
 
-    outDirection.w = emitPower.x + (emitPower.y - emitPower.x) * randoms.a;
+    float power = emitPower.x + (emitPower.y - emitPower.x) * randoms.a;
 
     outPosition = (emitterWM * vec4(position, 1.)).xyz;
-    outDirection.xyz = (emitterWM * vec4(direction, 0.)).xyz;
+    vec3 initial = (emitterWM * vec4(direction, 0.)).xyz;
+    outDirection = initial * power;
+#ifndef BILLBOARD        
+    outInitialDirection = initial;
+#endif
 
   } else {   
-    outPosition = position + direction.xyz * timeDelta * direction.w;
+    outPosition = position + direction * timeDelta;
     outAge = age + timeDelta;
     outLife = life;
     outSeed = seed;
     outColor = color;
     outSize = size;
-    outDirection.w = direction.w;
-    outDirection.xyz = direction.xyz + gravity * timeDelta;
+#ifndef BILLBOARD    
+    outInitialDirection = initialDirection;
+#endif
+    outDirection = direction + gravity * timeDelta;
     outAngle = vec2(angle.x + angle.y * timeDelta, angle.y);
   }
 }

BIN
tests/validation/ReferenceImages/particles.png


BIN
tests/validation/ReferenceImages/yeti.png