Browse Source

new BlurVarianceShadowMap filter for shadows

David Catuhe 10 years ago
parent
commit
51c82cb039

+ 3 - 3
Babylon/Debug/babylon.debugLayer.js

@@ -197,7 +197,7 @@ var BABYLON;
                 var centerX = projectedPosition.x - textMetrics.width / 2;
                 var centerY = projectedPosition.y;
                 var clientRect = this._drawingCanvas.getBoundingClientRect();
-                if (this._isClickInsideRect(clientRect.left * this._ratio + centerX - 5, clientRect.top * this._ratio + centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
+                if (this._showUI && this._isClickInsideRect(clientRect.left * this._ratio + centerX - 5, clientRect.top * this._ratio + centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
                     onClick();
                 }
                 this._drawingContext.beginPath();
@@ -237,7 +237,7 @@ var BABYLON;
             }
             this._enabled = false;
             var engine = this._scene.getEngine();
-            this._scene.unregisterAfterRender(this._syncData);
+            this._scene.unregisterBeforeRender(this._syncData);
             document.body.removeChild(this._globalDiv);
             window.removeEventListener("resize", this._syncPositions);
             this._scene.forceShowBoundingBoxes = false;
@@ -281,7 +281,7 @@ var BABYLON;
             window.addEventListener("resize", this._syncPositions);
             engine.getRenderingCanvas().addEventListener("click", this._onCanvasClick);
             this._syncPositions();
-            this._scene.registerAfterRender(this._syncData);
+            this._scene.registerBeforeRender(this._syncData);
         };
         DebugLayer.prototype._clearLabels = function () {
             this._drawingContext.clearRect(0, 0, this._drawingCanvas.width, this._drawingCanvas.height);

File diff suppressed because it is too large
+ 1 - 1
Babylon/Debug/babylon.debugLayer.js.map


+ 3 - 3
Babylon/Debug/babylon.debugLayer.ts

@@ -282,7 +282,7 @@
                 var centerY = projectedPosition.y;
                 var clientRect = this._drawingCanvas.getBoundingClientRect();
 
-                if (this._isClickInsideRect(clientRect.left * this._ratio + centerX - 5, clientRect.top * this._ratio + centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
+                if (this._showUI && this._isClickInsideRect(clientRect.left * this._ratio + centerX - 5, clientRect.top * this._ratio + centerY - labelOffset - 12, textMetrics.width + 10, 17)) {
                     onClick();
                 }
 
@@ -335,7 +335,7 @@
 
             var engine = this._scene.getEngine();
 
-            this._scene.unregisterAfterRender(this._syncData);
+            this._scene.unregisterBeforeRender(this._syncData);
             document.body.removeChild(this._globalDiv);
 
             window.removeEventListener("resize", this._syncPositions);
@@ -390,7 +390,7 @@
             engine.getRenderingCanvas().addEventListener("click", this._onCanvasClick);
 
             this._syncPositions();
-            this._scene.registerAfterRender(this._syncData);
+            this._scene.registerBeforeRender(this._syncData);
         }
 
         private _clearLabels(): void {

+ 56 - 3
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -5,6 +5,7 @@ var BABYLON;
             var _this = this;
             // Members
             this.filter = ShadowGenerator.FILTER_NONE;
+            this.blurSize = 2;
             this._darkness = 0;
             this._bias = 0.0001;
             this._transparencyShadow = false;
@@ -20,6 +21,25 @@ var BABYLON;
             this._shadowMap.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.renderParticles = false;
+            this._shadowMap.onAfterUnbind = function () {
+                if (_this.filter !== ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP) {
+                    return;
+                }
+                if (!_this._shadowMap2) {
+                    _this._shadowMap2 = new BABYLON.RenderTargetTexture(light.name + "_shadowMap", mapSize, _this._scene, false);
+                    _this._shadowMap2.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._shadowMap2.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._downSamplePostprocess = new BABYLON.PassPostProcess("downScale", 1.0 / _this.blurSize, null, BABYLON.Texture.NEAREST_SAMPLINGMODE, _this._scene.getEngine());
+                    _this._downSamplePostprocess.onApply = function (effect) {
+                        effect.setTexture("textureSampler", _this._shadowMap);
+                    };
+                    _this._boxBlurPostprocess = new BABYLON.PostProcess("DepthBoxBlur", "depthBoxBlur", ["screenSize"], [], 1.0 / _this.blurSize, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, _this._scene.getEngine());
+                    _this._boxBlurPostprocess.onApply = function (effect) {
+                        effect.setFloat2("screenSize", mapSize / _this.blurSize, mapSize / _this.blurSize);
+                    };
+                }
+                _this._scene.postProcessManager.directRender([_this._downSamplePostprocess, _this._boxBlurPostprocess], _this._shadowMap2.getInternalTexture());
+            };
             // Custom render function
             var renderSubMesh = function (subMesh) {
                 var mesh = subMesh.getRenderingMesh();
@@ -93,6 +113,13 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(ShadowGenerator, "FILTER_BLURVARIANCESHADOWMAP", {
+            get: function () {
+                return ShadowGenerator._FILTER_BLURVARIANCESHADOWMAP;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(ShadowGenerator.prototype, "useVarianceShadowMap", {
             get: function () {
                 return this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && this._light.supportsVSM();
@@ -105,7 +132,7 @@ var BABYLON;
         });
         Object.defineProperty(ShadowGenerator.prototype, "usePoissonSampling", {
             get: function () {
-                return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING || (this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && !this._light.supportsVSM());
+                return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
             },
             set: function (value) {
                 this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
@@ -113,9 +140,19 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(ShadowGenerator.prototype, "useBlurVarianceShadowMap", {
+            get: function () {
+                return this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP && this._light.supportsVSM();
+            },
+            set: function (value) {
+                this.filter = (value ? ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP : ShadowGenerator.FILTER_NONE);
+            },
+            enumerable: true,
+            configurable: true
+        });
         ShadowGenerator.prototype.isReady = function (subMesh, useInstances) {
             var defines = [];
-            if (this.useVarianceShadowMap) {
+            if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap) {
                 defines.push("#define VSM");
             }
             var attribs = [BABYLON.VertexBuffer.PositionKind];
@@ -159,6 +196,12 @@ var BABYLON;
         ShadowGenerator.prototype.getShadowMap = function () {
             return this._shadowMap;
         };
+        ShadowGenerator.prototype.getShadowMapForRendering = function () {
+            if (this._shadowMap2) {
+                return this._shadowMap2;
+            }
+            return this._shadowMap;
+        };
         ShadowGenerator.prototype.getLight = function () {
             return this._light;
         };
@@ -178,7 +221,7 @@ var BABYLON;
                 this._cachedPosition = lightPosition.clone();
                 this._cachedDirection = lightDirection.clone();
                 BABYLON.Matrix.LookAtLHToRef(lightPosition, this._light.position.add(lightDirection), BABYLON.Vector3.Up(), this._viewMatrix);
-                this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList);
+                this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList, this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP || this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP);
                 this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
             }
             return this._transformMatrix;
@@ -205,10 +248,20 @@ var BABYLON;
         };
         ShadowGenerator.prototype.dispose = function () {
             this._shadowMap.dispose();
+            if (this._shadowMap2) {
+                this._shadowMap2.dispose();
+            }
+            if (this._downSamplePostprocess) {
+                this._downSamplePostprocess.dispose();
+            }
+            if (this._boxBlurPostprocess) {
+                this._boxBlurPostprocess.dispose();
+            }
         };
         ShadowGenerator._FILTER_NONE = 0;
         ShadowGenerator._FILTER_VARIANCESHADOWMAP = 1;
         ShadowGenerator._FILTER_POISSONSAMPLING = 2;
+        ShadowGenerator._FILTER_BLURVARIANCESHADOWMAP = 3;
         return ShadowGenerator;
     })();
     BABYLON.ShadowGenerator = ShadowGenerator;

+ 63 - 4
Babylon/Lights/Shadows/babylon.shadowGenerator.ts

@@ -3,6 +3,7 @@
         private static _FILTER_NONE = 0;
         private static _FILTER_VARIANCESHADOWMAP = 1;
         private static _FILTER_POISSONSAMPLING = 2;
+        private static _FILTER_BLURVARIANCESHADOWMAP = 3;
 
         // Static
         public static get FILTER_NONE(): number {
@@ -17,8 +18,13 @@
             return ShadowGenerator._FILTER_POISSONSAMPLING;
         }
 
+        public static get FILTER_BLURVARIANCESHADOWMAP(): number {
+            return ShadowGenerator._FILTER_BLURVARIANCESHADOWMAP;
+        }
+
         // Members
         public filter = ShadowGenerator.FILTER_NONE;
+        public blurSize = 2;
 
         public get useVarianceShadowMap(): boolean {
             return this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && this._light.supportsVSM();
@@ -28,15 +34,23 @@
         }
 
         public get usePoissonSampling(): boolean {
-            return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING || (this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP && !this._light.supportsVSM());
+            return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
         }
         public set usePoissonSampling(value: boolean) {
             this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
         }
 
+        public get useBlurVarianceShadowMap(): boolean {
+            return this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP && this._light.supportsVSM();
+        }
+        public set useBlurVarianceShadowMap(value: boolean) {
+            this.filter = (value ? ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP : ShadowGenerator.FILTER_NONE);
+        }
+
         private _light: IShadowLight;
         private _scene: Scene;
         private _shadowMap: RenderTargetTexture;
+        private _shadowMap2: RenderTargetTexture;
         private _darkness = 0;
         private _bias = 0.0001;
         private _transparencyShadow = false;
@@ -50,6 +64,8 @@
         private _cachedDirection: Vector3;
         private _cachedDefines: string;
         private _currentRenderID: number;
+        private _downSamplePostprocess: PassPostProcess;
+        private _boxBlurPostprocess: PostProcess;
 
         constructor(mapSize: number, light: IShadowLight) {
             this._light = light;
@@ -63,6 +79,29 @@
             this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.renderParticles = false;
 
+            this._shadowMap.onAfterUnbind = () => {
+                if (this.filter !== ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP) {
+                    return;
+                }
+
+                if (!this._shadowMap2) {
+                    this._shadowMap2 = new RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false);
+                    this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
+                    this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
+                    
+                    this._downSamplePostprocess = new PassPostProcess("downScale", 1.0 / this.blurSize, null, Texture.NEAREST_SAMPLINGMODE, this._scene.getEngine());
+                    this._downSamplePostprocess.onApply = effect => {
+                        effect.setTexture("textureSampler", this._shadowMap);
+                    };
+                    this._boxBlurPostprocess = new PostProcess("DepthBoxBlur", "depthBoxBlur", ["screenSize"], [], 1.0 / this.blurSize, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
+                    this._boxBlurPostprocess.onApply = effect => {
+                        effect.setFloat2("screenSize", mapSize / this.blurSize, mapSize / this.blurSize);
+                    };
+                }
+
+                this._scene.postProcessManager.directRender([this._downSamplePostprocess, this._boxBlurPostprocess], this._shadowMap2.getInternalTexture());
+            }
+
             // Custom render function
             var renderSubMesh = (subMesh: SubMesh): void => {
                 var mesh = subMesh.getRenderingMesh();
@@ -110,7 +149,7 @@
             };
 
             this._shadowMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
-                var index;
+                var index: number;
 
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
@@ -132,7 +171,7 @@
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
             var defines = [];
 
-            if (this.useVarianceShadowMap) {
+            if (this.useVarianceShadowMap || this.useBlurVarianceShadowMap) {
                 defines.push("#define VSM");
             }
 
@@ -188,6 +227,14 @@
             return this._shadowMap;
         }
 
+        public getShadowMapForRendering(): RenderTargetTexture {
+            if (this._shadowMap2) {
+                return this._shadowMap2;
+            }
+
+            return this._shadowMap;
+        }
+
         public getLight(): IShadowLight {
             return this._light;
         }
@@ -215,7 +262,7 @@
 
                 Matrix.LookAtLHToRef(lightPosition, this._light.position.add(lightDirection), Vector3.Up(), this._viewMatrix);
 
-                this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList);
+                this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList, this.filter === ShadowGenerator.FILTER_VARIANCESHADOWMAP || this.filter === ShadowGenerator.FILTER_BLURVARIANCESHADOWMAP);
 
                 this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
             }
@@ -250,6 +297,18 @@
 
         public dispose(): void {
             this._shadowMap.dispose();
+
+            if (this._shadowMap2) {
+                this._shadowMap2.dispose();
+            }
+
+            if (this._downSamplePostprocess) {
+                this._downSamplePostprocess.dispose();
+            }
+
+            if (this._boxBlurPostprocess) {
+                this._boxBlurPostprocess.dispose();
+            }
         }
     }
 } 

+ 17 - 5
Babylon/Lights/babylon.directionalLight.js

@@ -11,6 +11,8 @@ var BABYLON;
         function DirectionalLight(name, direction, scene) {
             _super.call(this, name, scene);
             this.direction = direction;
+            this.shadowOrthoScale = 1.1;
+            this.shadowOrthoDepthScale = 3;
             this.position = direction.scale(-1);
         }
         DirectionalLight.prototype.getAbsolutePosition = function () {
@@ -20,11 +22,13 @@ var BABYLON;
             this.direction = BABYLON.Vector3.Normalize(target.subtract(this.position));
             return this.direction;
         };
-        DirectionalLight.prototype.setShadowProjectionMatrix = function (matrix, viewMatrix, renderList) {
+        DirectionalLight.prototype.setShadowProjectionMatrix = function (matrix, viewMatrix, renderList, useVSM) {
             var orthoLeft = Number.MAX_VALUE;
             var orthoRight = Number.MIN_VALUE;
             var orthoTop = Number.MIN_VALUE;
             var orthoBottom = Number.MAX_VALUE;
+            var orthoNear = Number.MAX_VALUE;
+            var orthoFar = Number.MIN_VALUE;
             var tempVector3 = BABYLON.Vector3.Zero();
             var activeCamera = this.getScene().activeCamera;
             for (var meshIndex = 0; meshIndex < renderList.length; meshIndex++) {
@@ -39,14 +43,22 @@ var BABYLON;
                         orthoRight = tempVector3.x;
                     if (tempVector3.y > orthoTop)
                         orthoTop = tempVector3.y;
+                    if (tempVector3.z < orthoNear)
+                        orthoNear = tempVector3.z;
+                    if (tempVector3.z > orthoFar)
+                        orthoFar = tempVector3.z;
                 }
             }
-            var orthoWidth = Math.max(Math.abs(orthoRight), Math.abs(orthoLeft)) * 1.1;
-            var orthoHeight = Math.max(Math.abs(orthoTop), Math.abs(orthoBottom)) * 1.1;
-            BABYLON.Matrix.OrthoOffCenterLHToRef(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, activeCamera.minZ, activeCamera.maxZ, matrix);
+            var orthoWidth = Math.max(Math.abs(orthoRight), Math.abs(orthoLeft)) * this.shadowOrthoScale;
+            var orthoHeight = Math.max(Math.abs(orthoTop), Math.abs(orthoBottom)) * this.shadowOrthoScale;
+            var orthoDepth = Math.max(Math.abs(orthoNear), Math.abs(orthoFar)) * this.shadowOrthoDepthScale;
+            BABYLON.Matrix.OrthoOffCenterLHToRef(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, useVSM ? -orthoDepth : activeCamera.minZ, orthoDepth, matrix);
+        };
+        DirectionalLight.prototype.getVSMOffset = function () {
+            return 0.55;
         };
         DirectionalLight.prototype.supportsVSM = function () {
-            return false;
+            return true;
         };
         DirectionalLight.prototype.needRefreshPerFrame = function () {
             return true;

+ 20 - 5
Babylon/Lights/babylon.directionalLight.ts

@@ -6,6 +6,9 @@
         public transformedPosition: Vector3;
         private _worldMatrix: Matrix;
 
+        public shadowOrthoScale = 1.1;
+        public shadowOrthoDepthScale = 3;
+
         constructor(name: string, public direction: Vector3, scene: Scene) {
             super(name, scene);
 
@@ -21,11 +24,13 @@
             return this.direction;
         }
 
-        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
+        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>, useVSM: boolean): void {
             var orthoLeft = Number.MAX_VALUE;
             var orthoRight = Number.MIN_VALUE;
             var orthoTop = Number.MIN_VALUE;
             var orthoBottom = Number.MAX_VALUE;
+            var orthoNear = Number.MAX_VALUE;
+            var orthoFar = Number.MIN_VALUE;
 
             var tempVector3 = Vector3.Zero();
 
@@ -47,17 +52,27 @@
                         orthoRight = tempVector3.x;
                     if (tempVector3.y > orthoTop)
                         orthoTop = tempVector3.y;
+
+                    if (tempVector3.z < orthoNear)
+                        orthoNear = tempVector3.z;
+                    if (tempVector3.z > orthoFar)
+                        orthoFar = tempVector3.z;
                 }
             }
 
-            var orthoWidth = Math.max(Math.abs(orthoRight), Math.abs(orthoLeft)) * 1.1;
-            var orthoHeight = Math.max(Math.abs(orthoTop), Math.abs(orthoBottom)) * 1.1;
+            var orthoWidth = Math.max(Math.abs(orthoRight), Math.abs(orthoLeft)) * this.shadowOrthoScale;
+            var orthoHeight = Math.max(Math.abs(orthoTop), Math.abs(orthoBottom)) * this.shadowOrthoScale;
+            var orthoDepth = Math.max(Math.abs(orthoNear), Math.abs(orthoFar)) * this.shadowOrthoDepthScale;
+
+            Matrix.OrthoOffCenterLHToRef(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, useVSM ? -orthoDepth : activeCamera.minZ, orthoDepth, matrix);
+        }
 
-            Matrix.OrthoOffCenterLHToRef(-orthoWidth, orthoWidth, -orthoHeight, orthoHeight, activeCamera.minZ, activeCamera.maxZ, matrix);
+        public getVSMOffset(): number {
+            return 0.55;
         }
 
         public supportsVSM(): boolean {
-            return false;
+            return true;
         }
 
         public needRefreshPerFrame(): boolean {

+ 2 - 2
Babylon/Lights/babylon.light.ts

@@ -9,10 +9,10 @@
         computeTransformedPosition(): boolean;
         getScene(): Scene;
 
-        setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void;
+        setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>, useVSM: boolean): void;
 
+        getVSMOffset(): number;
         supportsVSM(): boolean;
-
         needRefreshPerFrame(): boolean;
 
         _shadowGenerator: ShadowGenerator;

+ 4 - 1
Babylon/Lights/babylon.spotLight.js

@@ -18,10 +18,13 @@ var BABYLON;
         SpotLight.prototype.getAbsolutePosition = function () {
             return this.transformedPosition ? this.transformedPosition : this.position;
         };
-        SpotLight.prototype.setShadowProjectionMatrix = function (matrix, viewMatrix, renderList) {
+        SpotLight.prototype.setShadowProjectionMatrix = function (matrix, viewMatrix, renderList, useVSM) {
             var activeCamera = this.getScene().activeCamera;
             BABYLON.Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
         };
+        SpotLight.prototype.getVSMOffset = function () {
+            return 0.2;
+        };
         SpotLight.prototype.supportsVSM = function () {
             return true;
         };

+ 5 - 1
Babylon/Lights/babylon.spotLight.ts

@@ -14,11 +14,15 @@
             return this.transformedPosition ? this.transformedPosition : this.position;
         }
 
-        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
+        public setShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>, useVSM: boolean): void {
             var activeCamera = this.getScene().activeCamera;
             Matrix.PerspectiveFovLHToRef(this.angle, 1.0, activeCamera.minZ, activeCamera.maxZ, matrix);
         }
 
