浏览代码

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

Jaskar 7 年之前
父节点
当前提交
50ecb1a00d
共有 39 个文件被更改,包括 3947 次插入2588 次删除
  1. 1567 1473
      Playground/babylon.d.txt
  2. 1 0
      Tools/Gulp/config.json
  3. 1093 944
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 250 13
      dist/preview release/babylon.max.js
  6. 250 13
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 252 15
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  10. 15 1
      dist/preview release/viewer/babylon.viewer.d.ts
  11. 1 1
      dist/preview release/viewer/babylon.viewer.js
  12. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  13. 18 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  14. 3 0
      dist/preview release/what's new.md
  15. 1 1
      package.json
  16. 24 5
      src/Actions/babylon.actionManager.ts
  17. 12 12
      src/Animations/babylon.animation.ts
  18. 57 40
      src/Animations/babylon.runtimeAnimation.ts
  19. 12 14
      src/Culling/babylon.boundingBox.ts
  20. 14 10
      src/Culling/babylon.boundingSphere.ts
  21. 5 2
      src/Materials/Background/babylon.backgroundMaterial.ts
  22. 5 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  23. 2 0
      src/Materials/babylon.standardMaterial.ts
  24. 8 9
      src/Mesh/babylon.mesh.ts
  25. 2 2
      src/Mesh/babylon.transformNode.ts
  26. 138 0
      src/Particles/EmitterTypes/babylon.cylinderParticleEmitter.ts
  27. 14 0
      src/Particles/babylon.IParticleSystem.ts
  28. 25 1
      src/Particles/babylon.baseParticleSystem.ts
  29. 36 0
      src/Particles/babylon.gpuParticleSystem.ts
  30. 14 2
      src/Particles/babylon.particle.ts
  31. 57 2
      src/Particles/babylon.particleSystem.ts
  32. 4 0
      src/Shaders/ShadersInclude/defaultVertexDeclaration.fx
  33. 5 1
      src/Shaders/background.vertex.fx
  34. 5 1
      src/Shaders/default.vertex.fx
  35. 24 0
      src/Shaders/gpuUpdateParticles.vertex.fx
  36. 14 10
      src/Shaders/pbr.vertex.fx
  37. 13 10
      src/babylon.scene.ts
  38. 二进制
      tests/validation/ReferenceImages/ssao2.png
  39. 2 1
      what's new.md

文件差异内容过多而无法显示
+ 1567 - 1473
Playground/babylon.d.txt


+ 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",

文件差异内容过多而无法显示
+ 1093 - 944
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.js


文件差异内容过多而无法显示
+ 250 - 13
dist/preview release/babylon.max.js


文件差异内容过多而无法显示
+ 250 - 13
dist/preview release/babylon.no-module.max.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.worker.js


文件差异内容过多而无法显示
+ 252 - 15
dist/preview release/es6.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 15 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 18 - 1
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

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

@@ -107,6 +107,9 @@
 - 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 and constructor in baseParticle ([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))
 
 ### glTF Loader
 

+ 1 - 1
package.json

@@ -43,4 +43,4 @@
         "base64-font-loader": "0.0.4",
         "typescript": "^3.0.1"
     }
-}
+}

+ 24 - 5
src/Actions/babylon.actionManager.ts

@@ -15,15 +15,15 @@
          */
         constructor(
             /** The mesh or sprite that triggered the action */
-            public source: any, 
+            public source: any,
             /** The X mouse cursor position at the time of the event */
-            public pointerX: number, 
+            public pointerX: number,
             /** The Y mouse cursor position at the time of the event */
-            public pointerY: number, 
+            public pointerY: number,
             /** The mesh that is currently pointed at (can be null) */
-            public meshUnderPointer: Nullable<AbstractMesh>, 
+            public meshUnderPointer: Nullable<AbstractMesh>,
             /** the original (browser) event that triggered the ActionEvent */
-            public sourceEvent?: any, 
+            public sourceEvent?: any,
             /** additional data for the event */
             public additionalData?: any) {
 
@@ -307,6 +307,25 @@
         }
 
         /**
+         * Does this action manager handles actions of any of the given triggers. This function takes two arguments for 
+         * speed.
+         * @param triggerA defines the trigger to be tested
+         * @param triggerB defines the trigger to be tested
+         * @return a boolean indicating whether one (or more) of the triggers is handled 
+         */
+        public hasSpecificTriggers2(triggerA: number, triggerB: number): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (triggerA == action.trigger || triggerB == action.trigger) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
          * Does this action manager handles actions of a given trigger
          * @param trigger defines the trigger to be tested
          * @param parameterPredicate defines an optional predicate to filter triggers by parameter

+ 12 - 12
src/Animations/babylon.animation.ts

@@ -11,9 +11,9 @@
          */
         constructor(
             /**The name of the animation range**/
-            public name: string, 
+            public name: string,
             /**The starting frame of the animation */
-            public from: number, 
+            public from: number,
             /**The ending frame of the animation*/
             public to: number) {
         }
@@ -46,9 +46,9 @@
             /** The frame for which the event is triggered **/
             public frame: number,
             /** The event to perform when triggered **/
-            public action: (currentFrame: number) => void , 
+            public action: (currentFrame: number) => void,
             /** Specifies if the event should be triggered only once**/
