Browse Source

Merge pull request #7481 from Popov72/shadow-factorize-code

Shadow generators code refactoring
sebavan 5 years ago
parent
commit
fca85c2f71

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

@@ -59,6 +59,7 @@
 - Added `RenderTargetTexture.getCustomRenderList` to overload the render list at rendering time (and possibly for each layer (2DArray) / face (Cube)) ([Popov72](https://github.com/Popov72))
 - Added `RenderTargetTexture.getCustomRenderList` to overload the render list at rendering time (and possibly for each layer (2DArray) / face (Cube)) ([Popov72](https://github.com/Popov72))
 - Make sure all properties of CascadedShadowMap class are serialized/parsed ([Popov72](https://github.com/Popov72))
 - Make sure all properties of CascadedShadowMap class are serialized/parsed ([Popov72](https://github.com/Popov72))
 - Added `textures/opacity.png` file to the Playground ([Popov72](https://github.com/Popov72))
 - Added `textures/opacity.png` file to the Playground ([Popov72](https://github.com/Popov72))
+- Refactored the shadow generators code ([Popov72](https://github.com/Popov72))
 
 
 ### Engine
 ### Engine
 
 

File diff suppressed because it is too large
+ 91 - 927
src/Lights/Shadows/cascadedShadowGenerator.ts


+ 163 - 123
src/Lights/Shadows/shadowGenerator.ts

@@ -135,6 +135,12 @@ export interface IShadowGenerator {
  * Documentation: https://doc.babylonjs.com/babylon101/shadows
  * Documentation: https://doc.babylonjs.com/babylon101/shadows
  */
  */
 export class ShadowGenerator implements IShadowGenerator {
 export class ShadowGenerator implements IShadowGenerator {
+
+    /**
+     * Name of the shadow generator class
+     */
+    public static CLASSNAME = "ShadowGenerator";
+
     /**
     /**
      * Shadow generator mode None: no filtering applied.
      * Shadow generator mode None: no filtering applied.
      */
      */
@@ -232,7 +238,7 @@ export class ShadowGenerator implements IShadowGenerator {
      */
      */
     public onAfterShadowMapRenderMeshObservable = new Observable<Mesh>();
     public onAfterShadowMapRenderMeshObservable = new Observable<Mesh>();
 
 
-    private _bias = 0.00005;
+    protected _bias = 0.00005;
     /**
     /**
      * Gets the bias: offset applied on the depth preventing acnea (in light direction).
      * Gets the bias: offset applied on the depth preventing acnea (in light direction).
      */
      */
@@ -246,7 +252,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._bias = bias;
         this._bias = bias;
     }
     }
 
 
-    private _normalBias = 0;
+    protected _normalBias = 0;
     /**
     /**
      * Gets the normalBias: offset applied on the depth preventing acnea (along side the normal direction and proportinal to the light/normal angle).
      * Gets the normalBias: offset applied on the depth preventing acnea (along side the normal direction and proportinal to the light/normal angle).
      */
      */
@@ -260,7 +266,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._normalBias = normalBias;
         this._normalBias = normalBias;
     }
     }
 
 
-    private _blurBoxOffset = 1;
+    protected _blurBoxOffset = 1;
     /**
     /**
      * Gets the blur box offset: offset applied during the blur pass.
      * Gets the blur box offset: offset applied during the blur pass.
      * Only useful if useKernelBlur = false
      * Only useful if useKernelBlur = false
@@ -281,7 +287,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._disposeBlurPostProcesses();
         this._disposeBlurPostProcesses();
     }
     }
 
 
-    private _blurScale = 2;
+    protected _blurScale = 2;
     /**
     /**
      * Gets the blur scale: scale of the blurred texture compared to the main shadow map.
      * Gets the blur scale: scale of the blurred texture compared to the main shadow map.
      * 2 means half of the size.
      * 2 means half of the size.
@@ -302,7 +308,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._disposeBlurPostProcesses();
         this._disposeBlurPostProcesses();
     }
     }
 
 
-    private _blurKernel = 1;
+    protected _blurKernel = 1;
     /**
     /**
      * Gets the blur kernel: kernel size of the blur pass.
      * Gets the blur kernel: kernel size of the blur pass.
      * Only useful if useKernelBlur = true
      * Only useful if useKernelBlur = true
@@ -323,7 +329,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._disposeBlurPostProcesses();
         this._disposeBlurPostProcesses();
     }
     }
 
 
-    private _useKernelBlur = false;
+    protected _useKernelBlur = false;
     /**
     /**
      * Gets whether the blur pass is a kernel blur (if true) or box blur.
      * Gets whether the blur pass is a kernel blur (if true) or box blur.
      * Only useful in filtered mode (useBlurExponentialShadowMap...)
      * Only useful in filtered mode (useBlurExponentialShadowMap...)
@@ -344,7 +350,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._disposeBlurPostProcesses();
         this._disposeBlurPostProcesses();
     }
     }
 
 
-    private _depthScale: number;
+    protected _depthScale: number;
     /**
     /**
      * Gets the depth scale used in ESM mode.
      * Gets the depth scale used in ESM mode.
      */
      */
@@ -359,7 +365,11 @@ export class ShadowGenerator implements IShadowGenerator {
         this._depthScale = value;
         this._depthScale = value;
     }
     }
 
 
-    private _filter = ShadowGenerator.FILTER_NONE;
+    protected _validateFilter(filter: number): number {
+        return filter;
+    }
+
+    protected _filter = ShadowGenerator.FILTER_NONE;
     /**
     /**
      * Gets the current mode of the shadow generator (normal, PCF, ESM...).
      * Gets the current mode of the shadow generator (normal, PCF, ESM...).
      * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
      * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
@@ -372,6 +382,8 @@ export class ShadowGenerator implements IShadowGenerator {
      * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
      * The returned value is a number equal to one of the available mode defined in ShadowMap.FILTER_x like _FILTER_NONE
      */
      */
     public set filter(value: number) {
     public set filter(value: number) {
+        value = this._validateFilter(value);
+
         // Blurring the cubemap is going to be too expensive. Reverting to unblurred version
         // Blurring the cubemap is going to be too expensive. Reverting to unblurred version
         if (this._light.needCube()) {
         if (this._light.needCube()) {
             if (value === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
             if (value === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
@@ -417,11 +429,13 @@ export class ShadowGenerator implements IShadowGenerator {
      * Sets the current filter to Poisson Sampling.
      * Sets the current filter to Poisson Sampling.
      */
      */
     public set usePoissonSampling(value: boolean) {
     public set usePoissonSampling(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_POISSONSAMPLING);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
         if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
             return;
             return;
         }
         }
 
 
-        this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
     /**
     /**
@@ -434,10 +448,12 @@ export class ShadowGenerator implements IShadowGenerator {
      * Sets the current filter is to ESM.
      * Sets the current filter is to ESM.
      */
      */
     public set useExponentialShadowMap(value: boolean) {
     public set useExponentialShadowMap(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
         if (!value && this.filter !== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
     /**
     /**
@@ -450,10 +466,12 @@ export class ShadowGenerator implements IShadowGenerator {
      * Gets if the current filter is set to filtered  ESM.
      * Gets if the current filter is set to filtered  ESM.
      */
      */
     public set useBlurExponentialShadowMap(value: boolean) {
     public set useBlurExponentialShadowMap(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
         if (!value && this.filter !== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
     /**
     /**
@@ -468,10 +486,12 @@ export class ShadowGenerator implements IShadowGenerator {
      * exponential to prevent steep falloff artifacts).
      * exponential to prevent steep falloff artifacts).
      */
      */
     public set useCloseExponentialShadowMap(value: boolean) {
     public set useCloseExponentialShadowMap(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
         if (!value && this.filter !== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
     /**
     /**
@@ -486,10 +506,12 @@ export class ShadowGenerator implements IShadowGenerator {
      * exponential to prevent steep falloff artifacts).
      * exponential to prevent steep falloff artifacts).
      */
      */
     public set useBlurCloseExponentialShadowMap(value: boolean) {
     public set useBlurCloseExponentialShadowMap(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
         if (!value && this.filter !== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
     /**
     /**
@@ -502,13 +524,15 @@ export class ShadowGenerator implements IShadowGenerator {
      * Sets the current filter to "PCF" (percentage closer filtering).
      * Sets the current filter to "PCF" (percentage closer filtering).
      */
      */
     public set usePercentageCloserFiltering(value: boolean) {
     public set usePercentageCloserFiltering(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_PCF);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_PCF) {
         if (!value && this.filter !== ShadowGenerator.FILTER_PCF) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_PCF : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
-    private _filteringQuality = ShadowGenerator.QUALITY_HIGH;
+    protected _filteringQuality = ShadowGenerator.QUALITY_HIGH;
     /**
     /**
      * Gets the PCF or PCSS Quality.
      * Gets the PCF or PCSS Quality.
      * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
      * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
@@ -542,13 +566,15 @@ export class ShadowGenerator implements IShadowGenerator {
      * Sets the current filter to "PCSS" (contact hardening).
      * Sets the current filter to "PCSS" (contact hardening).
      */
      */
     public set useContactHardeningShadow(value: boolean) {
     public set useContactHardeningShadow(value: boolean) {
+        let filter = this._validateFilter(ShadowGenerator.FILTER_PCSS);
+
         if (!value && this.filter !== ShadowGenerator.FILTER_PCSS) {
         if (!value && this.filter !== ShadowGenerator.FILTER_PCSS) {
             return;
             return;
         }
         }
-        this.filter = (value ? ShadowGenerator.FILTER_PCSS : ShadowGenerator.FILTER_NONE);
+        this.filter = (value ? filter : ShadowGenerator.FILTER_NONE);
     }
     }
 
 
-    private _contactHardeningLightSizeUVRatio = 0.1;
+    protected _contactHardeningLightSizeUVRatio = 0.1;
     /**
     /**
      * Gets the Light Size (in shadow map uv unit) used in PCSS to determine the blocker search area and the penumbra size.
      * Gets the Light Size (in shadow map uv unit) used in PCSS to determine the blocker search area and the penumbra size.
      * Using a ratio helps keeping shape stability independently of the map size.
      * Using a ratio helps keeping shape stability independently of the map size.
@@ -574,7 +600,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._contactHardeningLightSizeUVRatio = contactHardeningLightSizeUVRatio;
         this._contactHardeningLightSizeUVRatio = contactHardeningLightSizeUVRatio;
     }
     }
 
 
-    private _darkness = 0;
+    protected _darkness = 0;
 
 
     /** Gets or sets the actual darkness of a shadow */
     /** Gets or sets the actual darkness of a shadow */
     public get darkness() {
     public get darkness() {
@@ -611,7 +637,7 @@ export class ShadowGenerator implements IShadowGenerator {
         return this;
         return this;
     }
     }
 
 
-    private _transparencyShadow = false;
+    protected _transparencyShadow = false;
 
 
     /** Gets or sets the ability to have transparent shadow  */
     /** Gets or sets the ability to have transparent shadow  */
     public get transparencyShadow() {
     public get transparencyShadow() {
@@ -632,8 +658,9 @@ export class ShadowGenerator implements IShadowGenerator {
         return this;
         return this;
     }
     }
 
 
-    private _shadowMap: Nullable<RenderTargetTexture>;
-    private _shadowMap2: Nullable<RenderTargetTexture>;
+    protected _shadowMap: Nullable<RenderTargetTexture>;
+    protected _shadowMap2: Nullable<RenderTargetTexture>;
+
     /**
     /**
      * Gets the main RTT containing the shadow map (usually storing depth from the light point of view).
      * Gets the main RTT containing the shadow map (usually storing depth from the light point of view).
      * @returns The render target texture if present otherwise, null
      * @returns The render target texture if present otherwise, null
@@ -641,6 +668,7 @@ export class ShadowGenerator implements IShadowGenerator {
     public getShadowMap(): Nullable<RenderTargetTexture> {
     public getShadowMap(): Nullable<RenderTargetTexture> {
         return this._shadowMap;
         return this._shadowMap;
     }
     }
+
     /**
     /**
      * Gets the RTT used during rendering (can be a blurred version of the shadow map or the shadow map itself).
      * Gets the RTT used during rendering (can be a blurred version of the shadow map or the shadow map itself).
      * @returns The render target texture if the shadow map is present otherwise, null
      * @returns The render target texture if the shadow map is present otherwise, null
@@ -658,7 +686,7 @@ export class ShadowGenerator implements IShadowGenerator {
      * @returns "ShadowGenerator"
      * @returns "ShadowGenerator"
      */
      */
     public getClassName(): string {
     public getClassName(): string {
-        return "ShadowGenerator";
+        return ShadowGenerator.CLASSNAME;
     }
     }
 
 
     /**
     /**
@@ -713,11 +741,10 @@ export class ShadowGenerator implements IShadowGenerator {
 
 
     /**
     /**
      * Controls the extent to which the shadows fade out at the edge of the frustum
      * Controls the extent to which the shadows fade out at the edge of the frustum
-     * Used only by directionals and spots
      */
      */
     public frustumEdgeFalloff = 0;
     public frustumEdgeFalloff = 0;
 
 
-    private _light: IShadowLight;
+    protected _light: IShadowLight;
     /**
     /**
      * Returns the associated light object.
      * Returns the associated light object.
      * @returns the light generating the shadow
      * @returns the light generating the shadow
@@ -733,28 +760,28 @@ export class ShadowGenerator implements IShadowGenerator {
      */
      */
     public forceBackFacesOnly = false;
     public forceBackFacesOnly = false;
 
 
-    private _scene: Scene;
-    private _lightDirection = Vector3.Zero();
-
-    private _effect: Effect;
-
-    private _viewMatrix = Matrix.Zero();
-    private _projectionMatrix = Matrix.Zero();
-    private _transformMatrix = Matrix.Zero();
-    private _cachedPosition: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-    private _cachedDirection: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
-    private _cachedDefines: string;
-    private _currentRenderID: number;
-    private _boxBlurPostprocess: Nullable<PostProcess>;
-    private _kernelBlurXPostprocess: Nullable<PostProcess>;
-    private _kernelBlurYPostprocess: Nullable<PostProcess>;
-    private _blurPostProcesses: PostProcess[];
-    private _mapSize: number;
-    private _currentFaceIndex = 0;
-    private _currentFaceIndexCache = 0;
-    private _textureType: number;
-    private _defaultTextureMatrix = Matrix.Identity();
-    private _storedUniqueId: Nullable<number>;
+    protected _scene: Scene;
+    protected _lightDirection = Vector3.Zero();
+
+    protected _effect: Effect;
+
+    protected _viewMatrix = Matrix.Zero();
+    protected _projectionMatrix = Matrix.Zero();
+    protected _transformMatrix = Matrix.Zero();
+    protected _cachedPosition: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+    protected _cachedDirection: Vector3 = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+    protected _cachedDefines: string;
+    protected _currentRenderID: number;
+    protected _boxBlurPostprocess: Nullable<PostProcess>;
+    protected _kernelBlurXPostprocess: Nullable<PostProcess>;
+    protected _kernelBlurYPostprocess: Nullable<PostProcess>;
+    protected _blurPostProcesses: PostProcess[];
+    protected _mapSize: number;
+    protected _currentFaceIndex = 0;
+    protected _currentFaceIndexCache = 0;
+    protected _textureType: number;
+    protected _defaultTextureMatrix = Matrix.Identity();
+    protected _storedUniqueId: Nullable<number>;
 
 
     /** @hidden */
     /** @hidden */
     public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
     public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
@@ -807,13 +834,12 @@ export class ShadowGenerator implements IShadowGenerator {
         this._applyFilterValues();
         this._applyFilterValues();
     }
     }
 
 
-    private _initializeGenerator(): void {
+    protected _initializeGenerator(): void {
         this._light._markMeshesAsLightDirty();
         this._light._markMeshesAsLightDirty();
         this._initializeShadowMap();
         this._initializeShadowMap();
     }
     }
 
 
-    private _initializeShadowMap(): void {
-        // Render target
+    protected _createTargetRenderTexture(): void {
         let engine = this._scene.getEngine();
         let engine = this._scene.getEngine();
         if (engine.webGLVersion > 1) {
         if (engine.webGLVersion > 1) {
             this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube(), undefined, false, false);
             this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube(), undefined, false, false);
@@ -822,6 +848,15 @@ export class ShadowGenerator implements IShadowGenerator {
         else {
         else {
             this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
             this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
         }
         }
+    }
+
+    protected _initializeShadowMap(): void {
+        this._createTargetRenderTexture();
+
+        if (this._shadowMap === null) {
+            return;
+        }
+
         this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.anisotropicFilteringLevel = 1;
         this._shadowMap.anisotropicFilteringLevel = 1;
@@ -832,6 +867,11 @@ export class ShadowGenerator implements IShadowGenerator {
             this._shadowMap.uniqueId = this._storedUniqueId;
             this._shadowMap.uniqueId = this._storedUniqueId;
         }
         }
 
 
+        // Custom render function.
+        this._shadowMap.customRenderFunction = this._renderForShadowMap.bind(this);
+
+        let engine = this._scene.getEngine();
+
         // Record Face Index before render.
         // Record Face Index before render.
         this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
         this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
             this._currentFaceIndex = faceIndex;
             this._currentFaceIndex = faceIndex;
@@ -840,9 +880,6 @@ export class ShadowGenerator implements IShadowGenerator {
             }
             }
         });
         });
 
 
-        // Custom render function.
-        this._shadowMap.customRenderFunction = this._renderForShadowMap.bind(this);
-
         // Blur if required afer render.
         // Blur if required afer render.
         this._shadowMap.onAfterUnbindObservable.add(() => {
         this._shadowMap.onAfterUnbindObservable.add(() => {
             if (this._filter === ShadowGenerator.FILTER_PCF) {
             if (this._filter === ShadowGenerator.FILTER_PCF) {
@@ -873,6 +910,7 @@ export class ShadowGenerator implements IShadowGenerator {
             }
             }
         });
         });
 
 
+        // Recreate on resize.
         this._shadowMap.onResizeObservable.add((RTT) => {
         this._shadowMap.onResizeObservable.add((RTT) => {
             this._storedUniqueId = this._shadowMap!.uniqueId;
             this._storedUniqueId = this._shadowMap!.uniqueId;
             this._mapSize = RTT.getRenderSize();
             this._mapSize = RTT.getRenderSize();
@@ -881,7 +919,7 @@ export class ShadowGenerator implements IShadowGenerator {
         });
         });
     }
     }
 
 
-    private _initializeBlurRTTAndPostProcesses(): void {
+    protected _initializeBlurRTTAndPostProcesses(): void {
         var engine = this._scene.getEngine();
         var engine = this._scene.getEngine();
         var targetSize = this._mapSize / this.blurScale;
         var targetSize = this._mapSize / this.blurScale;
 
 
@@ -925,7 +963,7 @@ export class ShadowGenerator implements IShadowGenerator {
         }
         }
     }
     }
 
 
-    private _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void {
+    protected _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void {
         var index: number;
         var index: number;
         let engine = this._scene.getEngine();
         let engine = this._scene.getEngine();
 
 
@@ -953,7 +991,10 @@ export class ShadowGenerator implements IShadowGenerator {
         }
         }
     }
     }
 
 
-    private _renderSubMeshForShadowMap(subMesh: SubMesh): void {
+    protected _bindCustomEffectForRenderSubMeshForShadowMap(subMesh: SubMesh, effect: Effect): void {
+    }
+
+    protected _renderSubMeshForShadowMap(subMesh: SubMesh): void {
         var mesh = subMesh.getRenderingMesh();
         var mesh = subMesh.getRenderingMesh();
         var scene = this._scene;
         var scene = this._scene;
         var engine = scene.getEngine();
         var engine = scene.getEngine();
@@ -1023,6 +1064,8 @@ export class ShadowGenerator implements IShadowGenerator {
             // Morph targets
             // Morph targets
             MaterialHelper.BindMorphTargetParameters(mesh, this._effect);
             MaterialHelper.BindMorphTargetParameters(mesh, this._effect);
 
 
+            this._bindCustomEffectForRenderSubMeshForShadowMap(subMesh, this._effect);
+
             if (this.forceBackFacesOnly) {
             if (this.forceBackFacesOnly) {
                 engine.setState(true, 0, false, true);
                 engine.setState(true, 0, false, true);
             }
             }
@@ -1051,7 +1094,7 @@ export class ShadowGenerator implements IShadowGenerator {
         }
         }
     }
     }
 
 
-    private _applyFilterValues(): void {
+    protected _applyFilterValues(): void {
         if (!this._shadowMap) {
         if (!this._shadowMap) {
             return;
             return;
         }
         }
@@ -1136,6 +1179,9 @@ export class ShadowGenerator implements IShadowGenerator {
         });
         });
     }
     }
 
 
+    protected _isReadyCustomDefines(defines: any, subMesh: SubMesh, useInstances: boolean): void {
+    }
+
     /**
     /**
      * Determine wheter the shadow generator is ready or not (mainly all effects and related post processes needs to be ready).
      * Determine wheter the shadow generator is ready or not (mainly all effects and related post processes needs to be ready).
      * @param subMesh The submesh we want to render in the shadow map
      * @param subMesh The submesh we want to render in the shadow map
@@ -1244,6 +1290,8 @@ export class ShadowGenerator implements IShadowGenerator {
             }
             }
         }
         }
 
 
+        this._isReadyCustomDefines(defines, subMesh, useInstances);
+
         // Get correct effect
         // Get correct effect
         var join = defines.join("\n");
         var join = defines.join("\n");
         if (this._cachedDefines !== join) {
         if (this._cachedDefines !== join) {
@@ -1336,7 +1384,7 @@ export class ShadowGenerator implements IShadowGenerator {
             }
             }
             // else default to high.
             // else default to high.
         }
         }
-        if (this.usePercentageCloserFiltering) {
+        else if (this.usePercentageCloserFiltering) {
             defines["SHADOWPCF" + lightIndex] = true;
             defines["SHADOWPCF" + lightIndex] = true;
             if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
             if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
                 defines["SHADOWLOWQUALITY" + lightIndex] = true;
                 defines["SHADOWLOWQUALITY" + lightIndex] = true;
@@ -1368,19 +1416,19 @@ export class ShadowGenerator implements IShadowGenerator {
      * @param effect The effect we are binfing the information for
      * @param effect The effect we are binfing the information for
      */
      */
     public bindShadowLight(lightIndex: string, effect: Effect): void {
     public bindShadowLight(lightIndex: string, effect: Effect): void {
-        var light = this._light;
-        var scene = this._scene;
+        const light = this._light;
+        const scene = this._scene;
 
 
         if (!scene.shadowsEnabled || !light.shadowEnabled) {
         if (!scene.shadowsEnabled || !light.shadowEnabled) {
             return;
             return;
         }
         }
 
 
-        let camera = scene.activeCamera;
+        const camera = scene.activeCamera;
         if (!camera) {
         if (!camera) {
             return;
             return;
         }
         }
 
 
-        let shadowMap = this.getShadowMap();
+        const shadowMap = this.getShadowMap();
 
 
         if (!shadowMap) {
         if (!shadowMap) {
             return;
             return;
@@ -1479,7 +1527,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._shadowMap!.renderList = renderList;
         this._shadowMap!.renderList = renderList;
     }
     }
 
 
-    private _disposeBlurPostProcesses(): void {
+    protected _disposeBlurPostProcesses(): void {
         if (this._shadowMap2) {
         if (this._shadowMap2) {
             this._shadowMap2.dispose();
             this._shadowMap2.dispose();
             this._shadowMap2 = null;
             this._shadowMap2 = null;
@@ -1503,7 +1551,7 @@ export class ShadowGenerator implements IShadowGenerator {
         this._blurPostProcesses = [];
         this._blurPostProcesses = [];
     }
     }
 
 
-    private _disposeRTTandPostProcesses(): void {
+    protected _disposeRTTandPostProcesses(): void {
         if (this._shadowMap) {
         if (this._shadowMap) {
             this._shadowMap.dispose();
             this._shadowMap.dispose();
             this._shadowMap = null;
             this._shadowMap = null;
@@ -1542,30 +1590,29 @@ export class ShadowGenerator implements IShadowGenerator {
             return serializationObject;
             return serializationObject;
         }
         }
 
 
+        serializationObject.className = this.getClassName();
         serializationObject.lightId = this._light.id;
         serializationObject.lightId = this._light.id;
         serializationObject.mapSize = shadowMap.getRenderSize();
         serializationObject.mapSize = shadowMap.getRenderSize();
+        serializationObject.forceBackFacesOnly = this.forceBackFacesOnly;
+        serializationObject.darkness = this.getDarkness();
+        serializationObject.transparencyShadow = this._transparencyShadow;
+        serializationObject.frustumEdgeFalloff = this.frustumEdgeFalloff;
+        serializationObject.bias = this.bias;
+        serializationObject.normalBias = this.normalBias;
+        serializationObject.usePercentageCloserFiltering = this.usePercentageCloserFiltering;
+        serializationObject.useContactHardeningShadow = this.useContactHardeningShadow;
+        serializationObject.contactHardeningLightSizeUVRatio = this.contactHardeningLightSizeUVRatio;
+        serializationObject.filteringQuality = this.filteringQuality;
         serializationObject.useExponentialShadowMap = this.useExponentialShadowMap;
         serializationObject.useExponentialShadowMap = this.useExponentialShadowMap;
         serializationObject.useBlurExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.useBlurExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.useCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.useCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.useBlurCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.useBlurCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
         serializationObject.usePoissonSampling = this.usePoissonSampling;
         serializationObject.usePoissonSampling = this.usePoissonSampling;
-        serializationObject.forceBackFacesOnly = this.forceBackFacesOnly;
         serializationObject.depthScale = this.depthScale;
         serializationObject.depthScale = this.depthScale;
-        serializationObject.darkness = this.getDarkness();
         serializationObject.blurBoxOffset = this.blurBoxOffset;
         serializationObject.blurBoxOffset = this.blurBoxOffset;
         serializationObject.blurKernel = this.blurKernel;
         serializationObject.blurKernel = this.blurKernel;
         serializationObject.blurScale = this.blurScale;
         serializationObject.blurScale = this.blurScale;
         serializationObject.useKernelBlur = this.useKernelBlur;
         serializationObject.useKernelBlur = this.useKernelBlur;
-        serializationObject.transparencyShadow = this._transparencyShadow;
-        serializationObject.frustumEdgeFalloff = this.frustumEdgeFalloff;
-
-        serializationObject.bias = this.bias;
-        serializationObject.normalBias = this.normalBias;
-
-        serializationObject.usePercentageCloserFiltering = this.usePercentageCloserFiltering;
-        serializationObject.useContactHardeningShadow = this.useContactHardeningShadow;
-        serializationObject.filteringQuality = this.filteringQuality;
-        serializationObject.contactHardeningLightSizeUVRatio = this.contactHardeningLightSizeUVRatio;
 
 
         serializationObject.renderList = [];
         serializationObject.renderList = [];
         if (shadowMap.renderList) {
         if (shadowMap.renderList) {
@@ -1583,11 +1630,12 @@ export class ShadowGenerator implements IShadowGenerator {
      * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
      * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
      * @param parsedShadowGenerator The JSON object to parse
      * @param parsedShadowGenerator The JSON object to parse
      * @param scene The scene to create the shadow map for
      * @param scene The scene to create the shadow map for
+     * @param constr A function that builds a shadow generator or undefined to create an instance of the default shadow generator
      * @returns The parsed shadow generator
      * @returns The parsed shadow generator
      */
      */
-    public static Parse(parsedShadowGenerator: any, scene: Scene): ShadowGenerator {
+    public static Parse(parsedShadowGenerator: any, scene: Scene, constr?: (mapSize: number, light: IShadowLight) => ShadowGenerator): ShadowGenerator {
         var light = <IShadowLight>scene.getLightByID(parsedShadowGenerator.lightId);
         var light = <IShadowLight>scene.getLightByID(parsedShadowGenerator.lightId);
-        var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
+        var shadowGenerator = constr ? constr(parsedShadowGenerator.mapSize, light) : new ShadowGenerator(parsedShadowGenerator.mapSize, light);
         var shadowMap = shadowGenerator.getShadowMap();
         var shadowMap = shadowGenerator.getShadowMap();
 
 
         for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
         for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
@@ -1603,42 +1651,56 @@ export class ShadowGenerator implements IShadowGenerator {
             });
             });
         }
         }
 
 
-        if (parsedShadowGenerator.usePoissonSampling) {
-            shadowGenerator.usePoissonSampling = true;
+        shadowGenerator.forceBackFacesOnly = !!parsedShadowGenerator.forceBackFacesOnly;
+
+        if (parsedShadowGenerator.darkness !== undefined) {
+            shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
         }
         }
-        else if (parsedShadowGenerator.useExponentialShadowMap) {
-            shadowGenerator.useExponentialShadowMap = true;
+
+        if (parsedShadowGenerator.transparencyShadow) {
+            shadowGenerator.setTransparencyShadow(true);
         }
         }
-        else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
-            shadowGenerator.useBlurExponentialShadowMap = true;
+
+        if (parsedShadowGenerator.frustumEdgeFalloff !== undefined) {
+            shadowGenerator.frustumEdgeFalloff = parsedShadowGenerator.frustumEdgeFalloff;
         }
         }
-        else if (parsedShadowGenerator.useCloseExponentialShadowMap) {
-            shadowGenerator.useCloseExponentialShadowMap = true;
+
+        if (parsedShadowGenerator.bias !== undefined) {
+            shadowGenerator.bias = parsedShadowGenerator.bias;
         }
         }
-        else if (parsedShadowGenerator.useBlurCloseExponentialShadowMap) {
-            shadowGenerator.useBlurCloseExponentialShadowMap = true;
+
+        if (parsedShadowGenerator.normalBias !== undefined) {
+            shadowGenerator.normalBias = parsedShadowGenerator.normalBias;
         }
         }
-        else if (parsedShadowGenerator.usePercentageCloserFiltering) {
+
+        if (parsedShadowGenerator.usePercentageCloserFiltering) {
             shadowGenerator.usePercentageCloserFiltering = true;
             shadowGenerator.usePercentageCloserFiltering = true;
-        }
-        else if (parsedShadowGenerator.useContactHardeningShadow) {
+        } else if (parsedShadowGenerator.useContactHardeningShadow) {
             shadowGenerator.useContactHardeningShadow = true;
             shadowGenerator.useContactHardeningShadow = true;
+        } else if (parsedShadowGenerator.usePoissonSampling) {
+            shadowGenerator.usePoissonSampling = true;
+        } else if (parsedShadowGenerator.useExponentialShadowMap) {
+            shadowGenerator.useExponentialShadowMap = true;
+        } else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
+            shadowGenerator.useBlurExponentialShadowMap = true;
+        } else if (parsedShadowGenerator.useCloseExponentialShadowMap) {
+            shadowGenerator.useCloseExponentialShadowMap = true;
+        } else if (parsedShadowGenerator.useBlurCloseExponentialShadowMap) {
+            shadowGenerator.useBlurCloseExponentialShadowMap = true;
+        } else
+        // Backward compat
+        if (parsedShadowGenerator.useVarianceShadowMap) {
+            shadowGenerator.useExponentialShadowMap = true;
+        } else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
+            shadowGenerator.useBlurExponentialShadowMap = true;
         }
         }
 
 
-        if (parsedShadowGenerator.filteringQuality) {
-            shadowGenerator.filteringQuality = parsedShadowGenerator.filteringQuality;
-        }
-
-        if (parsedShadowGenerator.contactHardeningLightSizeUVRatio) {
+        if (parsedShadowGenerator.contactHardeningLightSizeUVRatio !== undefined) {
             shadowGenerator.contactHardeningLightSizeUVRatio = parsedShadowGenerator.contactHardeningLightSizeUVRatio;
             shadowGenerator.contactHardeningLightSizeUVRatio = parsedShadowGenerator.contactHardeningLightSizeUVRatio;
         }
         }
 
 
-        // Backward compat
-        else if (parsedShadowGenerator.useVarianceShadowMap) {
-            shadowGenerator.useExponentialShadowMap = true;
-        }
-        else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
-            shadowGenerator.useBlurExponentialShadowMap = true;
+        if (parsedShadowGenerator.filteringQuality !== undefined) {
+            shadowGenerator.filteringQuality = parsedShadowGenerator.filteringQuality;
         }
         }
 
 
         if (parsedShadowGenerator.depthScale) {
         if (parsedShadowGenerator.depthScale) {
@@ -1661,28 +1723,6 @@ export class ShadowGenerator implements IShadowGenerator {
             shadowGenerator.blurKernel = parsedShadowGenerator.blurKernel;
             shadowGenerator.blurKernel = parsedShadowGenerator.blurKernel;
         }
         }
 
 
-        if (parsedShadowGenerator.bias !== undefined) {
-            shadowGenerator.bias = parsedShadowGenerator.bias;
-        }
-
-        if (parsedShadowGenerator.normalBias !== undefined) {
-            shadowGenerator.normalBias = parsedShadowGenerator.normalBias;
-        }
-
-        if (parsedShadowGenerator.frustumEdgeFalloff !== undefined) {
-            shadowGenerator.frustumEdgeFalloff = parsedShadowGenerator.frustumEdgeFalloff;
-        }
-
-        if (parsedShadowGenerator.darkness) {
-            shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
-        }
-
-        if (parsedShadowGenerator.transparencyShadow) {
-            shadowGenerator.setTransparencyShadow(true);
-        }
-
-        shadowGenerator.forceBackFacesOnly = parsedShadowGenerator.forceBackFacesOnly;
-
         return shadowGenerator;
         return shadowGenerator;
     }
     }
 }
 }

+ 0 - 8
src/Lights/Shadows/shadowGeneratorSceneComponent.ts

@@ -127,11 +127,3 @@ ShadowGenerator._SceneComponentInitialization = (scene: Scene) => {
         scene._addComponent(component);
         scene._addComponent(component);
     }
     }
 };
 };
-
-CascadedShadowGenerator._SceneComponentInitialization = (scene: Scene) => {
-    let component = scene._getComponent(SceneComponentConstants.NAME_SHADOWGENERATOR);
-    if (!component) {
-        component = new ShadowGeneratorSceneComponent(scene);
-        scene._addComponent(component);
-    }
-};