+        public getVSMOffset(): number {
+            return 0.2;
+        }
+
         public supportsVSM(): boolean {
             return true;
         }

+ 3 - 0
Babylon/Materials/Textures/babylon.renderTargetTexture.js

@@ -141,6 +141,9 @@ var BABYLON;
             }
             // Unbind
             engine.unBindFramebuffer(this._texture);
+            if (this.onAfterUnbind) {
+                this.onAfterUnbind();
+            }
         };
         RenderTargetTexture.prototype.clone = function () {
             var textureSize = this.getSize();

+ 5 - 0
Babylon/Materials/Textures/babylon.renderTargetTexture.ts

@@ -6,6 +6,7 @@
         public coordinatesMode = Texture.PROJECTION_MODE;
         public onBeforeRender: () => void;
         public onAfterRender: () => void;
+        public onAfterUnbind: () => void;
         public activeCamera: Camera;
         public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
 
@@ -169,6 +170,10 @@
 
             // Unbind
             engine.unBindFramebuffer(this._texture);
+
+            if (this.onAfterUnbind) {
+                this.onAfterUnbind();
+            }
         }
 
         public clone(): RenderTargetTexture {

+ 3 - 3
Babylon/Materials/babylon.standardMaterial.js

@@ -231,7 +231,7 @@ var BABYLON;
                                 defines.push("#define SHADOWS");
                                 shadowsActivated = true;
                             }