-            public onlyOnce?: boolean ) {
+            public onlyOnce?: boolean) {
         }
 
         /** @hidden */
@@ -472,15 +472,15 @@
          */
         constructor(
             /**Name of the animation */
-            public name: string, 
+            public name: string,
             /**Property to animate */
-            public targetProperty: string, 
+            public targetProperty: string,
             /**The frames per second of the animation */
-            public framePerSecond: number, 
+            public framePerSecond: number,
             /**The data type of the animation */
             public dataType: number,
-            /**The loop mode of the animation */ 
-            public loopMode?: number, 
+            /**The loop mode of the animation */
+            public loopMode?: number,
             /**Specifies if blending should be enabled */
             public enableBlending?: boolean) {
             this.targetPropertyPath = targetProperty.split(".");
@@ -757,7 +757,7 @@
             }
 
             return value;
-        } 
+        }
 
         /**
          * @hidden Internal use only
@@ -896,7 +896,7 @@
         public matrixInterpolateFunction(startValue: Matrix, endValue: Matrix, gradient: number, result?: Matrix): Matrix {
             if (Animation.AllowMatrixDecomposeForInterpolation) {
                 if (result) {
-                    Matrix.DecomposeLerpToRef(startValue, endValue, gradient, result);    
+                    Matrix.DecomposeLerpToRef(startValue, endValue, gradient, result);
                     return result;
                 }
                 return Matrix.DecomposeLerp(startValue, endValue, gradient);
@@ -1121,7 +1121,7 @@
             } else if (constructor.Slerp) { // Slerp supported
                 return constructor.Slerp(left, right, amount);
             } else if (left.toFixed) { // Number
-                return left * (1.0 - amount) + amount* right;
+                return left * (1.0 - amount) + amount * right;
             } else { // Blending not supported
                 return right;
             }

+ 57 - 40
src/Animations/babylon.runtimeAnimation.ts

@@ -1,5 +1,22 @@
 module BABYLON {
 
+    // Static values to help the garbage collector
+
+    // Quaternion
+    const _staticOffsetValueQuaternion: Readonly<Quaternion> = Object.freeze(new Quaternion(0, 0, 0, 0));
+
+    // Vector3
+    const _staticOffsetValueVector3: Readonly<Vector3> = Object.freeze(Vector3.Zero());
+
+    // Vector2
+    const _staticOffsetValueVector2: Readonly<Vector2> = Object.freeze(Vector2.Zero());
+
+    // Size
+    const _staticOffsetValueSize: Readonly<Size> = Object.freeze(Size.Zero());
+
+    // Color3
+    const _staticOffsetValueColor3: Readonly<Color3> = Object.freeze(Color3.Black());
+
     /**
      * Defines a runtime animation
      */
@@ -15,7 +32,7 @@
          * The animation used by the runtime animation
          */
         private _animation: Animation;
-        
+
         /**
          * The target of the runtime animation
          */
@@ -25,37 +42,37 @@
          * The initiating animatable
          */
         private _host: Animatable;
-        
+
         /**
          * The original value of the runtime animation
          */
         private _originalValue = new Array<any>();
-        
+
         /**
          * The original blend value of the runtime animation
          */
         private _originalBlendValue: any;
-        
+
         /**
          * The offsets cache of the runtime animation
          */
-        private _offsetsCache: {[key: string]: any} = {};
-        
+        private _offsetsCache: { [key: string]: any } = {};
+
         /**
          * The high limits cache of the runtime animation
          */
-        private _highLimitsCache: {[key: string]: any} = {};
-        
+        private _highLimitsCache: { [key: string]: any } = {};
+
         /**
          * Specifies if the runtime animation has been stopped
          */
         private _stopped = false;
-        
+
         /**
          * The blending factor of the runtime animation
          */
         private _blendingFactor = 0;
-        
+
         /**
          * The BabylonJS scene
          */
@@ -65,20 +82,20 @@
          * The current value of the runtime animation
          */
         private _currentValue: any;
-        
+
         /** @hidden */
         public _workValue: any;
-        
+
         /**
          * The active target of the runtime animation
          */
         private _activeTarget: any;
-        
+
         /**
          * The target path of the runtime animation
          */
         private _targetPath: string = "";
-        
+
         /**
          * The weight of the runtime animation
          */
@@ -93,7 +110,7 @@
          * The previous delay of the runtime animation
          */
         private _previousDelay: number = 0;
-        
+
         /**
          * The previous ratio of the runtime animation
          */
