Procházet zdrojové kódy

Merge remote-tracking branch 'upstream/master'

sebastien před 7 roky
rodič
revize
15cbab9503

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3489 - 3425
dist/preview release/babylon.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/babylon.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 88 - 54
dist/preview release/babylon.max.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 88 - 54
dist/preview release/babylon.no-module.max.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/babylon.worker.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 88 - 54
dist/preview release/es6.js


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

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

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


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

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

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

@@ -175,7 +175,7 @@
 - Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
 - Dispose existing gazeTrackers when setting a new one ([TrevorDev](https://github.com/TrevorDev))
 - Set missing parentId in Mesh.serialize() for instances ([julien-moreau](https://github.com/julien-moreau))
-- Do not modify pivot point when using bounding box gizmo ([TrevorDev](https://github.com/TrevorDev))
+- Do not modify pivot point when using bounding box gizmo or behaviors ([TrevorDev](https://github.com/TrevorDev))
 - GPUParticleSystem does not get stuck in burst loop when stopped and started ([TrevorDev](https://github.com/TrevorDev))
 - trackPosition:false not working in webVRCamera ([TrevorDev](https://github.com/TrevorDev))
 

+ 11 - 7
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -3,7 +3,7 @@ module BABYLON {
      * A behavior that when attached to a mesh will allow the mesh to be dragged around the screen based on pointer events
      */
     export class PointerDragBehavior implements Behavior<Mesh> {
-        private _attachedNode: Node; 
+        private _attachedNode: Mesh; 
         private _dragPlane: Mesh;
         private _scene:Scene;
         private _pointerObserver:Nullable<Observer<PointerInfo>>;
@@ -177,11 +177,13 @@ module BABYLON {
 
             this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add(()=>{
                 if(this._moving && this.moveAttached){
+                    BoundingBoxGizmo._RemoveAndStorePivotPoint(this._attachedNode);
                     // Slowly move mesh to avoid jitter
-                    this._targetPosition.subtractToRef((<Mesh>this._attachedNode).absolutePosition, this._tmpVector);
+                    this._targetPosition.subtractToRef((this._attachedNode).absolutePosition, this._tmpVector);
                     this._tmpVector.scaleInPlace(this.dragDeltaRatio);
-                    (<Mesh>this._attachedNode).getAbsolutePosition().addToRef(this._tmpVector, this._tmpVector);
-                    (<Mesh>this._attachedNode).setAbsolutePosition(this._tmpVector);
+                    (this._attachedNode).getAbsolutePosition().addToRef(this._tmpVector, this._tmpVector);
+                    (this._attachedNode).setAbsolutePosition(this._tmpVector);
+                    BoundingBoxGizmo._RestorePivotPoint(this._attachedNode);
                 }
             });
         }
@@ -219,6 +221,7 @@ module BABYLON {
                 return;
             }
             
+            BoundingBoxGizmo._RemoveAndStorePivotPoint(this._attachedNode);
             // Create start ray from the camera to the object
             if(fromRay){
                 this._startDragRay.direction.copyFrom(fromRay.direction)
@@ -237,7 +240,7 @@ module BABYLON {
                 this.currentDraggingPointerID = 1;
                 this.lastDragPosition.copyFrom(pickedPoint);
                 this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint, pointerId: this.currentDraggingPointerID});
-                this._targetPosition.copyFrom((<Mesh>this._attachedNode).absolutePosition)
+                this._targetPosition.copyFrom((this._attachedNode).absolutePosition)
 
                 // Detatch camera controls
                 if(this.detachCameraControls && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
@@ -249,6 +252,7 @@ module BABYLON {
                     }
                 }
             }
+            BoundingBoxGizmo._RestorePivotPoint(this._attachedNode);
         }
 
         private _dragDelta = new BABYLON.Vector3();
@@ -298,7 +302,7 @@ module BABYLON {
                 if(this._useAlternatePickedPointAboveMaxDragAngle){
                     // Invert ray direction along the towards object axis
                     this._tmpVector.copyFrom(ray.direction);
-                    (<Mesh>this._attachedNode).absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    (this._attachedNode).absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
                     this._alternatePickedPoint.normalize();
                     this._alternatePickedPoint.scaleInPlace(-2*Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
                     this._tmpVector.addInPlace(this._alternatePickedPoint);
@@ -307,7 +311,7 @@ module BABYLON {
                     var dot = Vector3.Dot(this._dragPlane.forward, this._tmpVector);
                     this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
                     this._alternatePickedPoint.addInPlace(this._tmpVector);
-                    this._alternatePickedPoint.addInPlace((<Mesh>this._attachedNode).absolutePosition);
+                    this._alternatePickedPoint.addInPlace((this._attachedNode).absolutePosition);
                     return this._alternatePickedPoint
                 }else{
                     return null;

+ 4 - 0
src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts

@@ -83,6 +83,7 @@ module BABYLON {
                         }
                         
                         pickedMesh = this._ownerNode;
+                        BoundingBoxGizmo._RemoveAndStorePivotPoint(pickedMesh);
                         lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
 
                         // Set position and orientation of the controller
@@ -115,6 +116,7 @@ module BABYLON {
                                 attachedElement = null;
                             }
                         }
+                        BoundingBoxGizmo._RestorePivotPoint(pickedMesh);
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId){
@@ -172,6 +174,7 @@ module BABYLON {
             // On every frame move towards target scaling to avoid jitter caused by vr controllers
             this._sceneRenderObserver = ownerNode.getScene().onBeforeRenderObservable.add(()=>{
                 if(this.dragging && this._moving && pickedMesh){
+                    BoundingBoxGizmo._RemoveAndStorePivotPoint(pickedMesh);
                     // Slowly move mesh to avoid jitter
                     pickedMesh.position.addInPlace(this._targetPosition.subtract(pickedMesh.position).scale(this.dragDeltaRatio));
                     
@@ -189,6 +192,7 @@ module BABYLON {
                     pickedMesh.setParent(null);
                     Quaternion.SlerpToRef(pickedMesh.rotationQuaternion!, tmpQuaternion, this.dragDeltaRatio, pickedMesh.rotationQuaternion!);
                     pickedMesh.setParent(oldParent);
+                    BoundingBoxGizmo._RestorePivotPoint(pickedMesh);
                 }
             });
         }

+ 33 - 31
src/Gizmos/babylon.boundingBoxGizmo.ts

@@ -65,34 +65,36 @@ module BABYLON {
 
         // Stores the state of the pivot cache (_oldPivotPoint, _pivotTranslation)
         // store/remove pivot point should only be applied during their outermost calls
-        private _pivotCached = 0;
-        private _oldPivotPoint = new Vector3();
-        private _pivotTranslation = new Vector3();
-        private _removeAndStorePivotPoint(){
-            if(this.attachedMesh && this._pivotCached === 0){
+        private static _PivotCached = 0;
+        private static _OldPivotPoint = new Vector3();
+        private static _PivotTranslation = new Vector3();
+        private static _PivotTmpVector = new Vector3();
+        /** @hidden */
+        public static _RemoveAndStorePivotPoint(mesh:AbstractMesh){
+            if(mesh && BoundingBoxGizmo._PivotCached === 0){
                 // Save old pivot and set pivot to 0,0,0
-                this.attachedMesh.getPivotPointToRef(this._oldPivotPoint);
-                if(this._oldPivotPoint.equalsToFloats(0,0,0)){
-                    return;
+                mesh.getPivotPointToRef(BoundingBoxGizmo._OldPivotPoint);
+                if(!BoundingBoxGizmo._OldPivotPoint.equalsToFloats(0,0,0)){
+                    mesh.setPivotMatrix(Matrix.IdentityReadOnly);
+                    BoundingBoxGizmo._OldPivotPoint.subtractToRef(mesh.getPivotPoint(), BoundingBoxGizmo._PivotTranslation);
+                    BoundingBoxGizmo._PivotTmpVector.copyFromFloats(1,1,1);
+                    BoundingBoxGizmo._PivotTmpVector.subtractInPlace(mesh.scaling);
+                    BoundingBoxGizmo._PivotTmpVector.multiplyInPlace(BoundingBoxGizmo._PivotTranslation);
+                    mesh.position.addInPlace(BoundingBoxGizmo._PivotTmpVector);
                 }
-                this.attachedMesh.setPivotMatrix(Matrix.IdentityReadOnly);
-                this._oldPivotPoint.subtractToRef(this.attachedMesh.getPivotPoint(), this._pivotTranslation);
-                this._tmpVector.copyFromFloats(1,1,1);
-                this._tmpVector.subtractInPlace(this.attachedMesh.scaling);
-                this._tmpVector.multiplyInPlace(this._pivotTranslation);
-                this.attachedMesh.position.addInPlace(this._tmpVector);
             }
-            this._pivotCached++;
+            BoundingBoxGizmo._PivotCached++;
         }
-        private _restorePivotPoint(){
-            if(this.attachedMesh && !this._oldPivotPoint.equalsToFloats(0,0,0) && this._pivotCached === 1){
-                this.attachedMesh.setPivotPoint(this._oldPivotPoint);
-                this._tmpVector.copyFromFloats(1,1,1);
-                this._tmpVector.subtractInPlace(this.attachedMesh.scaling);
-                this._tmpVector.multiplyInPlace(this._pivotTranslation);
-                this.attachedMesh.position.subtractInPlace(this._tmpVector);
+        /** @hidden */
+        public static _RestorePivotPoint(mesh:AbstractMesh){
+            if(mesh && !BoundingBoxGizmo._OldPivotPoint.equalsToFloats(0,0,0) && BoundingBoxGizmo._PivotCached === 1){
+                mesh.setPivotPoint(BoundingBoxGizmo._OldPivotPoint);
+                BoundingBoxGizmo._PivotTmpVector.copyFromFloats(1,1,1);
+                BoundingBoxGizmo._PivotTmpVector.subtractInPlace(mesh.scaling);
+                BoundingBoxGizmo._PivotTmpVector.multiplyInPlace(BoundingBoxGizmo._PivotTranslation);
+                mesh.position.subtractInPlace(BoundingBoxGizmo._PivotTmpVector);
             }
-            this._pivotCached--;
+            this._PivotCached--;
         }
 
         /**
@@ -161,7 +163,7 @@ module BABYLON {
                 _dragBehavior.onDragObservable.add((event) => {
                     this.onRotationSphereDragObservable.notifyObservers({});
                     if (this.attachedMesh) {
-                        this._removeAndStorePivotPoint();
+                        BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
 
                         var worldDragDirection = startingTurnDirection;
 
@@ -201,7 +203,7 @@ module BABYLON {
                         }
                         this.updateBoundingBox();
 
-                        this._restorePivotPoint();
+                        BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
                     }
                 });
 
@@ -236,7 +238,7 @@ module BABYLON {
                         _dragBehavior.onDragObservable.add((event) => {
                             this.onScaleBoxDragObservable.notifyObservers({});
                             if(this.attachedMesh){
-                                this._removeAndStorePivotPoint();
+                                BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
                                 var relativeDragDistance = (event.dragDistance / this._boundingDimensions.length())*this._anchorMesh.scaling.length();
                                 var deltaScale = new Vector3(relativeDragDistance,relativeDragDistance,relativeDragDistance);
                                 deltaScale.scaleInPlace(this._scaleDragSpeed);
@@ -263,7 +265,7 @@ module BABYLON {
                                 }
                                 this._anchorMesh.removeChild(this.attachedMesh);
 
-                                this._restorePivotPoint();
+                                BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
                             }
                         })
 
@@ -315,10 +317,10 @@ module BABYLON {
             if (value) {
                 // Reset anchor mesh to match attached mesh's scale
                 // This is needed to avoid invalid box/sphere position on first drag
-                this._removeAndStorePivotPoint();
+                BoundingBoxGizmo._RemoveAndStorePivotPoint(value);
                 this._anchorMesh.addChild(value);
                 this._anchorMesh.removeChild(value);
-                this._restorePivotPoint();
+                BoundingBoxGizmo._RestorePivotPoint(value);
                 this.updateBoundingBox();
             }
         }
@@ -344,7 +346,7 @@ module BABYLON {
          */
         public updateBoundingBox(){
             if(this.attachedMesh){
-                this._removeAndStorePivotPoint();
+                BoundingBoxGizmo._RemoveAndStorePivotPoint(this.attachedMesh);
                 this._update();
                 // Rotate based on axis
                 if (!this.attachedMesh.rotationQuaternion) {
@@ -439,7 +441,7 @@ module BABYLON {
             }
             if (this.attachedMesh) {
                 this._existingMeshScale.copyFrom(this.attachedMesh.scaling);   
-                this._restorePivotPoint();
+                BoundingBoxGizmo._RestorePivotPoint(this.attachedMesh);
             }
         }
 

+ 69 - 1
src/Particles/babylon.IParticleSystem.ts

@@ -396,6 +396,74 @@ module BABYLON {
          * You must use addEmitRateGradient and removeEmitRateGradient to udpate this list
          * @returns the list of emit rate gradients
          */
-        getEmitRateGradients(): Nullable<Array<FactorGradient>>;                        
+        getEmitRateGradients(): Nullable<Array<FactorGradient>>;                    
+        
+
+        /**
+         * Creates a Point Emitter for the particle system (emits directly from the emitter position)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @returns the emitter
+         */
+        createPointEmitter(direction1: Vector3, direction2: Vector3): PointParticleEmitter;
+
+        /**
+         * Creates a Hemisphere Emitter for the particle system (emits along the hemisphere radius)
+         * @param radius The radius of the hemisphere to emit from
+         * @param radiusRange The range of the hemisphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
+         * @returns the emitter
+         */
+        createHemisphericEmitter(radius: number, radiusRange: number): HemisphericParticleEmitter;
+
+        /**
+         * Creates a Sphere Emitter for the particle system (emits along the sphere radius)
+         * @param radius The radius of the sphere to emit from
+         * @param radiusRange The range of the sphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
+         * @returns the emitter
+         */
+        createSphereEmitter(radius: number, radiusRange: number): SphereParticleEmitter;
+
+        /**
+         * Creates a Directed Sphere Emitter for the particle system (emits between direction1 and direction2)
+         * @param radius The radius of the sphere to emit from
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
+         * @returns the emitter
+         */
+        createDirectedSphereEmitter(radius: number, direction1:Vector3, direction2: Vector3): SphereDirectedParticleEmitter;
+
+        /**
+         * Creates a Cylinder Emitter for the particle system (emits from the cylinder to the particle position)
+         * @param radius The radius of the emission cylinder
+         * @param height The height of the emission cylinder
+         * @param radiusRange The range of emission [0-1] 0 Surface only, 1 Entire Radius
+         * @param directionRandomizer How much to randomize the particle direction [0-1]
+         * @returns the emitter
+         */
+        createCylinderEmitter(radius: number, height: number, radiusRange: number, directionRandomizer: number): CylinderParticleEmitter;
+
+        /**
+         * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
+         * @param radius The radius of the cone to emit from
+         * @param angle The base angle of the cone
+         * @returns the emitter
+         */
+        createConeEmitter(radius: number, angle: number): ConeParticleEmitter;
+
+        /**
+         * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
+         * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @param maxEmitBox  Particles are emitted from the box between minEmitBox and maxEmitBox
+         * @returns the emitter
+         */
+        createBoxEmitter(direction1: Vector3, direction2: Vector3, minEmitBox: Vector3, maxEmitBox: Vector3): BoxParticleEmitter;   
+        
+        /**
+         * Get hosting scene
+         * @returns the scene
+         */
+        getScene(): Scene;
     }  
 }

+ 8 - 0
src/Particles/babylon.baseParticleSystem.ts

@@ -231,6 +231,14 @@ module BABYLON {
 
             this._reset();
         }
+        
+        /**
+         * Get hosting scene
+         * @returns the scene
+         */
+        public getScene(): Scene {
+            return this._scene;
+        }    
 
         /**
          * You can use gravity if you want to give an orientation to your particles.

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

@@ -803,6 +803,10 @@
                 defines = "\n#define CLIPPLANE4";
             }
 
+            if (this.blendMode === ParticleSystem.BLENDMODE_MULTIPLY) {
+                defines = "\n#define BLENDMULTIPLYMODE";
+            }
+
             if (this._isBillboardBased) {
                 defines += "\n#define BILLBOARD";
 

+ 9 - 2
src/Particles/babylon.particleHelper.ts

@@ -13,10 +13,17 @@ module BABYLON {
          * @param emitter defines the emitter to use
          * @param capacity defines the system capacity (default is 500 particles)
          * @param scene defines the hosting scene
+         * @param useGPU defines if a GPUParticleSystem must be created (default is false)
          * @returns the new Particle system
          */
-        public static CreateDefault(emitter: Nullable<AbstractMesh | Vector3>, capacity = 500, scene?: Scene): ParticleSystem {
-            var system = new ParticleSystem("default system", capacity, scene!);
+        public static CreateDefault(emitter: Nullable<AbstractMesh | Vector3>, capacity = 500, scene?: Scene, useGPU = false): IParticleSystem {
+            var system: IParticleSystem;
+            
+            if (useGPU) {
+                system= new GPUParticleSystem("default system", {capacity: capacity}, scene!);
+            } else {
+                system= new ParticleSystem("default system", capacity, scene!);
+            }
         
             system.emitter = emitter;
             system.particleTexture = new Texture("https://www.babylonjs.com/assets/Flare.png", system.getScene());

+ 4 - 10
src/Particles/babylon.particleSystem.ts

@@ -43,16 +43,6 @@
             this._onDisposeObserver = this.onDisposeObservable.add(callback);
         }
 
-
-
-        /**
-         * Get hosting scene
-         * @returns the scene
-         */
-        public getScene(): Scene {
-            return this._scene;
-        }    
-
         private _particles = new Array<Particle>();
         private _epsilon: number;
         private _capacity: number;
@@ -1104,6 +1094,10 @@
                 defines.push("#define ANIMATESHEET");
             }
 
+            if (this.blendMode === ParticleSystem.BLENDMODE_MULTIPLY) {
+                defines.push("#define BLENDMULTIPLYMODE");
+            }
+
             if (this._isBillboardBased) {
                 defines.push("#define BILLBOARD");
 

+ 2 - 2
src/PostProcess/babylon.postProcess.ts

@@ -489,8 +489,8 @@
             this.onActivateObservable.notifyObservers(camera);
 
             // Clear
-            if (scene._allowPostProcessClear && this.autoClear && this.alphaMode === Engine.ALPHA_DISABLE) {
-                this._engine.clear(this.clearColor ? this.clearColor : scene.clearColor, true, true, true);
+            if (this.autoClear && this.alphaMode === Engine.ALPHA_DISABLE) {
+                this._engine.clear(this.clearColor ? this.clearColor : scene.clearColor, scene._allowPostProcessClearColor, true, true);
             }
 
             if (this._reusable) {

+ 1 - 1
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -72,7 +72,7 @@ module BABYLON {
             public originalScene: Scene){
             // Create scene which will be rendered in the foreground and remove it from being referenced by engine to avoid interfering with existing app
             this.utilityLayerScene = new BABYLON.Scene(originalScene.getEngine());
-            this.utilityLayerScene._allowPostProcessClear = false;
+            this.utilityLayerScene._allowPostProcessClearColor = false;
             originalScene.getEngine().scenes.pop();
       
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority

+ 6 - 1
src/Shaders/gpuRenderParticles.fragment.fx

@@ -17,7 +17,12 @@ out vec4 outFragColor;
 
 void main() {
 	#include<clipPlaneFragment> 
-  	outFragColor = texture(textureSampler, vUV) * vColor;
+	vec4 textureColor = texture(textureSampler, vUV);
+  	outFragColor = textureColor * vColor;
+
+	#ifdef BLENDMULTIPLYMODE
+	outFragColor.rgb += vec3(1.0 - textureColor.a);
+	#endif	  
 
 // Apply image processing if relevant. As this applies in linear space, 
 // We first move from gamma to linear.

+ 5 - 0
src/Shaders/particles.fragment.fx

@@ -16,8 +16,13 @@ void main(void) {
 	#include<clipPlaneFragment>
 
 	vec4 baseColor = texture2D(diffuseSampler, vUV);
+	float alpha = baseColor.a;
 	baseColor = (baseColor * textureMask + (vec4(1., 1., 1., 1.) - textureMask)) * vColor;
 
+	#ifdef BLENDMULTIPLYMODE
+	baseColor.rgb += vec3(1.0 - alpha);
+	#endif
+
 // Apply image processing if relevant. As this applies in linear space, 
 // We first move from gamma to linear.
 #ifdef IMAGEPROCESSINGPOSTPROCESS

+ 1 - 1
src/babylon.scene.ts

@@ -4220,7 +4220,7 @@
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         }
         /** @hidden */
-        public _allowPostProcessClear = true;
+        public _allowPostProcessClearColor = true;
         private _renderForCamera(camera: Camera, rigParent?: Camera): void {
             if (camera && camera._skipRendering) {
                 return;