-                            if (shadowGenerator.useVarianceShadowMap) {
+                            if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) {
                                 defines.push("#define SHADOWVSM" + lightIndex);
                                 if (lightIndex > 0) {
                                     fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
@@ -476,8 +476,8 @@ var BABYLON;
                         var shadowGenerator = light.getShadowGenerator();
                         if (mesh.receiveShadows && shadowGenerator) {
                             this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
-                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
-                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
+                            this._effect.setFloat4("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias(), shadowGenerator.getLight().getVSMOffset());
                         }
                     }
                     lightIndex++;

+ 3 - 3
Babylon/Materials/babylon.standardMaterial.ts

@@ -267,7 +267,7 @@
                                 shadowsActivated = true;
                             }
 
-                            if (shadowGenerator.useVarianceShadowMap) {
+                            if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) {
                                 defines.push("#define SHADOWVSM" + lightIndex);
                                 if (lightIndex > 0) {
                                     fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
@@ -584,8 +584,8 @@
                         var shadowGenerator = light.getShadowGenerator();
                         if (mesh.receiveShadows && shadowGenerator) {
                             this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
-                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
-                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
+                            this._effect.setFloat4("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.getBias(), shadowGenerator.getLight().getVSMOffset());
                         }
                     }
 

+ 4 - 0
Babylon/PostProcess/babylon.postProcess.js

@@ -2,6 +2,7 @@ var BABYLON;
 (function (BABYLON) {
     var PostProcess = (function () {
         function PostProcess(name, fragmentUrl, parameters, samplers, ratio, camera, samplingMode, engine, reusable, defines) {
+            if (samplingMode === void 0) { samplingMode = BABYLON.Texture.NEAREST_SAMPLINGMODE; }
             this.name = name;
             this.width = -1;
             this.height = -1;
@@ -88,6 +89,9 @@ var BABYLON;
                 }
                 this._textures.reset();
             }
+            if (!camera) {
+                return;
+            }
             camera.detachPostProcess(this);
             var index = camera._postProcesses.indexOf(this);
             if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {

+ 8 - 5
Babylon/PostProcess/babylon.postProcess.ts

@@ -13,11 +13,11 @@
         private _engine: Engine;
         private _renderRatio: number;
         private _reusable = false;
-        public _textures = new BABYLON.SmartArray<WebGLTexture>(2);
+        public _textures = new SmartArray<WebGLTexture>(2);
         public _currentRenderTextureInd = 0;
         private _effect: Effect;
 
-        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number, camera: Camera, samplingMode: number, engine?: Engine, reusable?: boolean, defines?: string) {
+        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], ratio: number, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string) {
             if (camera != null) {
                 this._camera = camera;
                 this._scene = camera.getScene();
@@ -29,7 +29,7 @@
             }
 
             this._renderRatio = ratio;
-            this.renderTargetSamplingMode = samplingMode ? samplingMode : BABYLON.Texture.NEAREST_SAMPLINGMODE;
+            this.renderTargetSamplingMode = samplingMode ? samplingMode : Texture.NEAREST_SAMPLINGMODE;
             this._reusable = reusable || false;
 
             samplers = samplers || [];
@@ -99,7 +99,7 @@
             // States
             this._engine.enableEffect(this._effect);
             this._engine.setState(false);
-            this._engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            this._engine.setAlphaMode(Engine.ALPHA_DISABLE);
             this._engine.setDepthBuffer(false);
             this._engine.setDepthWrite(false);
 
@@ -114,7 +114,7 @@
             return this._effect;
         }
 
-        public dispose(camera: Camera): void {
+        public dispose(camera?: Camera): void {
             camera = camera || this._camera;
 
             if (this._textures.length > 0) {
@@ -124,6 +124,9 @@
                 this._textures.reset();
             }
 
+            if (!camera) {
+                return;
+            }
             camera.detachPostProcess(this);
 
             var index = camera._postProcesses.indexOf(this);

+ 32 - 2
Babylon/PostProcess/babylon.postProcessManager.js

@@ -32,8 +32,38 @@ var BABYLON;
             postProcesses[this._scene.activeCamera._postProcessesTakenIndices[0]].activate(this._scene.activeCamera, sourceTexture);
             return true;
         };
-        PostProcessManager.prototype._finalizeFrame = function (doNotPresent, targetTexture) {
-            var postProcesses = this._scene.activeCamera._postProcesses;
+        PostProcessManager.prototype.directRender = function (postProcesses, targetTexture) {
+            var engine = this._scene.getEngine();
+            for (var index = 0; index < postProcesses.length; index++) {
+                if (index < postProcesses.length - 1) {
+                    postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
+                }
+                else {
+                    if (targetTexture) {
+                        engine.bindFramebuffer(targetTexture);
+                    }
+                    else {
+                        engine.restoreDefaultFramebuffer();
+                    }
+                }
+                var pp = postProcesses[index];
+                var effect = pp.apply();
+                if (effect) {
+                    if (pp.onBeforeRender) {
+                        pp.onBeforeRender(effect);
+                    }
+                    // VBOs
+                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+                    // Draw order
+                    engine.draw(true, 0, 6);
+                }
+            }
+            // Restore depth buffer
+            engine.setDepthBuffer(true);
+            engine.setDepthWrite(true);
+        };
+        PostProcessManager.prototype._finalizeFrame = function (doNotPresent, targetTexture, postProcesses) {
+            postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
             var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
             if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
                 return;

+ 37 - 2
Babylon/PostProcess/babylon.postProcessManager.ts

@@ -44,8 +44,43 @@
             return true;
         }
 
-        public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture): void {
-            var postProcesses = this._scene.activeCamera._postProcesses;
+        public directRender(postProcesses: PostProcess[], targetTexture?: WebGLTexture): void {
+            var engine = this._scene.getEngine();
+
+            for (var index = 0; index < postProcesses.length; index++) {
+                if (index < postProcesses.length - 1) {
+                    postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
+                } else {
+                    if (targetTexture) {
+                        engine.bindFramebuffer(targetTexture);
+                    } else {
+                        engine.restoreDefaultFramebuffer();
+                    }
+                }
+
+                var pp = postProcesses[index];
+                var effect = pp.apply();
+
+                if (effect) {
+                    if (pp.onBeforeRender) {
+                        pp.onBeforeRender(effect);
+                    }
+
+                    // VBOs
+                    engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
+
+                    // Draw order
+                    engine.draw(true, 0, 6);
+                }
+            }
+
+            // Restore depth buffer
+            engine.setDepthBuffer(true);
+            engine.setDepthWrite(true);
+        }
+
+        public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture, postProcesses?: PostProcess[]): void {
+            postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
             var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
             if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
                 return;

+ 14 - 14
Babylon/Shaders/default.fragment.fx

@@ -35,7 +35,7 @@ uniform vec3 vLightSpecular0;
 #ifdef SHADOW0
 varying vec4 vPositionFromLight0;
 uniform sampler2D shadowSampler0;
-uniform vec3 shadowsInfo0;
+uniform vec4 shadowsInfo0;
 #endif
 #ifdef SPOTLIGHT0
 uniform vec4 vLightDirection0;
@@ -52,7 +52,7 @@ uniform vec3 vLightSpecular1;
 #ifdef SHADOW1
 varying vec4 vPositionFromLight1;
 uniform sampler2D shadowSampler1;
-uniform vec3 shadowsInfo1;
+uniform vec4 shadowsInfo1;
 #endif
 #ifdef SPOTLIGHT1
 uniform vec4 vLightDirection1;
@@ -69,7 +69,7 @@ uniform vec3 vLightSpecular2;
 #ifdef SHADOW2
 varying vec4 vPositionFromLight2;
 uniform sampler2D shadowSampler2;
-uniform vec3 shadowsInfo2;
+uniform vec4 shadowsInfo2;
 #endif
 #ifdef SPOTLIGHT2
 uniform vec4 vLightDirection2;
@@ -86,7 +86,7 @@ uniform vec3 vLightSpecular3;
 #ifdef SHADOW3
 varying vec4 vPositionFromLight3;
 uniform sampler2D shadowSampler3;
-uniform vec3 shadowsInfo3;
+uniform vec4 shadowsInfo3;
 #endif
 #ifdef SPOTLIGHT3
 uniform vec4 vLightDirection3;
@@ -204,8 +204,8 @@ vec3 computeReflectionCoords(float mode, vec4 worldPos, vec3 worldNormal)
 
 float unpack(vec4 color)
 {
-	const vec4 bitShift = vec4(1. / (255. * 255. * 255.), 1. / (255. * 255.), 1. / 255., 1.);
-	return dot(color, bitShift);
+	const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+	return dot(color, bit_shift);
 }
 
 float unpackHalf(vec2 color)
@@ -260,7 +260,7 @@ float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, flo
 }
 
 // Thanks to http://devmaster.net/
-float ChebychevInequality(vec2 moments, float t)
+float ChebychevInequality(vec2 moments, float t, float offset)
 {
 	if (t <= moments.x)
 	{
@@ -271,10 +271,10 @@ float ChebychevInequality(vec2 moments, float t)
 	variance = max(variance, 0.02);
 
 	float d = t - moments.x;
-	return clamp(variance / (variance + d * d) - 0.2, 0., 1.0);
+	return clamp(variance / (variance + d * d) - offset, 0., 1.0);
 }
 
-float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler)
+float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float offset)
 {
 	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
 	vec2 uv = 0.5 * depth.xy + vec2(0.5, 0.5);
@@ -287,7 +287,7 @@ float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler)
 	vec4 texel = texture2D(shadowSampler, uv);
 
 	vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));
-	return 1.0 - ChebychevInequality(moments, depth.z);
+	return 1.0 - ChebychevInequality(moments, depth.z, offset);
 }
 #endif
 
@@ -531,7 +531,7 @@ void main(void) {
 #endif
 #ifdef SHADOW0
 #ifdef SHADOWVSM0
-	shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0);
+	shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.w);
 #else
 	#ifdef SHADOWPCF0
 		shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z);
