Browse Source

Merge pull request #6140 from BabylonJS/perf

Perf
David Catuhe 6 years ago
parent
commit
8bce00f5f6

+ 6 - 6
loaders/src/glTF/2.0/glTFLoader.ts

@@ -1168,17 +1168,17 @@ export class GLTFLoader implements IGLTFLoader {
             let animationType: number;
             switch (channel.target.path) {
                 case AnimationChannelTargetPath.TRANSLATION: {
-                    targetPath = "position";
+                    targetPath = "_position";
                     animationType = Animation.ANIMATIONTYPE_VECTOR3;
                     break;
                 }
                 case AnimationChannelTargetPath.ROTATION: {
-                    targetPath = "rotationQuaternion";
+                    targetPath = "_rotationQuaternion";
                     animationType = Animation.ANIMATIONTYPE_QUATERNION;
                     break;
                 }
                 case AnimationChannelTargetPath.SCALE: {
-                    targetPath = "scaling";
+                    targetPath = "_scaling";
                     animationType = Animation.ANIMATIONTYPE_VECTOR3;
                     break;
                 }
@@ -1195,7 +1195,7 @@ export class GLTFLoader implements IGLTFLoader {
             let outputBufferOffset = 0;
             let getNextOutputValue: () => Vector3 | Quaternion | Array<number>;
             switch (targetPath) {
-                case "position": {
+                case "_position": {
                     getNextOutputValue = () => {
                         const value = Vector3.FromArray(data.output, outputBufferOffset);
                         outputBufferOffset += 3;
@@ -1203,7 +1203,7 @@ export class GLTFLoader implements IGLTFLoader {
                     };
                     break;
                 }
-                case "rotationQuaternion": {
+                case "_rotationQuaternion": {
                     getNextOutputValue = () => {
                         const value = Quaternion.FromArray(data.output, outputBufferOffset);
                         outputBufferOffset += 4;
@@ -1211,7 +1211,7 @@ export class GLTFLoader implements IGLTFLoader {
                     };
                     break;
                 }
-                case "scaling": {
+                case "_scaling": {
                     getNextOutputValue = () => {
                         const value = Vector3.FromArray(data.output, outputBufferOffset);
                         outputBufferOffset += 3;

+ 24 - 14
src/Animations/animatable.ts

@@ -170,7 +170,15 @@ export class Animatable {
         for (var index = 0; index < animations.length; index++) {
             var animation = animations[index];
 
-            this._runtimeAnimations.push(new RuntimeAnimation(target, animation, this._scene, this));
+            let newRuntimeAnimation = new RuntimeAnimation(target, animation, this._scene, this);
+            newRuntimeAnimation._onLoop = () => {
+                this.onAnimationLoopObservable.notifyObservers(this);
+                if (this.onAnimationLoop) {
+                    this.onAnimationLoop();
+                }
+            }
+
+            this._runtimeAnimations.push(newRuntimeAnimation);
         }
     }
 
@@ -387,13 +395,7 @@ export class Animatable {
         for (index = 0; index < runtimeAnimations.length; index++) {
             var animation = runtimeAnimations[index];
             var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame,
-                this.toFrame, this.loopAnimation, this._speedRatio, this._weight,
-                () => {
-                    this.onAnimationLoopObservable.notifyObservers(this);
-                    if (this.onAnimationLoop) {
-                        this.onAnimationLoop();
-                    }
-                }
+                this.toFrame, this.loopAnimation, this._speedRatio, this._weight
             );
             running = running || isRunning;
         }
@@ -561,7 +563,12 @@ declare module "../scene" {
 }
 
 Scene.prototype._animate = function(): void {
-    if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
+    if (!this.animationsEnabled) {
+        return;
+    }
+
+    const animatables = this._activeAnimatables;
+    if (animatables.length === 0) {
         return;
     }
 
@@ -573,11 +580,14 @@ Scene.prototype._animate = function(): void {
         }
         this._animationTimeLast = now;
     }
+
     var deltaTime = this.useConstantAnimationDeltaTime ? 16.0 : (now - this._animationTimeLast) * this.animationTimeScale;
     this._animationTime += deltaTime;
+    const animationTime = this._animationTime;
     this._animationTimeLast = now;
-    for (var index = 0; index < this._activeAnimatables.length; index++) {
-        this._activeAnimatables[index]._animate(this._animationTime);
+
+    for (let index = 0; index < animatables.length; index++) {
+        animatables[index]._animate(animationTime);
     }
 
     // Late animation bindings
@@ -781,9 +791,9 @@ Scene.prototype._processLateAnimationBindingsForMatrices = function(holder: {
         currentQuaternion.scaleAndAddToRef(scale, finalQuaternion);
         currentPosition.scaleAndAddToRef(scale, finalPosition);
     }
-
-    Matrix.ComposeToRef(finalScaling, finalQuaternion, finalPosition, originalAnimation._workValue);
-    return originalAnimation._workValue;
+    let workValue = originalAnimation._animationState.workValue;
+    Matrix.ComposeToRef(finalScaling, finalQuaternion, finalPosition, workValue);
+    return workValue;
 };
 
 Scene.prototype._processLateAnimationBindingsForQuaternions = function(holder: {

+ 31 - 19
src/Animations/animation.ts

@@ -16,6 +16,18 @@ declare type Animatable = import("./animatable").Animatable;
 declare type RuntimeAnimation = import("./runtimeAnimation").RuntimeAnimation;
 
 /**
+ * @hidden
+ */
+export class _IAnimationState {
+    key: number;
+    repeatCount: number;
+    workValue?: any;
+    loopMode?: number;
+    offsetValue?: any;
+    highLimitValue?: any;
+}
+
+/**
  * Class used to store any kind of animation
  */
 export class Animation {
@@ -571,9 +583,9 @@ export class Animation {
     /**
      * @hidden Internal use only
      */
-    public _interpolate(currentFrame: number, repeatCount: number, workValue?: any, loopMode?: number, offsetValue?: any, highLimitValue?: any): any {
-        if (loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
-            return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
+    public _interpolate(currentFrame: number, state: _IAnimationState): any {
+        if (state.loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && state.repeatCount > 0) {
+            return state.highLimitValue.clone ? state.highLimitValue.clone() : state.highLimitValue;
         }
 
         const keys = this._keys;
@@ -581,8 +593,7 @@ export class Animation {
             return this._getKeyValue(keys[0].value);
         }
 
-        // Try to get a hash to find the right key
-        var startKeyIndex = Math.max(0, Math.min(keys.length - 1, Math.floor(keys.length * (currentFrame - keys[0].frame) / (keys[keys.length - 1].frame - keys[0].frame)) - 1));
+        var startKeyIndex = state.key;
 
         if (keys[startKeyIndex].frame >= currentFrame) {
             while (startKeyIndex - 1 >= 0 && keys[startKeyIndex].frame >= currentFrame) {
@@ -594,6 +605,7 @@ export class Animation {
             var endKey = keys[key + 1];
 
             if (endKey.frame >= currentFrame) {
+                state.key = key;
                 var startKey = keys[key];
                 var startValue = this._getKeyValue(startKey.value);
                 if (startKey.interpolation === AnimationKeyInterpolation.STEP) {
@@ -618,71 +630,71 @@ export class Animation {
                     // Float
                     case Animation.ANIMATIONTYPE_FLOAT:
                         var floatValue = useTangent ? this.floatInterpolateFunctionWithTangents(startValue, startKey.outTangent * frameDelta, endValue, endKey.inTangent * frameDelta, gradient) : this.floatInterpolateFunction(startValue, endValue, gradient);
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return floatValue;
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return offsetValue * repeatCount + floatValue;
+                                return state.offsetValue * state.repeatCount + floatValue;
                         }
                         break;
                     // Quaternion
                     case Animation.ANIMATIONTYPE_QUATERNION:
                         var quatValue = useTangent ? this.quaternionInterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.quaternionInterpolateFunction(startValue, endValue, gradient);
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return quatValue;
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return quatValue.addInPlace(offsetValue.scale(repeatCount));
+                                return quatValue.addInPlace(state.offsetValue.scale(state.repeatCount));
                         }
 
                         return quatValue;
                     // Vector3
                     case Animation.ANIMATIONTYPE_VECTOR3:
                         var vec3Value = useTangent ? this.vector3InterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.vector3InterpolateFunction(startValue, endValue, gradient);
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return vec3Value;
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return vec3Value.add(offsetValue.scale(repeatCount));
+                                return vec3Value.add(state.offsetValue.scale(state.repeatCount));
                         }
                     // Vector2
                     case Animation.ANIMATIONTYPE_VECTOR2:
                         var vec2Value = useTangent ? this.vector2InterpolateFunctionWithTangents(startValue, startKey.outTangent.scale(frameDelta), endValue, endKey.inTangent.scale(frameDelta), gradient) : this.vector2InterpolateFunction(startValue, endValue, gradient);
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return vec2Value;
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return vec2Value.add(offsetValue.scale(repeatCount));
+                                return vec2Value.add(state.offsetValue.scale(state.repeatCount));
                         }
                     // Size
                     case Animation.ANIMATIONTYPE_SIZE:
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return this.sizeInterpolateFunction(startValue, endValue, gradient);
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return this.sizeInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                return this.sizeInterpolateFunction(startValue, endValue, gradient).add(state.offsetValue.scale(state.repeatCount));
                         }
                     // Color3
                     case Animation.ANIMATIONTYPE_COLOR3:
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 return this.color3InterpolateFunction(startValue, endValue, gradient);
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                return this.color3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                return this.color3InterpolateFunction(startValue, endValue, gradient).add(state.offsetValue.scale(state.repeatCount));
                         }
                     // Matrix
                     case Animation.ANIMATIONTYPE_MATRIX:
-                        switch (loopMode) {
+                        switch (state.loopMode) {
                             case Animation.ANIMATIONLOOPMODE_CYCLE:
                             case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 if (Animation.AllowMatricesInterpolation) {
-                                    return this.matrixInterpolateFunction(startValue, endValue, gradient, workValue);
+                                    return this.matrixInterpolateFunction(startValue, endValue, gradient, state.workValue);
                                 }
                             case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                 return startValue;

+ 42 - 41
src/Animations/runtimeAnimation.ts

@@ -1,6 +1,6 @@
 import { DeepImmutable } from "../types";
 import { Quaternion, Vector3, Vector2, Size, Color3, Matrix } from "../Maths/math";
-import { Animation } from "./animation";
+import { Animation, _IAnimationState } from "./animation";
 import { AnimationEvent } from "./animationEvent";
 
 declare type Animatable = import("./animatable").Animatable;
@@ -92,7 +92,7 @@ export class RuntimeAnimation {
     private _currentValue: any;
 
     /** @hidden */
-    public _workValue: any;
+    public _animationState: _IAnimationState;
 
     /**
      * The active target of the runtime animation
@@ -127,7 +127,6 @@ export class RuntimeAnimation {
     private _previousRatio: number = 0;
 
     private _enableBlending: boolean;
-    private _correctLoopMode: number | undefined;
 
     private _keys: IAnimationKey[];
     private _minFrame: number;
@@ -170,6 +169,9 @@ export class RuntimeAnimation {
         return this._currentActiveTarget;
     }
 
+    /** @hidden */
+    public _onLoop: () => void;
+
     /**
      * Create a new RuntimeAnimation object
      * @param target defines the target of the animation
@@ -186,6 +188,17 @@ export class RuntimeAnimation {
 
         animation._runtimeAnimations.push(this);
 
+        // State
+        this._animationState = {
+            key: 0,
+            repeatCount: 0,
+            loopMode: this._getCorrectLoopMode()
+        }
+
+        if (this._animation.dataType === Animation.ANIMATIONTYPE_MATRIX) {
+            this._animationState.workValue = Matrix.Zero();
+        }
+
         // Normalization
         if (this._host && this._host.syncRoot) {
             this._normalizationProcessor = this._defaultNormalizationProcessor;
@@ -229,7 +242,6 @@ export class RuntimeAnimation {
             });
         }
 
-        this._correctLoopMode = this._getCorrectLoopMode();
         this._enableBlending = target && target.animationPropertiesOverride ? target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
 
         if (this._enableBlending) {
@@ -240,8 +252,8 @@ export class RuntimeAnimation {
     }
 
     private _normalizationProcessor = (returnValue: boolean, range: number, ratio: number, from: number, to: number) => {
-        return (returnValue && range !== 0) ? from + ratio % range : to;
-    }
+        return (returnValue && range !== 0) ? from + ratio % range : to;;
+    };
     private _defaultNormalizationProcessor = (returnValue: boolean, range: number, ratio: number, from: number, to: number) => {
         const syncRoot = this._host.syncRoot;
         const hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
@@ -326,26 +338,9 @@ export class RuntimeAnimation {
     }
 
     /**
-     * Interpolates the animation from the current frame
-     * @param currentFrame The frame to interpolate the animation to
-     * @param repeatCount The number of times that the animation should loop
-     * @param loopMode The type of looping mode to use
-     * @param offsetValue Animation offset value
-     * @param highLimitValue The high limit value
-     * @returns The interpolated value
-     */
-    private _interpolate(currentFrame: number, repeatCount: number, loopMode?: number, offsetValue?: any, highLimitValue?: any): any {
-        this._currentFrame = currentFrame;
-
-        if (this._animation.dataType === Animation.ANIMATIONTYPE_MATRIX && !this._workValue) {
-            this._workValue = Matrix.Zero();
-        }
-
-        return this._animation._interpolate(currentFrame, repeatCount, this._workValue, loopMode, offsetValue, highLimitValue);
-    }
-
-    /**
      * Apply the interpolated value to the target
+     * @param currentValue defines the value computed by the animation
+     * @param weight defines the weight to apply to this value (Defaults to 1.0)
      */
     public setValue: (currentValue: any, weight: number) => void;
 
@@ -464,7 +459,7 @@ export class RuntimeAnimation {
             frame = keys[keys.length - 1].frame;
         }
 
-        var currentValue = this._interpolate(frame, 0, this._correctLoopMode);
+        var currentValue = this._animation._interpolate(frame, this._animationState);
 
         this.setValue(currentValue, -1);
     }
@@ -489,8 +484,9 @@ export class RuntimeAnimation {
      * @param onLoop optional callback called when animation loops
      * @returns a boolean indicating if the animation is running
      */
-    public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, weight = -1.0, onLoop?: () => void): boolean {
-        let targetPropertyPath = this._animation.targetPropertyPath;
+    public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, weight = -1.0): boolean {
+        let animation = this._animation;
+        let targetPropertyPath = animation.targetPropertyPath;
         if (!targetPropertyPath || targetPropertyPath.length < 1) {
             this._stopped = true;
             return false;
@@ -510,7 +506,7 @@ export class RuntimeAnimation {
         let offsetValue: any;
 
         // Compute ratio which represents the frame delta between from and to
-        const ratio = (delay * (this._animation.framePerSecond * speedRatio) / 1000.0) + this._ratioOffset;
+        const ratio = (delay * (animation.framePerSecond * speedRatio) / 1000.0) + this._ratioOffset;
         let highLimitValue = 0;
 
         this._previousDelay = delay;
@@ -518,16 +514,20 @@ export class RuntimeAnimation {
 
         if (!loop && (to > from && ratio >= range)) { // If we are out of range and not looping get back to caller
             returnValue = false;
-            highLimitValue = this._animation._getKeyValue(this._maxValue);
+            highLimitValue = animation._getKeyValue(this._maxValue);
         } else if (!loop && (from > to && ratio <= range)) {
             returnValue = false;
-            highLimitValue = this._animation._getKeyValue(this._minValue);
-        } else if (this._correctLoopMode !== Animation.ANIMATIONLOOPMODE_CYCLE) {
+            highLimitValue = animation._getKeyValue(this._minValue);
+        } else if (this._animationState.loopMode !== Animation.ANIMATIONLOOPMODE_CYCLE) {
             var keyOffset = to.toString() + from.toString();
             if (!this._offsetsCache[keyOffset]) {
-                var fromValue = this._interpolate(from, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
-                var toValue = this._interpolate(to, 0, Animation.ANIMATIONLOOPMODE_CYCLE);
-                switch (this._animation.dataType) {
+                this._animationState.repeatCount = 0;
+                this._animationState.loopMode = Animation.ANIMATIONLOOPMODE_CYCLE;
+                var fromValue = animation._interpolate(from, this._animationState);
+                var toValue = animation._interpolate(to, this._animationState);
+
+                this._animationState.loopMode = this._getCorrectLoopMode();
+                switch (animation.dataType) {
                     // Float
                     case Animation.ANIMATIONTYPE_FLOAT:
                         this._offsetsCache[keyOffset] = toValue - fromValue;
@@ -560,7 +560,7 @@ export class RuntimeAnimation {
         }
 
         if (offsetValue === undefined) {
-            switch (this._animation.dataType) {
+            switch (animation.dataType) {
                 // Float
                 case Animation.ANIMATIONTYPE_FLOAT:
                     offsetValue = 0;
@@ -594,9 +594,7 @@ export class RuntimeAnimation {
         const events = this._events;
         if (range > 0 && this.currentFrame > currentFrame ||
             range < 0 && this.currentFrame < currentFrame) {
-            if (onLoop) {
-                onLoop();
-            }
+            this._onLoop();
 
             // Need to reset animation events
             if (events.length) {
@@ -608,9 +606,12 @@ export class RuntimeAnimation {
                 }
             }
         }
+        this._currentFrame = currentFrame;
+        this._animationState.repeatCount = range === 0 ? 0 : (ratio / range) >> 0;
+        this._animationState.highLimitValue = highLimitValue;
+        this._animationState.offsetValue = offsetValue;
 
-        const repeatCount = range === 0 ? 0 : (ratio / range) >> 0;
-        const currentValue = this._interpolate(currentFrame, repeatCount, this._correctLoopMode, offsetValue, highLimitValue);
+        const currentValue = animation._interpolate(currentFrame, this._animationState);
 
         // Set value
         this.setValue(currentValue, weight);

+ 98 - 94
src/Materials/PBR/pbrBaseMaterial.ts

@@ -1526,44 +1526,45 @@ export abstract class PBRBaseMaterial extends PushMaterial {
      */
     public buildUniformLayout(): void {
         // Order is important !
-        this._uniformBuffer.addUniform("vAlbedoInfos", 2);
-        this._uniformBuffer.addUniform("vAmbientInfos", 4);
-        this._uniformBuffer.addUniform("vOpacityInfos", 2);
-        this._uniformBuffer.addUniform("vEmissiveInfos", 2);
-        this._uniformBuffer.addUniform("vLightmapInfos", 2);
-        this._uniformBuffer.addUniform("vReflectivityInfos", 3);
-        this._uniformBuffer.addUniform("vMicroSurfaceSamplerInfos", 2);
-        this._uniformBuffer.addUniform("vReflectionInfos", 2);
-        this._uniformBuffer.addUniform("vReflectionPosition", 3);
-        this._uniformBuffer.addUniform("vReflectionSize", 3);
-        this._uniformBuffer.addUniform("vBumpInfos", 3);
-        this._uniformBuffer.addUniform("albedoMatrix", 16);
-        this._uniformBuffer.addUniform("ambientMatrix", 16);
-        this._uniformBuffer.addUniform("opacityMatrix", 16);
-        this._uniformBuffer.addUniform("emissiveMatrix", 16);
-        this._uniformBuffer.addUniform("lightmapMatrix", 16);
-        this._uniformBuffer.addUniform("reflectivityMatrix", 16);
-        this._uniformBuffer.addUniform("microSurfaceSamplerMatrix", 16);
-        this._uniformBuffer.addUniform("bumpMatrix", 16);
-        this._uniformBuffer.addUniform("vTangentSpaceParams", 2);
-        this._uniformBuffer.addUniform("reflectionMatrix", 16);
-
-        this._uniformBuffer.addUniform("vReflectionColor", 3);
-        this._uniformBuffer.addUniform("vAlbedoColor", 4);
-        this._uniformBuffer.addUniform("vLightingIntensity", 4);
-
-        this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3);
-        this._uniformBuffer.addUniform("pointSize", 1);
-        this._uniformBuffer.addUniform("vReflectivityColor", 4);
-        this._uniformBuffer.addUniform("vEmissiveColor", 3);
-        this._uniformBuffer.addUniform("visibility", 1);
-
-        PBRClearCoatConfiguration.PrepareUniformBuffer(this._uniformBuffer);
-        PBRAnisotropicConfiguration.PrepareUniformBuffer(this._uniformBuffer);
-        PBRSheenConfiguration.PrepareUniformBuffer(this._uniformBuffer);
-        PBRSubSurfaceConfiguration.PrepareUniformBuffer(this._uniformBuffer);
-
-        this._uniformBuffer.create();
+        let ubo = this._uniformBuffer;
+        ubo.addUniform("vAlbedoInfos", 2);
+        ubo.addUniform("vAmbientInfos", 4);
+        ubo.addUniform("vOpacityInfos", 2);
+        ubo.addUniform("vEmissiveInfos", 2);
+        ubo.addUniform("vLightmapInfos", 2);
+        ubo.addUniform("vReflectivityInfos", 3);
+        ubo.addUniform("vMicroSurfaceSamplerInfos", 2);
+        ubo.addUniform("vReflectionInfos", 2);
+        ubo.addUniform("vReflectionPosition", 3);
+        ubo.addUniform("vReflectionSize", 3);
+        ubo.addUniform("vBumpInfos", 3);
+        ubo.addUniform("albedoMatrix", 16);
+        ubo.addUniform("ambientMatrix", 16);
+        ubo.addUniform("opacityMatrix", 16);
+        ubo.addUniform("emissiveMatrix", 16);
+        ubo.addUniform("lightmapMatrix", 16);
+        ubo.addUniform("reflectivityMatrix", 16);
+        ubo.addUniform("microSurfaceSamplerMatrix", 16);
+        ubo.addUniform("bumpMatrix", 16);
+        ubo.addUniform("vTangentSpaceParams", 2);
+        ubo.addUniform("reflectionMatrix", 16);
+
+        ubo.addUniform("vReflectionColor", 3);
+        ubo.addUniform("vAlbedoColor", 4);
+        ubo.addUniform("vLightingIntensity", 4);
+
+        ubo.addUniform("vReflectionMicrosurfaceInfos", 3);
+        ubo.addUniform("pointSize", 1);
+        ubo.addUniform("vReflectivityColor", 4);
+        ubo.addUniform("vEmissiveColor", 3);
+        ubo.addUniform("visibility", 1);
+
+        PBRClearCoatConfiguration.PrepareUniformBuffer(ubo);
+        PBRAnisotropicConfiguration.PrepareUniformBuffer(ubo);
+        PBRSheenConfiguration.PrepareUniformBuffer(ubo);
+        PBRSubSurfaceConfiguration.PrepareUniformBuffer(ubo);
+
+        ubo.create();
     }
 
     /**
@@ -1612,7 +1613,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        this.bindOnlyWorldMatrix(world);
+        if (!defines.INSTANCES) {
+            this.bindOnlyWorldMatrix(world);
+        }
 
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
@@ -1626,41 +1629,42 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
 
         let reflectionTexture: Nullable<BaseTexture> = null;
+        let ubo = this._uniformBuffer;
         if (mustRebind) {
             var engine = scene.getEngine();
-            this._uniformBuffer.bindToEffect(effect, "Material");
+            ubo.bindToEffect(effect, "Material");
 
             this.bindViewProjection(effect);
             reflectionTexture = this._getReflectionTexture();
 
-            if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
+            if (!ubo.useUbo || !this.isFrozen || !ubo.isSync) {
 
                 // Texture uniforms
                 if (scene.texturesEnabled) {
                     if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vAlbedoInfos", this._albedoTexture.coordinatesIndex, this._albedoTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._albedoTexture, this._uniformBuffer, "albedo");
+                        ubo.updateFloat2("vAlbedoInfos", this._albedoTexture.coordinatesIndex, this._albedoTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._albedoTexture, ubo, "albedo");
                     }
 
                     if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) {
-                        this._uniformBuffer.updateFloat4("vAmbientInfos", this._ambientTexture.coordinatesIndex, this._ambientTexture.level, this._ambientTextureStrength, this._ambientTextureImpactOnAnalyticalLights);
-                        MaterialHelper.BindTextureMatrix(this._ambientTexture, this._uniformBuffer, "ambient");
+                        ubo.updateFloat4("vAmbientInfos", this._ambientTexture.coordinatesIndex, this._ambientTexture.level, this._ambientTextureStrength, this._ambientTextureImpactOnAnalyticalLights);
+                        MaterialHelper.BindTextureMatrix(this._ambientTexture, ubo, "ambient");
                     }
 
                     if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._opacityTexture, this._uniformBuffer, "opacity");
+                        ubo.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._opacityTexture, ubo, "opacity");
                     }
 
                     if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) {
-                        this._uniformBuffer.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix());
-                        this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, 0);
+                        ubo.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix());
+                        ubo.updateFloat2("vReflectionInfos", reflectionTexture.level, 0);
 
                         if ((<any>reflectionTexture).boundingBoxSize) {
                             let cubeTexture = <CubeTexture>reflectionTexture;
 
-                            this._uniformBuffer.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
-                            this._uniformBuffer.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
+                            ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
+                            ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
                         }
 
                         var polynomials = reflectionTexture.sphericalPolynomial;
@@ -1680,71 +1684,71 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                             this._activeEffect.setFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
                         }
 
-                        this._uniformBuffer.updateFloat3("vReflectionMicrosurfaceInfos",
+                        ubo.updateFloat3("vReflectionMicrosurfaceInfos",
                             reflectionTexture.getSize().width,
                             reflectionTexture.lodGenerationScale,
                             reflectionTexture.lodGenerationOffset);
                     }
 
                     if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._emissiveTexture, this._uniformBuffer, "emissive");
+                        ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._emissiveTexture, ubo, "emissive");
                     }
 
                     if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._lightmapTexture, this._uniformBuffer, "lightmap");
+                        ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._lightmapTexture, ubo, "lightmap");
                     }
 
                     if (MaterialFlags.SpecularTextureEnabled) {
                         if (this._metallicTexture) {
-                            this._uniformBuffer.updateFloat3("vReflectivityInfos", this._metallicTexture.coordinatesIndex, this._metallicTexture.level, this._ambientTextureStrength);
-                            MaterialHelper.BindTextureMatrix(this._metallicTexture, this._uniformBuffer, "reflectivity");
+                            ubo.updateFloat3("vReflectivityInfos", this._metallicTexture.coordinatesIndex, this._metallicTexture.level, this._ambientTextureStrength);
+                            MaterialHelper.BindTextureMatrix(this._metallicTexture, ubo, "reflectivity");
                         }
                         else if (this._reflectivityTexture) {
-                            this._uniformBuffer.updateFloat3("vReflectivityInfos", this._reflectivityTexture.coordinatesIndex, this._reflectivityTexture.level, 1.0);
-                            MaterialHelper.BindTextureMatrix(this._reflectivityTexture, this._uniformBuffer, "reflectivity");
+                            ubo.updateFloat3("vReflectivityInfos", this._reflectivityTexture.coordinatesIndex, this._reflectivityTexture.level, 1.0);
+                            MaterialHelper.BindTextureMatrix(this._reflectivityTexture, ubo, "reflectivity");
                         }
 
                         if (this._microSurfaceTexture) {
-                            this._uniformBuffer.updateFloat2("vMicroSurfaceSamplerInfos", this._microSurfaceTexture.coordinatesIndex, this._microSurfaceTexture.level);
-                            MaterialHelper.BindTextureMatrix(this._microSurfaceTexture, this._uniformBuffer, "microSurfaceSampler");
+                            ubo.updateFloat2("vMicroSurfaceSamplerInfos", this._microSurfaceTexture.coordinatesIndex, this._microSurfaceTexture.level);
+                            MaterialHelper.BindTextureMatrix(this._microSurfaceTexture, ubo, "microSurfaceSampler");
                         }
                     }
 
                     if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) {
-                        this._uniformBuffer.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, this._bumpTexture.level, this._parallaxScaleBias);
-                        MaterialHelper.BindTextureMatrix(this._bumpTexture, this._uniformBuffer, "bump");
+                        ubo.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, this._bumpTexture.level, this._parallaxScaleBias);
+                        MaterialHelper.BindTextureMatrix(this._bumpTexture, ubo, "bump");
 
                         if (scene._mirroredCameraPosition) {
-                            this._uniformBuffer.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0);
+                            ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0);
                         } else {
-                            this._uniformBuffer.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? -1.0 : 1.0, this._invertNormalMapY ? -1.0 : 1.0);
+                            ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? -1.0 : 1.0, this._invertNormalMapY ? -1.0 : 1.0);
                         }
                     }
                 }
 
                 // Point size
                 if (this.pointsCloud) {
-                    this._uniformBuffer.updateFloat("pointSize", this.pointSize);
+                    ubo.updateFloat("pointSize", this.pointSize);
                 }
 
                 // Colors
                 if (defines.METALLICWORKFLOW) {
                     Tmp.Color3[0].r = (this._metallic === undefined || this._metallic === null) ? 1 : this._metallic;
                     Tmp.Color3[0].g = (this._roughness === undefined || this._roughness === null) ? 1 : this._roughness;
-                    this._uniformBuffer.updateColor4("vReflectivityColor", Tmp.Color3[0], 0);
+                    ubo.updateColor4("vReflectivityColor", Tmp.Color3[0], 0);
                 }
                 else {
-                    this._uniformBuffer.updateColor4("vReflectivityColor", this._reflectivityColor, this._microSurface);
+                    ubo.updateColor4("vReflectivityColor", this._reflectivityColor, this._microSurface);
                 }
 
-                this._uniformBuffer.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly);
-                this._uniformBuffer.updateColor3("vReflectionColor", this._reflectionColor);
-                this._uniformBuffer.updateColor4("vAlbedoColor", this._albedoColor, this.alpha);
+                ubo.updateColor3("vEmissiveColor", MaterialFlags.EmissiveTextureEnabled ? this._emissiveColor : Color3.BlackReadOnly);
+                ubo.updateColor3("vReflectionColor", this._reflectionColor);
+                ubo.updateColor4("vAlbedoColor", this._albedoColor, this.alpha);
 
                 // Visibility
-                this._uniformBuffer.updateFloat("visibility", mesh.visibility);
+                ubo.updateFloat("visibility", mesh.visibility);
 
                 // Misc
                 this._lightingInfos.x = this._directIntensity;
@@ -1752,68 +1756,68 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                 this._lightingInfos.z = this._environmentIntensity;
                 this._lightingInfos.w = this._specularIntensity;
 
-                this._uniformBuffer.updateVector4("vLightingIntensity", this._lightingInfos);
+                ubo.updateVector4("vLightingIntensity", this._lightingInfos);
             }
 
             // Textures
             if (scene.texturesEnabled) {
                 if (this._albedoTexture && MaterialFlags.DiffuseTextureEnabled) {
-                    this._uniformBuffer.setTexture("albedoSampler", this._albedoTexture);
+                    ubo.setTexture("albedoSampler", this._albedoTexture);
                 }
 
                 if (this._ambientTexture && MaterialFlags.AmbientTextureEnabled) {
-                    this._uniformBuffer.setTexture("ambientSampler", this._ambientTexture);
+                    ubo.setTexture("ambientSampler", this._ambientTexture);
                 }
 
                 if (this._opacityTexture && MaterialFlags.OpacityTextureEnabled) {
-                    this._uniformBuffer.setTexture("opacitySampler", this._opacityTexture);
+                    ubo.setTexture("opacitySampler", this._opacityTexture);
                 }
 
                 if (reflectionTexture && MaterialFlags.ReflectionTextureEnabled) {
                     if (defines.LODBASEDMICROSFURACE) {
-                        this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture);
+                        ubo.setTexture("reflectionSampler", reflectionTexture);
                     }
                     else {
-                        this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture);
-                        this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture);
-                        this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture);
+                        ubo.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture);
+                        ubo.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture);
+                        ubo.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture);
                     }
                 }
 
                 if (defines.ENVIRONMENTBRDF) {
-                    this._uniformBuffer.setTexture("environmentBrdfSampler", this._environmentBRDFTexture);
+                    ubo.setTexture("environmentBrdfSampler", this._environmentBRDFTexture);
                 }
 
                 if (this._emissiveTexture && MaterialFlags.EmissiveTextureEnabled) {
-                    this._uniformBuffer.setTexture("emissiveSampler", this._emissiveTexture);
+                    ubo.setTexture("emissiveSampler", this._emissiveTexture);
                 }
 
                 if (this._lightmapTexture && MaterialFlags.LightmapTextureEnabled) {
-                    this._uniformBuffer.setTexture("lightmapSampler", this._lightmapTexture);
+                    ubo.setTexture("lightmapSampler", this._lightmapTexture);
                 }
 
                 if (MaterialFlags.SpecularTextureEnabled) {
                     if (this._metallicTexture) {
-                        this._uniformBuffer.setTexture("reflectivitySampler", this._metallicTexture);
+                        ubo.setTexture("reflectivitySampler", this._metallicTexture);
                     }
                     else if (this._reflectivityTexture) {
-                        this._uniformBuffer.setTexture("reflectivitySampler", this._reflectivityTexture);
+                        ubo.setTexture("reflectivitySampler", this._reflectivityTexture);
                     }
 
                     if (this._microSurfaceTexture) {
-                        this._uniformBuffer.setTexture("microSurfaceSampler", this._microSurfaceTexture);
+                        ubo.setTexture("microSurfaceSampler", this._microSurfaceTexture);
                     }
                 }
 
                 if (this._bumpTexture && engine.getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled && !this._disableBumpMap) {
-                    this._uniformBuffer.setTexture("bumpSampler", this._bumpTexture);
+                    ubo.setTexture("bumpSampler", this._bumpTexture);
                 }
             }
 
-            this.subSurface.bindForSubMesh(this._uniformBuffer, scene, engine, this.isFrozen, defines.LODBASEDMICROSFURACE);
-            this.clearCoat.bindForSubMesh(this._uniformBuffer, scene, engine, this._disableBumpMap, this.isFrozen, this._invertNormalMapX, this._invertNormalMapY);
-            this.anisotropy.bindForSubMesh(this._uniformBuffer, scene, this.isFrozen);
-            this.sheen.bindForSubMesh(this._uniformBuffer, scene, this.isFrozen);
+            this.subSurface.bindForSubMesh(ubo, scene, engine, this.isFrozen, defines.LODBASEDMICROSFURACE);
+            this.clearCoat.bindForSubMesh(ubo, scene, engine, this._disableBumpMap, this.isFrozen, this._invertNormalMapX, this._invertNormalMapY);
+            this.anisotropy.bindForSubMesh(ubo, scene, this.isFrozen);
+            this.sheen.bindForSubMesh(ubo, scene, this.isFrozen);
 
             // Clip plane
             MaterialHelper.BindClipPlane(this._activeEffect, scene);
@@ -1859,7 +1863,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             MaterialHelper.BindLogDepth(defines, this._activeEffect, scene);
         }
 
-        this._uniformBuffer.update();
+        ubo.update();
 
         this._afterBind(mesh, this._activeEffect);
     }
@@ -2094,4 +2098,4 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
         super.dispose(forceDisposeEffect, forceDisposeTextures);
     }
-}
+}

+ 1 - 3
src/Materials/Textures/Procedurals/proceduralTexture.ts

@@ -201,9 +201,7 @@ export class ProceduralTexture extends Texture {
         if (this._effect === undefined) {
             return;
         }
-
-        var engine = this._engine;
-        engine._releaseEffect(this._effect);
+        this._effect.dispose();
     }
 
     protected _getDefines(): string {

+ 7 - 1
src/Materials/effect.ts

@@ -4,6 +4,7 @@ import { Matrix, Vector3, Vector2, Color3, Color4, Vector4 } from "../Maths/math
 import { Constants } from "../Engines/constants";
 import { DomManagement } from "../Misc/domManagement";
 import { Logger } from "../Misc/logger";
+import { IDisposable } from 'scene';
 
 declare type Engine = import("../Engines/engine").Engine;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
@@ -181,7 +182,7 @@ export class EffectCreationOptions {
 /**
  * Effect containing vertex and fragment shader that can be executed on an object.
  */
-export class Effect {
+export class Effect implements IDisposable {
     /**
      * Gets or sets the relative url used to load shaders if using the engine in non-minified mode
      */
@@ -1501,6 +1502,11 @@ export class Effect {
         return this;
     }
 
+    /** Release all associated resources */
+    public dispose() {
+        this._engine._releaseEffect(this);
+    }
+
     /**
      * This function will add a new shader to the shader store
      * @param name the name of the shader

+ 3 - 4
src/Materials/material.ts

@@ -1104,7 +1104,7 @@ export class Material implements IAnimatable {
         // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
         if (forceDisposeEffect && this._effect) {
             if (!this._storeEffectOnSubMeshes) {
-                scene.getEngine()._releaseEffect(this._effect);
+                this._effect.dispose();
             }
 
             this._effect = null;
@@ -1127,12 +1127,11 @@ export class Material implements IAnimatable {
     private releaseVertexArrayObject(mesh: AbstractMesh, forceDisposeEffect?: boolean) {
         if ((<Mesh>mesh).geometry) {
             var geometry = <Geometry>((<Mesh>mesh).geometry);
-            const scene = this.getScene();
             if (this._storeEffectOnSubMeshes) {
                 for (var subMesh of mesh.subMeshes) {
                     geometry._releaseVertexArrayObject(subMesh._materialEffect);
                     if (forceDisposeEffect && subMesh._materialEffect) {
-                        scene.getEngine()._releaseEffect(subMesh._materialEffect);
+                        subMesh._materialEffect.dispose();
                     }
                 }
             } else {
@@ -1171,4 +1170,4 @@ export class Material implements IAnimatable {
         var materialType = Tools.Instantiate(parsedMaterial.customType);
         return materialType.Parse(parsedMaterial, scene, rootUrl);
     }
-}
+}

+ 84 - 81
src/Materials/standardMaterial.ts

@@ -1190,45 +1190,46 @@ export class StandardMaterial extends PushMaterial {
      */
     public buildUniformLayout(): void {
         // Order is important !
-        this._uniformBuffer.addUniform("diffuseLeftColor", 4);
-        this._uniformBuffer.addUniform("diffuseRightColor", 4);
-        this._uniformBuffer.addUniform("opacityParts", 4);
-        this._uniformBuffer.addUniform("reflectionLeftColor", 4);
-        this._uniformBuffer.addUniform("reflectionRightColor", 4);
-        this._uniformBuffer.addUniform("refractionLeftColor", 4);
-        this._uniformBuffer.addUniform("refractionRightColor", 4);
-        this._uniformBuffer.addUniform("emissiveLeftColor", 4);
-        this._uniformBuffer.addUniform("emissiveRightColor", 4);
-
-        this._uniformBuffer.addUniform("vDiffuseInfos", 2);
-        this._uniformBuffer.addUniform("vAmbientInfos", 2);
-        this._uniformBuffer.addUniform("vOpacityInfos", 2);
-        this._uniformBuffer.addUniform("vReflectionInfos", 2);
-        this._uniformBuffer.addUniform("vReflectionPosition", 3);
-        this._uniformBuffer.addUniform("vReflectionSize", 3);
-        this._uniformBuffer.addUniform("vEmissiveInfos", 2);
-        this._uniformBuffer.addUniform("vLightmapInfos", 2);
-        this._uniformBuffer.addUniform("vSpecularInfos", 2);
-        this._uniformBuffer.addUniform("vBumpInfos", 3);
-
-        this._uniformBuffer.addUniform("diffuseMatrix", 16);
-        this._uniformBuffer.addUniform("ambientMatrix", 16);
-        this._uniformBuffer.addUniform("opacityMatrix", 16);
-        this._uniformBuffer.addUniform("reflectionMatrix", 16);
-        this._uniformBuffer.addUniform("emissiveMatrix", 16);
-        this._uniformBuffer.addUniform("lightmapMatrix", 16);
-        this._uniformBuffer.addUniform("specularMatrix", 16);
-        this._uniformBuffer.addUniform("bumpMatrix", 16);
-        this._uniformBuffer.addUniform("vTangentSpaceParams", 2);
-        this._uniformBuffer.addUniform("pointSize", 1);
-        this._uniformBuffer.addUniform("refractionMatrix", 16);
-        this._uniformBuffer.addUniform("vRefractionInfos", 4);
-        this._uniformBuffer.addUniform("vSpecularColor", 4);
-        this._uniformBuffer.addUniform("vEmissiveColor", 3);
-        this._uniformBuffer.addUniform("visibility", 1);
-        this._uniformBuffer.addUniform("vDiffuseColor", 4);
-
-        this._uniformBuffer.create();
+        let ubo = this._uniformBuffer;
+        ubo.addUniform("diffuseLeftColor", 4);
+        ubo.addUniform("diffuseRightColor", 4);
+        ubo.addUniform("opacityParts", 4);
+        ubo.addUniform("reflectionLeftColor", 4);
+        ubo.addUniform("reflectionRightColor", 4);
+        ubo.addUniform("refractionLeftColor", 4);
+        ubo.addUniform("refractionRightColor", 4);
+        ubo.addUniform("emissiveLeftColor", 4);
+        ubo.addUniform("emissiveRightColor", 4);
+
+        ubo.addUniform("vDiffuseInfos", 2);
+        ubo.addUniform("vAmbientInfos", 2);
+        ubo.addUniform("vOpacityInfos", 2);
+        ubo.addUniform("vReflectionInfos", 2);
+        ubo.addUniform("vReflectionPosition", 3);
+        ubo.addUniform("vReflectionSize", 3);
+        ubo.addUniform("vEmissiveInfos", 2);
+        ubo.addUniform("vLightmapInfos", 2);
+        ubo.addUniform("vSpecularInfos", 2);
+        ubo.addUniform("vBumpInfos", 3);
+
+        ubo.addUniform("diffuseMatrix", 16);
+        ubo.addUniform("ambientMatrix", 16);
+        ubo.addUniform("opacityMatrix", 16);
+        ubo.addUniform("reflectionMatrix", 16);
+        ubo.addUniform("emissiveMatrix", 16);
+        ubo.addUniform("lightmapMatrix", 16);
+        ubo.addUniform("specularMatrix", 16);
+        ubo.addUniform("bumpMatrix", 16);
+        ubo.addUniform("vTangentSpaceParams", 2);
+        ubo.addUniform("pointSize", 1);
+        ubo.addUniform("refractionMatrix", 16);
+        ubo.addUniform("vRefractionInfos", 4);
+        ubo.addUniform("vSpecularColor", 4);
+        ubo.addUniform("vEmissiveColor", 3);
+        ubo.addUniform("visibility", 1);
+        ubo.addUniform("vDiffuseColor", 4);
+
+        ubo.create();
     }
 
     /**
@@ -1276,7 +1277,9 @@ export class StandardMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        this.bindOnlyWorldMatrix(world);
+        if (!defines.INSTANCES) {
+            this.bindOnlyWorldMatrix(world);
+        }
 
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
@@ -1288,45 +1291,45 @@ export class StandardMaterial extends PushMaterial {
 
         // Bones
         MaterialHelper.BindBonesParameters(mesh, effect);
-
+        let ubo = this._uniformBuffer;
         if (mustRebind) {
-            this._uniformBuffer.bindToEffect(effect, "Material");
+            ubo.bindToEffect(effect, "Material");
 
             this.bindViewProjection(effect);
-            if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
+            if (!ubo.useUbo || !this.isFrozen || !ubo.isSync) {
 
                 if (StandardMaterial.FresnelEnabled && defines.FRESNEL) {
                     // Fresnel
                     if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
-                        this._uniformBuffer.updateColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
-                        this._uniformBuffer.updateColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
+                        ubo.updateColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
+                        ubo.updateColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
                     }
 
                     if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
-                        this._uniformBuffer.updateColor4("opacityParts", new Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
+                        ubo.updateColor4("opacityParts", new Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
                     }
 
                     if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                        this._uniformBuffer.updateColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
-                        this._uniformBuffer.updateColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
+                        ubo.updateColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
+                        ubo.updateColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
                     }
 
                     if (this.refractionFresnelParameters && this.refractionFresnelParameters.isEnabled) {
-                        this._uniformBuffer.updateColor4("refractionLeftColor", this.refractionFresnelParameters.leftColor, this.refractionFresnelParameters.power);
-                        this._uniformBuffer.updateColor4("refractionRightColor", this.refractionFresnelParameters.rightColor, this.refractionFresnelParameters.bias);
+                        ubo.updateColor4("refractionLeftColor", this.refractionFresnelParameters.leftColor, this.refractionFresnelParameters.power);
+                        ubo.updateColor4("refractionRightColor", this.refractionFresnelParameters.rightColor, this.refractionFresnelParameters.bias);
                     }
 
                     if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
-                        this._uniformBuffer.updateColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
-                        this._uniformBuffer.updateColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
+                        ubo.updateColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
+                        ubo.updateColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
                     }
                 }
 
                 // Textures
                 if (scene.texturesEnabled) {
                     if (this._diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse");
+                        ubo.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._diffuseTexture, ubo, "diffuse");
 
                         if (this._diffuseTexture.hasAlpha) {
                             effect.setFloat("alphaCutOff", this.alphaCutOff);
@@ -1334,81 +1337,81 @@ export class StandardMaterial extends PushMaterial {
                     }
 
                     if (this._ambientTexture && StandardMaterial.AmbientTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vAmbientInfos", this._ambientTexture.coordinatesIndex, this._ambientTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._ambientTexture, this._uniformBuffer, "ambient");
+                        ubo.updateFloat2("vAmbientInfos", this._ambientTexture.coordinatesIndex, this._ambientTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._ambientTexture, ubo, "ambient");
                     }
 
                     if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._opacityTexture, this._uniformBuffer, "opacity");
+                        ubo.updateFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._opacityTexture, ubo, "opacity");
                     }
 
                     if (this._reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vReflectionInfos", this._reflectionTexture.level, this.roughness);
-                        this._uniformBuffer.updateMatrix("reflectionMatrix", this._reflectionTexture.getReflectionTextureMatrix());
+                        ubo.updateFloat2("vReflectionInfos", this._reflectionTexture.level, this.roughness);
+                        ubo.updateMatrix("reflectionMatrix", this._reflectionTexture.getReflectionTextureMatrix());
 
                         if ((<any>this._reflectionTexture).boundingBoxSize) {
                             let cubeTexture = <CubeTexture>this._reflectionTexture;
 
-                            this._uniformBuffer.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
-                            this._uniformBuffer.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
+                            ubo.updateVector3("vReflectionPosition", cubeTexture.boundingBoxPosition);
+                            ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
                         }
                     }
 
                     if (this._emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._emissiveTexture, this._uniformBuffer, "emissive");
+                        ubo.updateFloat2("vEmissiveInfos", this._emissiveTexture.coordinatesIndex, this._emissiveTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._emissiveTexture, ubo, "emissive");
                     }
 
                     if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._lightmapTexture, this._uniformBuffer, "lightmap");
+                        ubo.updateFloat2("vLightmapInfos", this._lightmapTexture.coordinatesIndex, this._lightmapTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._lightmapTexture, ubo, "lightmap");
                     }
 
                     if (this._specularTexture && StandardMaterial.SpecularTextureEnabled) {
-                        this._uniformBuffer.updateFloat2("vSpecularInfos", this._specularTexture.coordinatesIndex, this._specularTexture.level);
-                        MaterialHelper.BindTextureMatrix(this._specularTexture, this._uniformBuffer, "specular");
+                        ubo.updateFloat2("vSpecularInfos", this._specularTexture.coordinatesIndex, this._specularTexture.level);
+                        MaterialHelper.BindTextureMatrix(this._specularTexture, ubo, "specular");
                     }
 
                     if (this._bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
-                        this._uniformBuffer.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, 1.0 / this._bumpTexture.level, this.parallaxScaleBias);
-                        MaterialHelper.BindTextureMatrix(this._bumpTexture, this._uniformBuffer, "bump");
+                        ubo.updateFloat3("vBumpInfos", this._bumpTexture.coordinatesIndex, 1.0 / this._bumpTexture.level, this.parallaxScaleBias);
+                        MaterialHelper.BindTextureMatrix(this._bumpTexture, ubo, "bump");
 
                         if (scene._mirroredCameraPosition) {
-                            this._uniformBuffer.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0);
+                            ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? 1.0 : -1.0, this._invertNormalMapY ? 1.0 : -1.0);
                         } else {
-                            this._uniformBuffer.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? -1.0 : 1.0, this._invertNormalMapY ? -1.0 : 1.0);
+                            ubo.updateFloat2("vTangentSpaceParams", this._invertNormalMapX ? -1.0 : 1.0, this._invertNormalMapY ? -1.0 : 1.0);
                         }
                     }
 
                     if (this._refractionTexture && StandardMaterial.RefractionTextureEnabled) {
                         var depth = 1.0;
                         if (!this._refractionTexture.isCube) {
-                            this._uniformBuffer.updateMatrix("refractionMatrix", this._refractionTexture.getReflectionTextureMatrix());
+                            ubo.updateMatrix("refractionMatrix", this._refractionTexture.getReflectionTextureMatrix());
 
                             if ((<any>this._refractionTexture).depth) {
                                 depth = (<any>this._refractionTexture).depth;
                             }
                         }
-                        this._uniformBuffer.updateFloat4("vRefractionInfos", this._refractionTexture.level, this.indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
+                        ubo.updateFloat4("vRefractionInfos", this._refractionTexture.level, this.indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
                     }
                 }
 
                 // Point size
                 if (this.pointsCloud) {
-                    this._uniformBuffer.updateFloat("pointSize", this.pointSize);
+                    ubo.updateFloat("pointSize", this.pointSize);
                 }
 
                 if (defines.SPECULARTERM) {
-                    this._uniformBuffer.updateColor4("vSpecularColor", this.specularColor, this.specularPower);
+                    ubo.updateColor4("vSpecularColor", this.specularColor, this.specularPower);
                 }
-                this._uniformBuffer.updateColor3("vEmissiveColor", StandardMaterial.EmissiveTextureEnabled ? this.emissiveColor : Color3.BlackReadOnly);
+                ubo.updateColor3("vEmissiveColor", StandardMaterial.EmissiveTextureEnabled ? this.emissiveColor : Color3.BlackReadOnly);
 
                 // Visibility
-                this._uniformBuffer.updateFloat("visibility", mesh.visibility);
+                ubo.updateFloat("visibility", mesh.visibility);
 
                 // Diffuse
-                this._uniformBuffer.updateColor4("vDiffuseColor", this.diffuseColor, this.alpha);
+                ubo.updateColor4("vDiffuseColor", this.diffuseColor, this.alpha);
             }
 
             // Textures
@@ -1497,7 +1500,7 @@ export class StandardMaterial extends PushMaterial {
             }
         }
 
-        this._uniformBuffer.update();
+        ubo.update();
         this._afterBind(mesh, this._activeEffect);
     }
 
@@ -1842,4 +1845,4 @@ _TypeStore.RegisteredTypes["BABYLON.StandardMaterial"] = StandardMaterial;
 
 Scene.DefaultMaterialFactory = (scene: Scene) => {
     return new StandardMaterial("default material", scene);
-};
+};

+ 40 - 27
src/Meshes/mesh.ts

@@ -82,8 +82,9 @@ class _InstanceDataStorage {
     public instancesData: Float32Array;
     public overridenInstanceCount: number;
     public isFrozen: boolean;
-    public _previousBatch: _InstancesBatch;
+    public previousBatch: _InstancesBatch;
     public hardwareInstancedRendering: boolean;
+    public sideOrientation: number;
 }
 
 /**
@@ -1367,8 +1368,8 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
     /** @hidden */
     public _getInstancesRenderList(subMeshId: number): _InstancesBatch {
-        if (this._instanceDataStorage.isFrozen && this._instanceDataStorage._previousBatch) {
-            return this._instanceDataStorage._previousBatch;
+        if (this._instanceDataStorage.isFrozen && this._instanceDataStorage.previousBatch) {
+            return this._instanceDataStorage.previousBatch;
         }
         var scene = this.getScene();
         let batchCache = this._instanceDataStorage.batchCache;
@@ -1387,7 +1388,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             }
         }
         batchCache.hardwareInstancedRendering[subMeshId] = this._instanceDataStorage.hardwareInstancedRendering && (batchCache.visibleInstances[subMeshId] !== null) && (batchCache.visibleInstances[subMeshId] !== undefined);
-        this._instanceDataStorage._previousBatch = batchCache;
+        this._instanceDataStorage.previousBatch = batchCache;
         return batchCache;
     }
 
@@ -1398,19 +1399,21 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             return this;
         }
 
-        var matricesCount = visibleInstances.length + 1;
-        var bufferSize = matricesCount * 16 * 4;
-
         let instanceStorage = this._instanceDataStorage;
         var currentInstancesBufferSize = instanceStorage.instancesBufferSize;
         var instancesBuffer = instanceStorage.instancesBuffer;
+        if (!instanceStorage.isFrozen || !instanceStorage.instancesData) {
+            var matricesCount = visibleInstances.length + 1;
+            var bufferSize = matricesCount * 16 * 4;
 
-        while (instanceStorage.instancesBufferSize < bufferSize) {
-            instanceStorage.instancesBufferSize *= 2;
-        }
 
-        if (!instanceStorage.instancesData || currentInstancesBufferSize != instanceStorage.instancesBufferSize) {
-            instanceStorage.instancesData = new Float32Array(instanceStorage.instancesBufferSize / 4);
+            while (instanceStorage.instancesBufferSize < bufferSize) {
+                instanceStorage.instancesBufferSize *= 2;
+            }
+
+            if (!instanceStorage.instancesData || currentInstancesBufferSize != instanceStorage.instancesBufferSize) {
+                instanceStorage.instancesData = new Float32Array(instanceStorage.instancesBufferSize / 4);
+            }
         }
 
         var offset = 0;
@@ -1445,7 +1448,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world2", 8, 4));
             this.setVerticesBuffer(instancesBuffer.createVertexBuffer("world3", 12, 4));
         } else {
-            instancesBuffer.updateDirectly(instanceStorage.instancesData, 0, instancesCount);
+            instancesBuffer!.updateDirectly(instanceStorage.instancesData, 0, instancesCount);
         }
 
         this._bind(subMesh, effect, fillMode);
@@ -1542,22 +1545,25 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
         var engine = scene.getEngine();
         var hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id];
+        let instanceDataStorage = this._instanceDataStorage;
 
         // Material
-        let material = subMesh.getMaterial();
+        if (!instanceDataStorage.isFrozen ||!this._effectiveMaterial) {
+            let material = subMesh.getMaterial();
 
-        if (!material) {
-            return this;
-        }
+            if (!material) {
+                return this;
+            }
 
-        this._effectiveMaterial = material;
+            this._effectiveMaterial = material;
 
-        if (this._effectiveMaterial._storeEffectOnSubMeshes) {
-            if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
+                if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
+                    return this;
+                }
+            } else if (!this._effectiveMaterial.isReady(this, hardwareInstancedRendering)) {
                 return this;
             }
-        } else if (!this._effectiveMaterial.isReady(this, hardwareInstancedRendering)) {
-            return this;
         }
 
         // Alpha mode
@@ -1582,12 +1588,19 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
         const effectiveMesh = this._effectiveMesh;
 
-        var sideOrientation = this.overrideMaterialSideOrientation;
-        if (sideOrientation == null) {
-            sideOrientation = this._effectiveMaterial.sideOrientation;
-            if (effectiveMesh._getWorldMatrixDeterminant() < 0) {
-                sideOrientation = (sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation);
+        var sideOrientation: Nullable<number>;
+        
+        if (!instanceDataStorage.isFrozen) {
+            sideOrientation = this.overrideMaterialSideOrientation;
+            if (sideOrientation == null) {
+                sideOrientation = this._effectiveMaterial.sideOrientation;
+                if (effectiveMesh._getWorldMatrixDeterminant() < 0) {
+                    sideOrientation = (sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation);
+                }
             }
+            instanceDataStorage.sideOrientation = sideOrientation!;
+        } else {
+            sideOrientation = instanceDataStorage.sideOrientation;
         }
 
         var reverse = this._effectiveMaterial._preBind(effect, sideOrientation);

+ 25 - 20
src/Meshes/transformNode.ts

@@ -301,11 +301,13 @@ export class TransformNode extends Node {
 
     /** @hidden */
     public _isSynchronized(): boolean {
-        if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
+        let cache = this._cache;
+
+        if (this.billboardMode !== cache.billboardMode || this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
             return false;
         }
 
-        if (this._cache.pivotMatrixUpdated) {
+        if (cache.pivotMatrixUpdated) {
             return false;
         }
 
@@ -313,19 +315,19 @@ export class TransformNode extends Node {
             return false;
         }
 
-        if (!this._cache.position.equals(this._position)) {
+        if (!cache.position.equals(this._position)) {
             return false;
         }
 
         if (this._rotationQuaternion) {
-            if (!this._cache.rotationQuaternion.equals(this._rotationQuaternion)) {
+            if (!cache.rotationQuaternion.equals(this._rotationQuaternion)) {
                 return false;
             }
-        } else if (!this._cache.rotation.equals(this._rotation)) {
+        } else if (!cache.rotation.equals(this._rotation)) {
             return false;
         }
 
-        if (!this._cache.scaling.equals(this._scaling)) {
+        if (!cache.scaling.equals(this._scaling)) {
             return false;
         }
 
@@ -336,13 +338,14 @@ export class TransformNode extends Node {
     public _initCache() {
         super._initCache();
 
-        this._cache.localMatrixUpdated = false;
-        this._cache.position = Vector3.Zero();
-        this._cache.scaling = Vector3.Zero();
-        this._cache.rotation = Vector3.Zero();
-        this._cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
-        this._cache.billboardMode = -1;
-        this._cache.infiniteDistance = false;
+        let cache = this._cache;
+        cache.localMatrixUpdated = false;
+        cache.position = Vector3.Zero();
+        cache.scaling = Vector3.Zero();
+        cache.rotation = Vector3.Zero();
+        cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
+        cache.billboardMode = -1;
+        cache.infiniteDistance = false;
     }
 
     /**
@@ -386,6 +389,7 @@ export class TransformNode extends Node {
         } else {
             this._activeCompositionProcessor = this._pivotCompositionProcessor;
         }
+        
         this._cache.pivotMatrixUpdated = true;
         this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
 
@@ -1055,9 +1059,10 @@ export class TransformNode extends Node {
         }
 
         this._updateCache();
-        this._cache.pivotMatrixUpdated = false;
-        this._cache.billboardMode = this.billboardMode;
-        this._cache.infiniteDistance = this.infiniteDistance;
+        let cache = this._cache;
+        cache.pivotMatrixUpdated = false;
+        cache.billboardMode = this.billboardMode;
+        cache.infiniteDistance = this.infiniteDistance;
 
         this._currentRenderId = currentRenderId;
         this._childUpdateId++;
@@ -1065,8 +1070,8 @@ export class TransformNode extends Node {
         let parent = this._getEffectiveParent();
 
         // Scaling
-        let scaling: Vector3 = this._cache.scaling;
-        let translation: Vector3 = this._cache.position;
+        let scaling: Vector3 = cache.scaling;
+        let translation: Vector3 = cache.position;
 
         // Translation
         this._translationProcessor(translation);
@@ -1075,7 +1080,7 @@ export class TransformNode extends Node {
         scaling.copyFromFloats(this._scaling.x * this.scalingDeterminant, this._scaling.y * this.scalingDeterminant, this._scaling.z * this.scalingDeterminant);
 
         // Rotation
-        let rotation: Quaternion = this._cache.rotationQuaternion;
+        let rotation: Quaternion = cache.rotationQuaternion;
         if (this._rotationQuaternion) {
             if (this.reIntegrateRotationIntoRotationQuaternion) {
                 var len = this.rotation.lengthSquared();
@@ -1087,7 +1092,7 @@ export class TransformNode extends Node {
             rotation.copyFrom(this._rotationQuaternion);
         } else {
             Quaternion.RotationYawPitchRollToRef(this._rotation.y, this._rotation.x, this._rotation.z, rotation);
-            this._cache.rotation.copyFrom(this._rotation);
+            cache.rotation.copyFrom(this._rotation);
         }
 
         // Compose