Bläddra i källkod

removing subsurface dependency from prepass

Benjamin Guignabert 5 år sedan
förälder
incheckning
cfbd416f3d

+ 2 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -246,8 +246,8 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                     <CheckBoxLineComponent label="Scattering Enabled" target={material.subSurface} propertyName="isScatteringEnabled"
                         onValueChanged={() => this.forceUpdate()}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    { (material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer &&
-                        <SliderLineComponent label="Meters per unit" target={ material.getScene().prePassRenderer!.subSurfaceConfiguration } propertyName="metersPerUnit" minimum={0.01} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    { (material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration &&
+                        <SliderLineComponent label="Meters per unit" target={ material.getScene().subSurfaceConfiguration! } propertyName="metersPerUnit" minimum={0.01} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                     <CheckBoxLineComponent label="Refraction Enabled" target={material.subSurface} propertyName="isRefractionEnabled"
                         onValueChanged={() => this.forceUpdate()}

+ 1 - 1
package.json

@@ -113,4 +113,4 @@
         "xhr2": "^0.2.0",
         "xmlbuilder": "15.1.1"
     }
-}
+}

+ 7 - 2
src/Materials/PBR/pbrBaseMaterial.ts

@@ -2232,11 +2232,16 @@ export abstract class PBRBaseMaterial extends PushMaterial {
      */
     public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
         if (this.subSurface.isScatteringEnabled) {
-            prePassRenderer.subSurfaceConfiguration.enabled = true;
+            let subSurfaceConfiguration = this.getScene().enableSubSurfaceForPrePass();
+            if (subSurfaceConfiguration) {
+                subSurfaceConfiguration.enabled = true;
+            }
             prePassRenderer.materialsShouldRenderIrradiance = true;
+
+            return true;
         }
 
-        return true;
+        return false;
     }
 
     /**

+ 4 - 4
src/Materials/PBR/pbrSubSurfaceConfiguration.ts

@@ -80,22 +80,22 @@ export class PBRSubSurfaceConfiguration {
      * Useful for better scattering in the skins or foliages.
      */
     public get scatteringDiffusionProfile() : Nullable<Color3> {
-        if (!this._scene.prePassRenderer) {
+        if (!this._scene.subSurfaceConfiguration) {
             return null;
         }
 
-        return this._scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionProfileColors[this._scatteringDiffusionProfileIndex];
+        return this._scene.subSurfaceConfiguration.ssDiffusionProfileColors[this._scatteringDiffusionProfileIndex];
     }
 
     public set scatteringDiffusionProfile(c: Nullable<Color3>) {
-        if (!this._scene.enablePrePassRenderer()) {
+        if (!this._scene.enableSubSurfaceForPrePass()) {
             // Not supported
             return;
         }
 
         // addDiffusionProfile automatically checks for doubles
         if (c) {
-            this._scatteringDiffusionProfileIndex = this._scene.prePassRenderer!.subSurfaceConfiguration.addDiffusionProfile(c);
+            this._scatteringDiffusionProfileIndex = this._scene.subSurfaceConfiguration!.addDiffusionProfile(c);
         }
     }
 

+ 6 - 6
src/PostProcesses/subSurfaceScatteringPostProcess.ts

@@ -28,12 +28,12 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
         this.updateEffect();
 
         this.onApplyObservable.add((effect: Effect) => {
-            if (!scene.prePassRenderer) {
-                Logger.Error("PrePass needs to be enabled for subsurface scattering.");
+            if (!scene.prePassRenderer || !scene.subSurfaceConfiguration) {
+                Logger.Error("PrePass and subsurface configuration needs to be enabled for subsurface scattering.");
                 return;
             }
             var texelSize = this.texelSize;
-            effect.setFloat("metersPerUnit", scene.prePassRenderer.subSurfaceConfiguration.metersPerUnit);
+            effect.setFloat("metersPerUnit", scene.subSurfaceConfiguration.metersPerUnit);
             effect.setFloat2("texelSize", texelSize.x, texelSize.y);
             effect.setTexture("irradianceSampler", scene.prePassRenderer.prePassRT.textures[1]);
             effect.setTexture("depthSampler", scene.prePassRenderer.prePassRT.textures[2]);
@@ -41,9 +41,9 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
             effect.setFloat2("viewportSize",
                 Math.tan(scene.activeCamera!.fov / 2) * scene.getEngine().getAspectRatio(scene.activeCamera!, true),
                 Math.tan(scene.activeCamera!.fov / 2));
-            effect.setArray3("diffusionS", scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionS);
-            effect.setArray("diffusionD", scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionD);
-            effect.setArray("filterRadii", scene.prePassRenderer.subSurfaceConfiguration.ssFilterRadii);
+            effect.setArray3("diffusionS", scene.subSurfaceConfiguration.ssDiffusionS);
+            effect.setArray("diffusionD", scene.subSurfaceConfiguration.ssDiffusionD);
+            effect.setArray("filterRadii", scene.subSurfaceConfiguration.ssFilterRadii);
         });
 
     }

+ 1 - 0
src/Rendering/index.ts

@@ -6,6 +6,7 @@ export * from "./geometryBufferRenderer";
 export * from "./geometryBufferRendererSceneComponent";
 export * from "./prePassRenderer";
 export * from "./prePassRendererSceneComponent";
+export * from "./subSurfaceSceneComponent";
 export * from "./outlineRenderer";
 export * from "./renderingGroup";
 export * from "./renderingManager";

+ 5 - 0
src/Rendering/prePassEffectConfiguration.ts

@@ -5,6 +5,11 @@ import { PostProcess } from "../PostProcesses/postProcess";
  */
 export interface PrePassEffectConfiguration {
     /**
+     * Name of the effect
+     */
+    name: string;
+
+    /**
      * Post process to attach for this effect
      */
     postProcess: PostProcess;

+ 36 - 14
src/Rendering/prePassRenderer.ts

@@ -7,7 +7,7 @@ import { PostProcess } from "../PostProcesses/postProcess";
 import { Effect } from "../Materials/effect";
 import { _DevTools } from '../Misc/devTools';
 import { Color4 } from "../Maths/math.color";
-import { SubSurfaceConfiguration } from "./subSurfaceConfiguration";
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
 
 /**
  * Renders a pre pass of the scene
@@ -56,7 +56,7 @@ export class PrePassRenderer {
     /**
      * Configuration for sub surface scattering post process
      */
-    public subSurfaceConfiguration: SubSurfaceConfiguration;
+    private _effectConfigurations: PrePassEffectConfiguration[] = [];
 
     /**
      * Should materials render their geometry on the MRT
@@ -101,8 +101,6 @@ export class PrePassRenderer {
         this._engine = scene.getEngine();
 
         PrePassRenderer._SceneComponentInitialization(this._scene);
-
-        this.subSurfaceConfiguration = new SubSurfaceConfiguration(this._scene);
     }
 
     private _initializeAttachments() {
@@ -230,15 +228,31 @@ export class PrePassRenderer {
         }
     }
 
+    /**
+     * Adds an effect configuration
+     */
+    public addEffectConfiguration(cfg: PrePassEffectConfiguration) {
+        // Do not add twice
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].name === cfg.name) {
+                return;
+            }
+        }
+
+        this._effectConfigurations.push(cfg);
+    }
+
     private _enable() {
         this._resetPostProcessChain();
 
-        if (this.subSurfaceConfiguration.enabled) {
-            if (!this.subSurfaceConfiguration.postProcess) {
-                this.subSurfaceConfiguration.createPostProcess();
-            }
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].enabled) {
+                if (!this._effectConfigurations[i].postProcess) {
+                    this._effectConfigurations[i].createPostProcess();
+                }
 
-            this._postProcesses.push(this.subSurfaceConfiguration.postProcess);
+                this._postProcesses.push(this._effectConfigurations[i].postProcess);
+            }
         }
 
         if (!this.imageProcessingPostProcess) {
@@ -252,7 +266,11 @@ export class PrePassRenderer {
 
     private _disable() {
         this._setState(false);
-        this.subSurfaceConfiguration.enabled = false;
+
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            this._effectConfigurations[i].enabled = false;
+        }
+
         this.materialsShouldRenderGeometry = false;
         this.materialsShouldRenderIrradiance = false;
     }
@@ -263,8 +281,10 @@ export class PrePassRenderer {
             this.imageProcessingPostProcess.restoreDefaultInputTexture();
         }
 
-        if (this.subSurfaceConfiguration.postProcess) {
-            this.subSurfaceConfiguration.postProcess.restoreDefaultInputTexture();
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].postProcess) {
+                this._effectConfigurations[i].postProcess.restoreDefaultInputTexture();
+            }
         }
     }
 