@@ -558,7 +558,7 @@ void main(void) {
 #endif
 #ifdef SHADOW1
 #ifdef SHADOWVSM1
-	shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1);
+	shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.w);
 #else
 	#ifdef SHADOWPCF1
 		shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z);
@@ -585,7 +585,7 @@ void main(void) {
 #endif
 #ifdef SHADOW2
 #ifdef SHADOWVSM2
-	shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2);
+	shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.w);
 #else
 	#ifdef SHADOWPCF2
 		shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z);
@@ -612,7 +612,7 @@ void main(void) {
 #endif
 #ifdef SHADOW3
 #ifdef SHADOWVSM3
-	shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3);
+	shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.w);
 #else
 	#ifdef SHADOWPCF3
 		shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z);

+ 40 - 0
Babylon/Shaders/depthBoxBlur.fragment.fx

@@ -0,0 +1,40 @@
+#ifdef GL_ES
+precision highp float;
+#endif
+
+#define OFFSET 1
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+// Parameters
+uniform vec2 screenSize;
+
+vec4 pack(float depth)
+{
+	const vec4 bit_shift = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0);
+	const vec4 bit_mask = vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+
+	vec4 res = fract(depth * bit_shift);
+	res -= res.xxyz * bit_mask;
+
+	return res;
+}
+
+float unpack(vec4 color)
+{
+	const vec4 bit_shift = vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0);
+	return dot(color, bit_shift);
+}
+
+void main(void)
+{
+	vec4 colorDepth = vec4(0.0);
+
+	for (int x = -OFFSET; x <= OFFSET; x++)
+		for (int y = -OFFSET; y <= OFFSET; y++)
+			colorDepth += texture2D(textureSampler, vUV + vec2(x, y) / screenSize);
+
+	gl_FragColor = (colorDepth / float((OFFSET * 2 + 1) * (OFFSET * 2 + 1)));
+}

+ 7 - 7
Babylon/Shaders/shadowMap.fragment.fx

@@ -4,13 +4,13 @@ precision highp float;
 
 vec4 pack(float depth)
 {
-	const vec4 bitOffset = vec4(255. * 255. * 255., 255. * 255., 255., 1.);
-	const vec4 bitMask = vec4(0., 1. / 255., 1. / 255., 1. / 255.);
-	
-	vec4 comp = mod(depth * bitOffset * vec4(255.), vec4(255.)) / vec4(255.);
-	comp -= comp.xxyz * bitMask;
-	
-	return comp;
+	const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
+	const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
+
+	vec4 res = fract(depth * bit_shift);
+	res -= res.xxyz * bit_mask;
+
+	return res;
 }
 
 // Thanks to http://devmaster.net/

File diff suppressed because it is too large
+ 125 - 19
babylon.2.1-alpha.debug.js


File diff suppressed because it is too large
+ 16 - 16
babylon.2.1-alpha.js