@@ -111,7 +128,7 @@
          */
         public get weight(): number {
             return this._weight;
-        }              
+        }
 
         /**
          * Gets the current value of the runtime animation
@@ -196,7 +213,7 @@
             // Events
             for (var index = 0; index < this._events.length; index++) {
                 this._events[index].isDone = false;
-            }                  
+            }
         }
 
         /**
@@ -205,7 +222,7 @@
          */
         public isStopped(): boolean {
             return this._stopped;
-        }        
+        }
 
         /**
          * Disposes of the runtime animation
@@ -217,7 +234,7 @@
                 this._animation.runtimeAnimations.splice(index, 1);
             }
         }
-        
+
         /**
          * Interpolates the animation from the current frame
          * @param currentFrame The frame to interpolate the animation to
@@ -269,7 +286,7 @@
                     property = property[targetPropertyPath[index]];
                 }
 
-                path =  targetPropertyPath[targetPropertyPath.length - 1];
+                path = targetPropertyPath[targetPropertyPath.length - 1];
                 destination = property;
             } else {
                 path = targetPropertyPath[0];
@@ -323,7 +340,7 @@
                             this._currentValue = Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
                         }
                     }
-                } else { 
+                } else {
                     this._currentValue = Animation._UniversalLerp(this._originalBlendValue, currentValue, this._blendingFactor);
                 }
 
@@ -349,7 +366,7 @@
          * @returns Loop Mode
          */
         private _getCorrectLoopMode(): number | undefined {
-            if ( this._target && this._target.animationPropertiesOverride) {
+            if (this._target && this._target.animationPropertiesOverride) {
                 return this._target.animationPropertiesOverride.loopMode;
             }
 
@@ -424,7 +441,7 @@
             }
 
             //to and from cannot be the same key
-            if(from === to) {
+            if (from === to) {
                 if (from > keys[0].frame) {
                     from--;
                 } else if (to < keys[keys.length - 1].frame) {
@@ -434,7 +451,7 @@
 
             // Compute ratio
             var range = to - from;
-            var offsetValue;
+            var offsetValue: any;
             // ratio represents the frame delta between from and to
             var ratio = (delay * (this._animation.framePerSecond * speedRatio) / 1000.0) + this._ratioOffset;
             var highLimitValue = 0;
@@ -495,30 +512,30 @@
                         break;
                     // Quaternion
                     case Animation.ANIMATIONTYPE_QUATERNION:
-                        offsetValue = new Quaternion(0, 0, 0, 0);
+                        offsetValue = _staticOffsetValueQuaternion;
                         break;
                     // Vector3
                     case Animation.ANIMATIONTYPE_VECTOR3:
-                        offsetValue = Vector3.Zero();
+                        offsetValue = _staticOffsetValueVector3;
                         break;
                     // Vector2
                     case Animation.ANIMATIONTYPE_VECTOR2:
-                        offsetValue = Vector2.Zero();
+                        offsetValue = _staticOffsetValueVector2;
                         break;
                     // Size
                     case Animation.ANIMATIONTYPE_SIZE:
-                        offsetValue = Size.Zero();
+                        offsetValue = _staticOffsetValueSize;
                         break;
                     // Color3
                     case Animation.ANIMATIONTYPE_COLOR3:
-                        offsetValue = Color3.Black();
+                        offsetValue = _staticOffsetValueColor3;
                 }
             }
 
             // Compute value
             var repeatCount = (ratio / range) >> 0;
             var currentFrame = returnValue ? from + ratio % range : to;
-            
+
             // Need to normalize?
             if (this._host && this._host.syncRoot) {
                 let syncRoot = this._host.syncRoot;
@@ -528,16 +545,16 @@
 
             // Reset events if looping
             let events = this._events;
-            if (range > 0 && this.currentFrame > currentFrame || 
+            if (range > 0 && this.currentFrame > currentFrame ||
                 range < 0 && this.currentFrame < currentFrame) {
-                    // Need to reset animation events
-                    for (var index = 0; index < events.length; index++) {
-                        if (!events[index].onlyOnce) {
-                            // reset event, the animation is looping
-                            events[index].isDone = false;
-                        }
-                    }                    
+                // Need to reset animation events
+                for (var index = 0; index < events.length; index++) {
+                    if (!events[index].onlyOnce) {
+                        // reset event, the animation is looping
+                        events[index].isDone = false;
+                    }
                 }
+            }
 
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
@@ -551,7 +568,7 @@
                 if (
                     (range > 0 && currentFrame >= events[index].frame && events[index].frame >= from) ||
                     (range < 0 && currentFrame <= events[index].frame && events[index].frame <= from)
-                ){
+                ) {
                     var event = events[index];
                     if (!event.isDone) {
                         // If event should be done only once, remove it.
@@ -571,6 +588,6 @@
             return returnValue;
         }
     }
-} 
+}
 
 

+ 12 - 14
src/Culling/babylon.boundingBox.ts

@@ -33,27 +33,24 @@
         public reConstruct(min: Vector3, max: Vector3) {
             this.minimum = min.clone();
             this.maximum = max.clone()
+
             // Bounding vectors
-            this.vectors = new Array<Vector3>();
-            this.vectors.push(this.minimum.clone());
-            this.vectors.push(this.maximum.clone());
+            this.vectors = [
+                this.minimum.clone(),
+                this.maximum.clone(),
+                this.minimum.clone(),
+                this.minimum.clone(),
+                this.minimum.clone(),
+                this.maximum.clone(),
+                this.maximum.clone(),
+                this.maximum.clone()
+            ];
 
-            this.vectors.push(this.minimum.clone());
             this.vectors[2].x = this.maximum.x;
-
-            this.vectors.push(this.minimum.clone());
             this.vectors[3].y = this.maximum.y;
-
-            this.vectors.push(this.minimum.clone());
             this.vectors[4].z = this.maximum.z;
-
-            this.vectors.push(this.maximum.clone());
             this.vectors[5].z = this.minimum.z;
-
-            this.vectors.push(this.maximum.clone());
             this.vectors[6].x = this.minimum.x;
-
-            this.vectors.push(this.maximum.clone());
             this.vectors[7].y = this.minimum.y;
 
             // OBB
@@ -65,6 +62,7 @@
             for (var index = 0; index < this.vectors.length; index++) {
                 this.vectorsWorld[index] = Vector3.Zero();
             }
+
             this.minimumWorld = Vector3.Zero();
             this.maximumWorld = Vector3.Zero();
             this.centerWorld = Vector3.Zero();

+ 14 - 10
src/Culling/babylon.boundingSphere.ts

@@ -1,4 +1,8 @@
 module BABYLON {
+    // This matrix is used as a value to reset the bounding box.
+    const _identityMatrix = Matrix.Identity();
+    const _tempRadiusVector = new Vector3(0, 0, 0);
+
     export class BoundingSphere {
         public center: Vector3;
         public radius: number;
@@ -7,14 +11,14 @@
         public minimum: Vector3;
         public maximum: Vector3;
 
-        private _tempRadiusVector = Vector3.Zero();
-
         /**
          * Creates a new bounding sphere
          * @param min defines the minimum vector (in local space)
          * @param max defines the maximum vector (in local space)
          */
         constructor(min: Vector3, max: Vector3) {
+            this.center = Vector3.Zero();
+            this.centerWorld = Vector3.Zero();
             this.reConstruct(min, max);
         }
 
@@ -29,11 +33,11 @@
 
             var distance = Vector3.Distance(min, max);
 
-            this.center = Vector3.Lerp(min, max, 0.5);
+            Vector3.LerpToRef(min, max, 0.5, this.center);
             this.radius = distance * 0.5;
 
-            this.centerWorld = Vector3.Zero();
-            this._update(Matrix.Identity());
+            this.centerWorld.set(0, 0, 0);
+            this._update(_identityMatrix);
         }
 
         /**
@@ -43,10 +47,10 @@
          */
         public scale(factor: number): BoundingSphere {
             let newRadius = this.radius * factor;
-            let newRadiusVector = new Vector3(newRadius, newRadius, newRadius);
+            _tempRadiusVector.set(newRadius, newRadius, newRadius)
 
-            let min = this.center.subtract(newRadiusVector);
-            let max = this.center.add(newRadiusVector);
+            let min = this.center.subtract(_tempRadiusVector);
+            let max = this.center.add(_tempRadiusVector);
 
             this.reConstruct(min, max);
 
@@ -57,8 +61,8 @@
         /** @hidden */
         public _update(world: Matrix): void {
             Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, this._tempRadiusVector);
-            this.radiusWorld = Math.max(Math.abs(this._tempRadiusVector.x), Math.abs(this._tempRadiusVector.y), Math.abs(this._tempRadiusVector.z)) * this.radius;
+            Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, _tempRadiusVector);
+            this.radiusWorld = Math.max(Math.abs(_tempRadiusVector.x), Math.abs(_tempRadiusVector.y), Math.abs(_tempRadiusVector.z)) * this.radius;
         }
 
         public isInFrustum(frustumPlanes: Plane[]): boolean {

+ 5 - 2
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -99,6 +99,7 @@
         public REFLECTIONMAP_CUBIC = false;
         public REFLECTIONMAP_PROJECTION = false;
         public REFLECTIONMAP_SKYBOX = false;
+        public REFLECTIONMAP_SKYBOX_TRANSFORMED = false;
         public REFLECTIONMAP_EXPLICIT = false;
         public REFLECTIONMAP_EQUIRECTANGULAR = false;
         public REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
@@ -687,6 +688,7 @@
                                 break;
                             case Texture.SKYBOX_MODE:
                                 defines.REFLECTIONMAP_SKYBOX = true;
+                                defines.REFLECTIONMAP_SKYBOX_TRANSFORMED = !reflectionTexture.getReflectionTextureMatrix().isIdentity();
                                 break;
                             case Texture.SPHERICAL_MODE:
                                 defines.REFLECTIONMAP_SPHERICAL = true;
@@ -703,8 +705,8 @@
                             case Texture.CUBIC_MODE:
                             case Texture.INVCUBIC_MODE:
                             default:
-                                    defines.REFLECTIONMAP_CUBIC = true;
-                                    break;                        }
+                                defines.REFLECTIONMAP_CUBIC = true;
+                                break;                        }
 
                         if (this.reflectionFresnel) {
                             defines.REFLECTIONFRESNEL = true;
@@ -730,6 +732,7 @@
                         defines.REFLECTIONMAP_CUBIC = false;
                         defines.REFLECTIONMAP_PROJECTION = false;
                         defines.REFLECTIONMAP_SKYBOX = false;
+                        defines.REFLECTIONMAP_SKYBOX_TRANSFORMED = false;
                         defines.REFLECTIONMAP_EXPLICIT = false;
                         defines.REFLECTIONMAP_EQUIRECTANGULAR = false;
                         defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;

+ 5 - 0
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -76,6 +76,7 @@
         public USE_LOCAL_REFLECTIONMAP_CUBIC = false;
         public REFLECTIONMAP_PROJECTION = false;
         public REFLECTIONMAP_SKYBOX = false;
+        public REFLECTIONMAP_SKYBOX_TRANSFORMED = false;
         public REFLECTIONMAP_EXPLICIT = false;
         public REFLECTIONMAP_EQUIRECTANGULAR = false;
         public REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
@@ -1134,6 +1135,9 @@
                                 }
                             }
                         }
