Explorar o código

Merge pull request #4994 from menduz/master

Garbage collector optimizations
David Catuhe %!s(int64=7) %!d(string=hai) anos
pai
achega
917de6a873

+ 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 {

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

+ 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`