@@ -283,7 +303,6 @@ export class PrePassRenderer {
         this._disable();
         let enablePrePass = false;
 
-        // Subsurface scattering
         for (let i = 0; i < this._scene.materials.length; i++) {
             if (this._scene.materials[i].setPrePassRenderer(this)) {
                 enablePrePass = true;
@@ -312,8 +331,11 @@ export class PrePassRenderer {
      * Disposes the prepass renderer.
      */
     public dispose() {
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            this._effectConfigurations[i].dispose();
+        }
+
         this.imageProcessingPostProcess.dispose();
-        this.subSurfaceConfiguration.dispose();
         this.prePassRT.dispose();
     }
 

+ 2 - 57
src/Rendering/prePassRendererSceneComponent.ts

@@ -1,25 +1,9 @@
 import { Nullable } from "../types";
 import { Scene } from "../scene";
-import { ISceneSerializableComponent, SceneComponentConstants } from "../sceneComponent";
+import { ISceneComponent, SceneComponentConstants } from "../sceneComponent";
 import { PrePassRenderer } from "./prePassRenderer";
-import { AbstractScene } from "../abstractScene";
-import { Color3 } from "../Maths/math.color";
 import { Logger } from "../Misc/logger";
 
-// Adds the parser to the scene parsers.
-AbstractScene.AddParser(SceneComponentConstants.NAME_PREPASSRENDERER, (parsedData: any, scene: Scene) => {
-    // Diffusion profiles
-    if (parsedData.ssDiffusionProfileColors !== undefined && parsedData.ssDiffusionProfileColors !== null) {
-        scene.enablePrePassRenderer();
-        if (scene.prePassRenderer) {
-            for (var index = 0, cache = parsedData.ssDiffusionProfileColors.length; index < cache; index++) {
-                var color = parsedData.ssDiffusionProfileColors[index];
-                scene.prePassRenderer.subSurfaceConfiguration.addDiffusionProfile(new Color3(color.r, color.g, color.b));
-            }
-        }
-    }
-});
-
 declare module "../abstractScene" {
     export interface AbstractScene {
         /** @hidden (Backing field) */
@@ -86,7 +70,7 @@ Scene.prototype.disablePrePassRenderer = function(): void {
  * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful
  * in several rendering techniques.
  */
-export class PrePassRendererSceneComponent implements ISceneSerializableComponent {
+export class PrePassRendererSceneComponent implements ISceneComponent {
     /**
      * The component name helpful to identify the component in the list of scene components.
      */
@@ -133,45 +117,6 @@ export class PrePassRendererSceneComponent implements ISceneSerializableComponen
     }
 
     /**
-     * Serializes the component data to the specified json object
-     * @param serializationObject The object to serialize to
-     */
-    public serialize(serializationObject: any): void {
-        if (!this.scene.prePassRenderer) {
-            return;
-        }
-
-        const ssDiffusionProfileColors = this.scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionProfileColors;
-        serializationObject.ssDiffusionProfileColors = [];
-
-        for (let i = 0; i < ssDiffusionProfileColors.length; i++) {
-            serializationObject.ssDiffusionProfileColors.push({ r: ssDiffusionProfileColors[i].r,
-                                                                g: ssDiffusionProfileColors[i].g,
-                                                                b: ssDiffusionProfileColors[i].b });
-        }
-    }
-
-    /**
-     * Adds all the elements from the container to the scene
-     * @param container the container holding the elements
-     */
-    public addFromContainer(container: AbstractScene): void {
-        // Nothing to do
-    }
-
-    /**
-     * Removes all the elements in the container from the scene
-     * @param container contains the elements to remove
-     * @param dispose if the removed element should be disposed (default: false)
-     */
-    public removeFromContainer(container: AbstractScene, dispose?: boolean): void {
-        // Make sure nothing will be serialized
-        if (this.scene.prePassRenderer) {
-            this.scene.prePassRenderer.subSurfaceConfiguration.clearAllDiffusionProfiles();
-        }
-    }
-
-    /**
      * Rebuilds the elements related to this component in case of
      * context lost for instance.
      */

+ 15 - 0
src/Rendering/subSurfaceConfiguration.ts

@@ -2,12 +2,20 @@ import { Logger } from "../Misc/logger";
 import { Scene } from "../scene";
 import { Color3 } from "../Maths/math.color";
 import { SubSurfaceScatteringPostProcess } from "../PostProcesses/subSurfaceScatteringPostProcess";
+import { SceneComponentConstants } from "../sceneComponent";
 import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+
 /**
  * Contains all parameters needed for the prepass to perform
  * screen space subsurface scattering
  */
 export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
+    /** @hidden */
+    public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
+        throw _DevTools.WarnImport("PrePassRendererSceneComponent");
+    }
+
     private _ssDiffusionS: number[] = [];
     private _ssFilterRadii: number[] = [];
     private _ssDiffusionD: number[] = [];
@@ -44,6 +52,11 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
     public enabled = false;
 
     /**
+     * Name of the configuration
+     */
+    public name = SceneComponentConstants.NAME_SUBSURFACE;
+
+    /**
      * Diffusion profile colors for subsurface scattering
      * You can add one diffusion color using `addDiffusionProfile` on `scene.prePassRenderer`
      * See ...
@@ -67,6 +80,8 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
         // Adding default diffusion profile
         this.addDiffusionProfile(new Color3(1, 1, 1));
         this._scene = scene;
+
+        SubSurfaceConfiguration._SceneComponentInitialization(this._scene);
     }
 
     /**

+ 181 - 0
src/Rendering/subSurfaceSceneComponent.ts

@@ -0,0 +1,181 @@
+import { Nullable } from "../types";
+import { Scene } from "../scene";
+import { ISceneSerializableComponent, SceneComponentConstants } from "../sceneComponent";
+import { SubSurfaceConfiguration } from "./subSurfaceConfiguration";
+import { AbstractScene } from "../abstractScene";
+import { Color3 } from "../Maths/math.color";
+
+// Adds the parser to the scene parsers.
+AbstractScene.AddParser(SceneComponentConstants.NAME_SUBSURFACE, (parsedData: any, scene: Scene) => {
+    // Diffusion profiles
+    if (parsedData.ssDiffusionProfileColors !== undefined && parsedData.ssDiffusionProfileColors !== null) {
+        scene.enableSubSurfaceForPrePass();
+        if (scene.subSurfaceConfiguration) {
+            for (var index = 0, cache = parsedData.ssDiffusionProfileColors.length; index < cache; index++) {
+                var color = parsedData.ssDiffusionProfileColors[index];
+                scene.subSurfaceConfiguration.addDiffusionProfile(new Color3(color.r, color.g, color.b));
+            }
+        }
+    }
+});
+
+declare module "../abstractScene" {
+    export interface AbstractScene {
+        /** @hidden (Backing field) */
+        _subSurfaceConfiguration: Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Gets or Sets the current prepass renderer associated to the scene.
+         */
+        subSurfaceConfiguration: Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Enables the subsurface effect for prepass
+         * @returns the SubSurfaceConfiguration
+         */
+        enableSubSurfaceForPrePass(): Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Disables the subsurface effect for prepass
+         */
+        disableSubSurfaceForPrePass(): void;
+    }
+}
+
+Object.defineProperty(Scene.prototype, "subSurfaceConfiguration", {
+    get: function(this: Scene) {
+        return this._subSurfaceConfiguration;
+    },
+    set: function(this: Scene, value: Nullable<SubSurfaceConfiguration>) {
+        if (value) {
+            if (this.enablePrePassRenderer()) {
+                    this._subSurfaceConfiguration = value;
+            }
+        }
+    },
+    enumerable: true,
+    configurable: true
+});
+
+Scene.prototype.enableSubSurfaceForPrePass = function(): Nullable<SubSurfaceConfiguration> {
+    if (this._subSurfaceConfiguration) {
+        return this._subSurfaceConfiguration;
+    }
+
+    const prePassRenderer = this.enablePrePassRenderer();
+    if (prePassRenderer) {
+        this._subSurfaceConfiguration = new SubSurfaceConfiguration(this);
+        prePassRenderer.addEffectConfiguration(this._subSurfaceConfiguration);
+        return this._subSurfaceConfiguration;
+    }
+
+    return null;
+
+};
+
+Scene.prototype.disableSubSurfaceForPrePass = function(): void {
+    if (!this._subSurfaceConfiguration) {
+        return;
+    }
+
+    this._subSurfaceConfiguration.dispose();
+    this._subSurfaceConfiguration = null;
+};
+
+/**
+ * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful
+ * in several rendering techniques.
+ */
+export class SubSurfaceSceneComponent implements ISceneSerializableComponent {
+    /**
+     * The component name helpful to identify the component in the list of scene components.
+     */
+    public readonly name = SceneComponentConstants.NAME_PREPASSRENDERER;
+
+    /**
+     * The scene the component belongs to.
+     */
+    public scene: Scene;
+
+    /**
+     * Creates a new instance of the component for the given scene
+     * @param scene Defines the scene to register the component in
+     */
+    constructor(scene: Scene) {
+        this.scene = scene;
+    }
+
+    /**
+     * Registers the component in a given scene
+     */
+    public register(): void {
+    }
+
+    /**
+     * Serializes the component data to the specified json object
+     * @param serializationObject The object to serialize to
+     */
+    public serialize(serializationObject: any): void {
+        if (!this.scene.subSurfaceConfiguration) {
+            return;
+        }
+
+        const ssDiffusionProfileColors = this.scene.subSurfaceConfiguration.ssDiffusionProfileColors;
+        serializationObject.ssDiffusionProfileColors = [];
+
+        for (let i = 0; i < ssDiffusionProfileColors.length; i++) {
+            serializationObject.ssDiffusionProfileColors.push({ r: ssDiffusionProfileColors[i].r,
+                                                                g: ssDiffusionProfileColors[i].g,
+                                                                b: ssDiffusionProfileColors[i].b });
+        }
+    }
+
+    /**
+     * Adds all the elements from the container to the scene
+     * @param container the container holding the elements
+     */
+    public addFromContainer(container: AbstractScene): void {
+        // Nothing to do
+    }
+
+    /**
+     * Removes all the elements in the container from the scene
+     * @param container contains the elements to remove
+     * @param dispose if the removed element should be disposed (default: false)
+     */
+    public removeFromContainer(container: AbstractScene, dispose?: boolean): void {
+        // Make sure nothing will be serialized
+        if (!this.scene.prePassRenderer) {
+            return;
+        }
+
+        if (this.scene.subSurfaceConfiguration) {
+            this.scene.subSurfaceConfiguration.clearAllDiffusionProfiles();
+        }
+    }
+
+    /**
+     * Rebuilds the elements related to this component in case of
+     * context lost for instance.
+     */
+    public rebuild(): void {
+        // Nothing to do for this component
+    }
+
+    /**
+     * Disposes the component and the associated ressources
+     */
+    public dispose(): void {
+        // Nothing to do for this component
+    }
+
+}
+
+SubSurfaceConfiguration._SceneComponentInitialization = (scene: Scene) => {
+    // Register the G Buffer component to the scene.
+    let component = scene._getComponent(SceneComponentConstants.NAME_SUBSURFACE) as SubSurfaceSceneComponent;
+    if (!component) {
+        component = new SubSurfaceSceneComponent(scene);
+        scene._addComponent(component);
+    }
+};

+ 1 - 0
src/sceneComponent.ts

@@ -28,6 +28,7 @@ export class SceneComponentConstants {
     public static readonly NAME_DEPTHRENDERER = "DepthRenderer";
     public static readonly NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager";
     public static readonly NAME_SPRITE = "Sprite";
+    public static readonly NAME_SUBSURFACE = "SubSurface";
     public static readonly NAME_OUTLINERENDERER = "Outline";
     public static readonly NAME_PROCEDURALTEXTURE = "ProceduralTexture";
     public static readonly NAME_SHADOWGENERATOR = "ShadowGenerator";