+                        else {
+                            defines.REFLECTIONMAP_SKYBOX_TRANSFORMED = !reflectionTexture.getReflectionTextureMatrix().isIdentity();
+                        }
                     } else {
                         defines.REFLECTION = false;
                         defines.REFLECTIONMAP_3D = false;
@@ -1143,6 +1147,7 @@
                         defines.USE_LOCAL_REFLECTIONMAP_CUBIC = false;
                         defines.REFLECTIONMAP_PROJECTION = false;
                         defines.REFLECTIONMAP_SKYBOX = false;
+                        defines.REFLECTIONMAP_SKYBOX_TRANSFORMED = false;
                         defines.REFLECTIONMAP_EXPLICIT = false;
                         defines.REFLECTIONMAP_EQUIRECTANGULAR = false;
                         defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;

+ 2 - 0
src/Materials/babylon.standardMaterial.ts

@@ -60,6 +60,7 @@ module BABYLON {
         public USE_LOCAL_REFLECTIONMAP_CUBIC = false;
         public REFLECTIONMAP_PROJECTION = false;
         public REFLECTIONMAP_SKYBOX = false;
+        public REFLECTIONMAP_SKYBOX_TRANSFORMED = false;
         public REFLECTIONMAP_EXPLICIT = false;
         public REFLECTIONMAP_EQUIRECTANGULAR = false;
         public REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
@@ -631,6 +632,7 @@ module BABYLON {
                                     break;
                                 case Texture.SKYBOX_MODE:
                                     defines.setReflectionMode("REFLECTIONMAP_SKYBOX");
+                                    defines.REFLECTIONMAP_SKYBOX_TRANSFORMED = !this._reflectionTexture.getReflectionTextureMatrix().isIdentity();
                                     break;
                                 case Texture.SPHERICAL_MODE:
                                     defines.setReflectionMode("REFLECTIONMAP_SPHERICAL");

+ 8 - 9
src/Mesh/babylon.mesh.ts

@@ -1718,7 +1718,7 @@
         /**
          * Modifies the mesh geometry according to the passed transformation matrix.  
          * This method returns nothing but it really modifies the mesh even if it's originally not set as updatable. 
-         * The mesh normals are modified accordingly the same transformation.  
+         * The mesh normals are modified using the same transformation.  
          * tuto : http://doc.babylonjs.com/resources/baking_transformations  
          * Note that, under the hood, this method sets a new VertexBuffer each call.  
          * Returns the Mesh.  
@@ -1744,15 +1744,14 @@
             this.setVerticesData(VertexBuffer.PositionKind, temp, (<VertexBuffer>this.getVertexBuffer(VertexBuffer.PositionKind)).isUpdatable());
 
             // Normals
-            if (!this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-                return this;
-            }
-            data = <FloatArray>this.getVerticesData(VertexBuffer.NormalKind);
-            temp = [];
-            for (index = 0; index < data.length; index += 3) {
-                Vector3.TransformNormal(Vector3.FromArray(data, index), transform).normalize().toArray(temp, index);
+            if (this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                data = <FloatArray>this.getVerticesData(VertexBuffer.NormalKind);
+                temp = [];
+                for (index = 0; index < data.length; index += 3) {
+                    Vector3.TransformNormal(Vector3.FromArray(data, index), transform).normalize().toArray(temp, index);
+                }
+                this.setVerticesData(VertexBuffer.NormalKind, temp, (<VertexBuffer>this.getVertexBuffer(VertexBuffer.NormalKind)).isUpdatable());
             }
-            this.setVerticesData(VertexBuffer.NormalKind, temp, (<VertexBuffer>this.getVertexBuffer(VertexBuffer.NormalKind)).isUpdatable());
 
             // flip faces?
             if (transform.m[0] * transform.m[5] * transform.m[10] < 0) { this.flipFaces(); }

+ 2 - 2
src/Mesh/babylon.transformNode.ts

@@ -229,8 +229,8 @@ module BABYLON {
             if (!this._cache.position.equals(this.position))
                 return false;
 
-            if (this.rotationQuaternion) {
-                if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
+            if (this._rotationQuaternion) {
+                if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion))
                     return false;
             }
 

+ 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;
+        }          
+    }
+}

+ 14 - 0
src/Particles/babylon.IParticleSystem.ts

@@ -362,5 +362,19 @@ module BABYLON {
          * @returns the current particle system
          */
         removeLimitVelocityGradient(gradient: number): IParticleSystem;        
+        /**
+         * Adds a new drag gradient
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the drag to affect to the specified gradient         
+         * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
+         * @returns the current particle system
+         */
+        addDragGradient(gradient: number, factor: number, factor2?: number): IParticleSystem;
+        /**
+         * Remove a specific drag gradient
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        removeDragGradient(gradient: number): IParticleSystem;               
     }  
 }

+ 25 - 1
src/Particles/babylon.baseParticleSystem.ts

@@ -240,10 +240,20 @@ module BABYLON {
         protected _angularSpeedGradients: Nullable<Array<FactorGradient>> = null;
         protected _velocityGradients: Nullable<Array<FactorGradient>> = null;
         protected _limitVelocityGradients: Nullable<Array<FactorGradient>> = null;
+        protected _dragGradients: Nullable<Array<FactorGradient>> = null;
+
+        /**
+         * Gets the current list of drag gradients.
+         * You must use addDragGradient and removeDragGradient to udpate this list
+         * @returns the list of drag gradients
+         */
+        public getDragGradients(): Nullable<Array<FactorGradient>> {
+            return this._dragGradients;
+        }   
 
         /** Gets or sets a value indicating the damping to apply if the limit velocity factor is reached */
         public limitVelocityDamping = 0.4;
-
+        
         /**
          * Gets the current list of limit velocity gradients.
          * You must use addLimitVelocityGradient and removeLimitVelocityGradient to udpate this list
@@ -533,6 +543,20 @@ module BABYLON {
         }
 
         /**
+         * Creates a Cylinder Emitter for the particle system (emits from the cylinder to the particle position)
+         * @param radius The radius of the emission cylinder
+         * @param height The height of the emission cylinder
+         * @param radiusRange The range of emission [0-1] 0 Surface only, 1 Entire Radius
+         * @param directionRandomizer How much to randomize the particle direction [0-1]
+         * @returns the emitter
+         */
+        public createCylinderEmitter(radius = 1, height = 1, radiusRange = 1, directionRandomizer = 0): CylinderParticleEmitter {
+            var particleEmitter = new CylinderParticleEmitter(radius, height, radiusRange, directionRandomizer);
+            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

+ 36 - 0
src/Particles/babylon.gpuParticleSystem.ts

@@ -234,6 +234,7 @@
         private _sizeGradientsTexture: RawTexture;             
         private _velocityGradientsTexture: RawTexture;    
         private _limitVelocityGradientsTexture: RawTexture;    
+        private _dragGradientsTexture: RawTexture;  
 
         private _addFactorGradient(factorGradients: FactorGradient[], gradient: number, factor: number) {
             let valueGradient = new FactorGradient();
@@ -395,6 +396,41 @@
         }
 
         /**
+         * Adds a new drag gradient
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the drag value to affect to the specified gradient    
+         * @returns the current particle system     
+         */
+        public addDragGradient(gradient: number, factor: number): GPUParticleSystem {
+            if (!this._dragGradients) {
+                this._dragGradients = [];
+            }
+
+            this._addFactorGradient(this._dragGradients, gradient, factor);
+
+            if (this._dragGradientsTexture) {
+                this._dragGradientsTexture.dispose();
+                (<any>this._dragGradientsTexture) = null;
+            }
+
+            this._releaseBuffers();   
+
+            return this;
+        }
+
+        /**
+         * Remove a specific drag gradient
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeDragGradient(gradient: number): GPUParticleSystem {
+            this._removeGradient(gradient, this._dragGradients, this._dragGradientsTexture);
+            (<any>this._dragGradientsTexture) = null;
+
+            return this;
+        }        
+
+        /**
          * 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

+ 14 - 2
src/Particles/babylon.particle.ts

@@ -100,7 +100,14 @@
         /** @hidden */
         public _currentLimitVelocity1 = 0;
         /** @hidden */
-        public _currentLimitVelocity2 = 0;            
+        public _currentLimitVelocity2 = 0;       
+        
+        /** @hidden */
+        public _currentDragGradient: Nullable<FactorGradient>;
+        /** @hidden */
+        public _currentDrag1 = 0;
+        /** @hidden */
+        public _currentDrag2 = 0;  
 
         /**
          * Creates a new instance Particle
@@ -182,7 +189,12 @@
                 other._currentLimitVelocityGradient = this._currentLimitVelocityGradient;
                 other._currentLimitVelocity1 = this._currentLimitVelocity1;
                 other._currentLimitVelocity2 = this._currentLimitVelocity2;
-            }                           
+            }     
+            if (this._currentDragGradient) {
+                other._currentDragGradient = this._currentDragGradient;
+                other._currentDrag1 = this._currentDrag1;
+                other._currentDrag2 = this._currentDrag2;
+            }                                   
             if (this.particleSystem.isAnimationSheetEnabled) {
                 other._initialStartSpriteCellID = this._initialStartSpriteCellID;
                 other._initialEndSpriteCellID = this._initialEndSpriteCellID;

+ 57 - 2
src/Particles/babylon.particleSystem.ts

@@ -235,6 +235,21 @@
                             });
                         }   
 
+                        /// Drag
+                        if (this._dragGradients && this._dragGradients.length > 0) {                  
+                            Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
+                                if (currentGradient !== particle._currentDragGradient) {
+                                    particle._currentDrag1 = particle._currentDrag2;
+                                    particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();    
+                                    particle._currentDragGradient = (<FactorGradient>currentGradient);
+                                }                                
+                                
+                                let drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
+
+                                this._scaledDirection.scaleInPlace(drag);
+                            });
+                        }                           
+
                         particle.position.addInPlace(this._scaledDirection);
 
                         // Noise
@@ -260,7 +275,7 @@
 
                         // Gravity
                         this.gravity.scaleToRef(this._scaledUpdateSpeed, this._scaledGravity);
-                        particle.direction.addInPlace(this._scaledGravity);
+                        particle.direction.addInPlace(this._scaledGravity);                       
 
                         // Size
                         if (this._sizeGradients && this._sizeGradients.length > 0) {                  
@@ -454,7 +469,35 @@
             this._removeFactorGradient(this._limitVelocityGradients, gradient);
 
             return this;
-        }            
+        }       
+        
+        /**
+         * Adds a new drag gradient
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param factor defines the drag value to affect to the specified gradient         
+         * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
+         * @returns the current particle system
+         */
+        public addDragGradient(gradient: number, factor: number, factor2?: number): IParticleSystem {
+            if (!this._dragGradients) {
+                this._dragGradients = [];
+            }
+
+            this._addFactorGradient(this._dragGradients, gradient, factor, factor2);
+
+            return this;
+        }
+
+        /**
+         * Remove a specific drag gradient
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeDragGradient(gradient: number): IParticleSystem {
+            this._removeFactorGradient(this._dragGradients, gradient);
+
+            return this;
+        }           
 
         /**
          * Adds a new color gradient
@@ -924,6 +967,18 @@
                     }
                 }                   
 
+                // Drag
+                if (this._dragGradients && this._dragGradients.length > 0) {
+                    particle._currentDragGradient = this._dragGradients[0];
+                    particle._currentDrag1 = particle._currentDragGradient.getFactor();
+
+                    if (this._dragGradients.length > 1) {
+                        particle._currentDrag2 = this._dragGradients[1].getFactor();
+                    } else {
+                        particle._currentDrag2 = particle._currentDrag1;
+                    }
+                }          
+
                 // Color
                 if (!this._colorGradients || this._colorGradients.length === 0) {
                     var step = Scalar.RandomRange(0, 1.0);

+ 4 - 0
src/Shaders/ShadersInclude/defaultVertexDeclaration.fx

@@ -37,6 +37,10 @@ uniform vec3 vBumpInfos;
 uniform mat4 bumpMatrix;
 #endif
 
+#ifdef REFLECTION
+uniform mat4 reflectionMatrix;
+#endif
+
 #ifdef POINTSIZE
 	uniform float pointSize;
 #endif

+ 5 - 1
src/Shaders/background.vertex.fx

@@ -57,7 +57,11 @@ varying vec3 vDirectionW;
 void main(void) {
 
 #ifdef REFLECTIONMAP_SKYBOX
-    vPositionUVW = position;
+    #ifdef REFLECTIONMAP_SKYBOX_TRANSFORMED
+        vPositionUVW = (reflectionMatrix * vec4(position, 1.0)).xyz;
+    #else
+        vPositionUVW = position;
+    #endif
 #endif 
 
 #include<instancesVertex>

+ 5 - 1
src/Shaders/default.vertex.fx

@@ -109,7 +109,11 @@ void main(void) {
 #include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
 
 #ifdef REFLECTIONMAP_SKYBOX
-	vPositionUVW = positionUpdated;
+	#ifdef REFLECTIONMAP_SKYBOX_TRANSFORMED
+		vPositionUVW = (reflectionMatrix * vec4(position, 1.0)).xyz;
+	#else
+		vPositionUVW = position;
+	#endif
 #endif 
 
 #define CUSTOM_VERTEX_UPDATE_POSITION

+ 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);
 

+ 14 - 10
src/Shaders/pbr.vertex.fx

@@ -98,9 +98,9 @@ varying vec3 vDirectionW;
 #include<logDepthDeclaration>
 
 void main(void) {
-	vec3 positionUpdated = position;
+    vec3 positionUpdated = position;
 #ifdef NORMAL
-	vec3 normalUpdated = normal;
+    vec3 normalUpdated = normal;
 #endif
 #ifdef TANGENT
     vec4 tangentUpdated = tangent;
@@ -109,7 +109,11 @@ void main(void) {
 #include<morphTargetsVertex>[0..maxSimultaneousMorphTargets]
 
 #ifdef REFLECTIONMAP_SKYBOX
-    vPositionUVW = positionUpdated;
+    #ifdef REFLECTIONMAP_SKYBOX_TRANSFORMED
+        vPositionUVW = (reflectionMatrix * vec4(positionUpdated, 1.0)).xyz;
+    #else
+        vPositionUVW = positionUpdated;
+    #endif
 #endif 
 
 #include<instancesVertex>
@@ -121,13 +125,13 @@ void main(void) {
     vPositionW = vec3(worldPos);
 
 #ifdef NORMAL
-	mat3 normalWorld = mat3(finalWorld);
+    mat3 normalWorld = mat3(finalWorld);
 
-	#ifdef NONUNIFORMSCALING
-		normalWorld = transposeMat3(inverseMat3(normalWorld));
-	#endif
+    #ifdef NONUNIFORMSCALING
+        normalWorld = transposeMat3(inverseMat3(normalWorld));
+    #endif
 
-	vNormalW = normalize(normalWorld * normalUpdated);
+    vNormalW = normalize(normalWorld * normalUpdated);
 
     #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
         vec3 reflectionVector = vec3(reflectionMatrix * vec4(vNormalW, 0)).xyz;
@@ -151,11 +155,11 @@ void main(void) {
 #endif
 
 #ifdef MAINUV1
-	vMainUV1 = uv;
+    vMainUV1 = uv;
 #endif 
 
 #ifdef MAINUV2
-	vMainUV2 = uv2;
+    vMainUV2 = uv2;
 #endif 
 
 #if defined(ALBEDO) && ALBEDODIRECTUV == 0 

+ 13 - 10
src/babylon.scene.ts

@@ -207,18 +207,18 @@
          * Gets or sets the active clipplane 2
          */
         public clipPlane2: Nullable<Plane>;
-        
+
 
         /**
          * Gets or sets the active clipplane 3
          */
         public clipPlane3: Nullable<Plane>;
-        
+
 
         /**
          * Gets or sets the active clipplane 4
          */
-        public clipPlane4: Nullable<Plane>;        
+        public clipPlane4: Nullable<Plane>;
 
         /**
          * Gets or sets a boolean indicating if animations are enabled
@@ -2742,12 +2742,13 @@
             totalWeight: number,
             animations: RuntimeAnimation[],
             originalValue: Quaternion
-        }): Quaternion {
+        }, refQuaternion: Quaternion): Quaternion {
             let originalAnimation = holder.animations[0];
             let originalValue = holder.originalValue;
 
             if (holder.animations.length === 1) {
-                return Quaternion.Slerp(originalValue, originalAnimation.currentValue, Math.min(1.0, holder.totalWeight));
+                Quaternion.SlerpToRef(originalValue, originalAnimation.currentValue, Math.min(1.0, holder.totalWeight), refQuaternion);
+                return refQuaternion;
             }
 
             let normalizer = 1.0;
@@ -2764,7 +2765,8 @@
                 weights.push(scale);
             } else {
                 if (holder.animations.length === 2) { // Slerp as soon as we can
-                    return Quaternion.Slerp(holder.animations[0].currentValue, holder.animations[1].currentValue, holder.animations[1].weight / holder.totalWeight);
+                    Quaternion.SlerpToRef(holder.animations[0].currentValue, holder.animations[1].currentValue, holder.animations[1].weight / holder.totalWeight, refQuaternion);
+                    return refQuaternion;
                 }
                 quaternions = [];
                 weights = [];
@@ -2783,7 +2785,8 @@
             let cumulativeQuaternion: Nullable<Quaternion> = null;
             for (var index = 0; index < quaternions.length;) {
                 if (!cumulativeQuaternion) {
-                    cumulativeQuaternion = Quaternion.Slerp(quaternions[index], quaternions[index + 1], weights[index + 1] / (weights[index] + weights[index + 1]));
+                    Quaternion.SlerpToRef(quaternions[index], quaternions[index + 1], weights[index + 1] / (weights[index] + weights[index + 1]), refQuaternion);
+                    cumulativeQuaternion = refQuaternion;
                     cumulativeAmount = weights[index] + weights[index + 1];
                     index += 2;
                     continue;
@@ -2810,13 +2813,13 @@
 
                     let matrixDecomposeMode = Animation.AllowMatrixDecomposeForInterpolation && originalValue.m; // ie. data is matrix
 
-                    let finalValue: any;
+                    let finalValue: any = target[path];
                     if (matrixDecomposeMode) {
                         finalValue = this._processLateAnimationBindingsForMatrices(holder);
                     } else {
                         let quaternionMode = originalValue.w !== undefined;
                         if (quaternionMode) {
-                            finalValue = this._processLateAnimationBindingsForQuaternions(holder);
+                            finalValue = this._processLateAnimationBindingsForQuaternions(holder, finalValue || Quaternion.Identity());
                         } else {
 
                             let startIndex = 0;
@@ -4186,7 +4189,7 @@
                 mesh.computeWorldMatrix();
 
                 // Intersections
-                if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
+                if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers2(ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger)) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 

二进制
tests/validation/ReferenceImages/ssao2.png


+ 2 - 1
what's new.md

@@ -121,6 +121,7 @@
 - Added `alphaCutOff` support for StandardMaterial ([deltakosh](https://github.com/deltakosh))
 - New `serialize` and `Parse` functions for SSAO2 Rendering Pipeline ([julien-moreau](https://github.com/julien-moreau))
 - Added `furOcclusion` property to FurMaterial to control the occlusion strength ([julien-moreau](https://github.com/julien-moreau))
+- Optimize ephimeral object creation to help GC ([menduz](https://github.com/menduz))
 
 ## Bug fixes
 
@@ -154,4 +155,4 @@
 - `Bone.setScale` does not support scaleChildren property anymore. You can use `Bone.scale` to achieve the same effect ([deltakosh](https://github.com/deltakosh))
 - Vector3 &amp; Vector4:
   - `MinimizeInPlace` has been renamed to `minimizeInPlace`
-  - `MaximizeInPlace` has been renamed to `maximizeInPlace`
+  - `MaximizeInPlace` has been renamed to `maximizeInPlace`