浏览代码

Merge pull request #8909 from CraigFeldspar/prepass-velocity

Make motion blur + screen space reflections use prepass
David Catuhe 4 年之前
父节点
当前提交
4b5a595de3
共有 35 个文件被更改,包括 602 次插入152 次删除
  1. 1 1
      dist/preview release/what's new.md
  2. 12 0
      src/Cameras/camera.ts
  3. 5 1
      src/Engines/constants.ts
  4. 21 1
      src/Materials/PBR/pbrBaseMaterial.ts
  5. 1 0
      src/Materials/PBR/pbrSubSurfaceConfiguration.ts
  6. 17 0
      src/Materials/material.ts
  7. 11 0
      src/Materials/materialDefines.ts
  8. 71 23
      src/Materials/materialHelper.ts
  9. 70 0
      src/Materials/prePassConfiguration.ts
  10. 20 0
      src/Materials/standardMaterial.ts
  11. 4 21
      src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts
  12. 48 12
      src/PostProcesses/motionBlurPostProcess.ts
  13. 23 0
      src/PostProcesses/postProcess.ts
  14. 47 17
      src/PostProcesses/screenSpaceReflectionPostProcess.ts
  15. 26 0
      src/Rendering/motionBlurConfiguration.ts
  16. 1 1
      src/Rendering/prePassEffectConfiguration.ts
  17. 36 35
      src/Rendering/prePassRenderer.ts
  18. 28 0
      src/Rendering/screenSpaceReflectionsConfiguration.ts
  19. 0 15
      src/Rendering/ssao2Configuration.ts
  20. 4 1
      src/Shaders/ShadersInclude/bonesDeclaration.fx
  21. 3 1
      src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx
  22. 1 5
      src/Shaders/ShadersInclude/pbrFragmentExtraDeclaration.fx
  23. 9 0
      src/Shaders/ShadersInclude/prePassDeclaration.fx
  24. 37 0
      src/Shaders/ShadersInclude/prePassVertex.fx
  25. 11 0
      src/Shaders/ShadersInclude/prePassVertexDeclaration.fx
  26. 6 0
      src/Shaders/ShadersInclude/subSurfaceScatteringFunctions.fx
  27. 21 4
      src/Shaders/default.fragment.fx
  28. 10 7
      src/Shaders/default.vertex.fx
  29. 23 0
      src/Shaders/pbr.fragment.fx
  30. 10 7
      src/Shaders/pbr.vertex.fx
  31. 4 0
      src/Shaders/screenSpaceReflection.fragment.fx
  32. 二进制
      tests/validation/ReferenceImages/geometrybufferrenderer.png
  33. 二进制
      tests/validation/ReferenceImages/motionBlur.png
  34. 二进制
      tests/validation/ReferenceImages/ssr.png
  35. 21 0
      tests/validation/config.json

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

@@ -243,7 +243,7 @@
 
 ### Post Processes
 
-- SSAO 2 is now using the brand new `PrePassRenderer` to avoid rendering the scene twice ([CraigFeldpsar](https://github.com/craigfeldspar)
+- SSAO 2, motion blur and screen space reflections are now using the brand new `PrePassRenderer` to avoid rendering the scene twice ([CraigFeldpsar](https://github.com/craigfeldspar)
 - Added Screen Space Curvature post process: [Doc](https://doc.babylonjs.com/how_to/how_to_use_postprocesses#screen-space-curvature) ([Popov72](https://github.com/Popov72) and [Sebavan](https://github.com/sebavan/))
 
 ## Bugs

+ 12 - 0
src/Cameras/camera.ts

@@ -625,6 +625,12 @@ export class Camera extends Node {
             this._postProcesses.splice(insertAt, 0, postProcess);
         }
         this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
+
+        // Update prePass
+        if (this._scene.prePassRenderer) {
+            this._scene.prePassRenderer.markAsDirty();
+        }
+
         return this._postProcesses.indexOf(postProcess);
     }
 
@@ -638,6 +644,12 @@ export class Camera extends Node {
         if (idx !== -1) {
             this._postProcesses[idx] = null;
         }
+
+        // Update prePass
+        if (this._scene.prePassRenderer) {
+            this._scene.prePassRenderer.markAsDirty();
+        }
+
         this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
     }
 

+ 5 - 1
src/Engines/constants.ts

@@ -282,9 +282,13 @@ export class Constants {
      */
     public static readonly MATERIAL_MiscDirtyFlag = 16;
     /**
+     * The dirty prepass flag value
+     */
+    public static readonly MATERIAL_PrePassDirtyFlag = 32;
+    /**
      * The all dirty flag value
      */
-    public static readonly MATERIAL_AllDirtyFlag = 31;
+    public static readonly MATERIAL_AllDirtyFlag = 63;
 
     /**
      * Returns the triangle fill mode

+ 21 - 1
src/Materials/PBR/pbrBaseMaterial.ts

@@ -16,6 +16,7 @@ import { IMaterialAnisotropicDefines, PBRAnisotropicConfiguration } from "./pbrA
 import { IMaterialBRDFDefines, PBRBRDFConfiguration } from "./pbrBRDFConfiguration";
 import { IMaterialSheenDefines, PBRSheenConfiguration } from "./pbrSheenConfiguration";
 import { IMaterialSubSurfaceDefines, PBRSubSurfaceConfiguration } from "./pbrSubSurfaceConfiguration";
+import { PrePassConfiguration } from "../prePassConfiguration";
 import { Color3, TmpColors } from '../../Maths/math.color';
 import { Scalar } from "../../Maths/math.scalar";
 
@@ -170,11 +171,18 @@ export class PBRMaterialDefines extends MaterialDefines
     public PREPASS_ALBEDO_INDEX = -1;
     public PREPASS_DEPTHNORMAL = false;
     public PREPASS_DEPTHNORMAL_INDEX = -1;
+    public PREPASS_POSITION = false;
+    public PREPASS_POSITION_INDEX = -1;
+    public PREPASS_VELOCITY = false;
+    public PREPASS_VELOCITY_INDEX = -1;
+    public PREPASS_REFLECTIVITY = false;
+    public PREPASS_REFLECTIVITY_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
+    public BONES_VELOCITY_ENABLED = false;
 
     public NONUNIFORMSCALING = false;
 
@@ -818,6 +826,11 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     public readonly subSurface: PBRSubSurfaceConfiguration;
 
     /**
+     * Defines additionnal PrePass parameters for the material.
+     */
+    public readonly prePassConfiguration: PrePassConfiguration;
+
+    /**
      * Defines the detail map parameters for the material.
      */
     public readonly detailMap = new DetailMapConfiguration(this._markAllSubMeshesAsTexturesDirty.bind(this));
@@ -850,6 +863,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
         this._environmentBRDFTexture = BRDFTextureTools.GetEnvironmentBRDFTexture(scene);
         this.subSurface = new PBRSubSurfaceConfiguration(this._markAllSubMeshesAsTexturesDirty.bind(this), this._markScenePrePassDirty.bind(this), scene);
+        this.prePassConfiguration = new PrePassConfiguration();
     }
 
     /**
@@ -1282,6 +1296,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         PBRSheenConfiguration.AddUniforms(uniforms);
         PBRSheenConfiguration.AddSamplers(samplers);
 
+        PrePassConfiguration.AddUniforms(uniforms);
+        PrePassConfiguration.AddSamplers(uniforms);
+
         if (ImageProcessingConfiguration) {
             ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
             ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
@@ -1748,6 +1765,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             this.bindOnlyWorldMatrix(world);
         }
 
+        // PrePass
+        this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen);
+
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
             world.toNormalMatrix(this._normalMatrix);
@@ -1757,7 +1777,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
         // Bones
-        MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
+        MaterialHelper.BindBonesParameters(mesh, this._activeEffect, this.prePassConfiguration);
 
         let reflectionTexture: Nullable<BaseTexture> = null;
         let ubo = this._uniformBuffer;

+ 1 - 0
src/Materials/PBR/pbrSubSurfaceConfiguration.ts

@@ -253,6 +253,7 @@ export class PBRSubSurfaceConfiguration {
     }
     /** @hidden */
     public _markScenePrePassDirty(): void {
+        this._internalMarkAllSubMeshesAsTexturesDirty();
         this._internalMarkScenePrePassDirty();
     }
 

+ 17 - 0
src/Materials/material.ts

@@ -130,6 +130,11 @@ export class Material implements IAnimatable {
     public static readonly MiscDirtyFlag = Constants.MATERIAL_MiscDirtyFlag;
 
     /**
+     * The dirty prepass flag value
+     */
+    public static readonly PrePassDirtyFlag = Constants.MATERIAL_PrePassDirtyFlag;
+
+    /**
      * The all dirty flag value
      */
     public static readonly AllDirtyFlag = Constants.MATERIAL_AllDirtyFlag;
@@ -1156,6 +1161,7 @@ export class Material implements IAnimatable {
     private static readonly _TextureDirtyCallBack = (defines: MaterialDefines) => defines.markAsTexturesDirty();
     private static readonly _FresnelDirtyCallBack = (defines: MaterialDefines) => defines.markAsFresnelDirty();
     private static readonly _MiscDirtyCallBack = (defines: MaterialDefines) => defines.markAsMiscDirty();
+    private static readonly _PrePassDirtyCallBack = (defines: MaterialDefines) => defines.markAsPrePassDirty();
     private static readonly _LightsDirtyCallBack = (defines: MaterialDefines) => defines.markAsLightDirty();
     private static readonly _AttributeDirtyCallBack = (defines: MaterialDefines) => defines.markAsAttributesDirty();
 
@@ -1207,6 +1213,10 @@ export class Material implements IAnimatable {
             Material._DirtyCallbackArray.push(Material._MiscDirtyCallBack);
         }
 
+        if (flag & Material.PrePassDirtyFlag) {
+            Material._DirtyCallbackArray.push(Material._PrePassDirtyCallBack);
+        }
+
         if (Material._DirtyCallbackArray.length) {
             this._markAllSubMeshesAsDirty(Material._RunDirtyCallBacks);
         }
@@ -1313,6 +1323,13 @@ export class Material implements IAnimatable {
     }
 
     /**
+     * Indicates that prepass needs to be re-calculated for all submeshes
+     */
+    protected _markAllSubMeshesAsPrePassDirty() {
+        this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
+    }
+
+    /**
      * Indicates that textures and misc need to be re-calculated for all submeshes
      */
     protected _markAllSubMeshesAsTexturesAndMiscDirty() {

+ 11 - 0
src/Materials/materialDefines.ts

@@ -21,6 +21,8 @@ export class MaterialDefines {
     /** @hidden */
     public _areMiscDirty = true;
     /** @hidden */
+    public _arePrePassDirty = true;
+    /** @hidden */
     public _areImageProcessingDirty = true;
 
     /** @hidden */
@@ -53,6 +55,7 @@ export class MaterialDefines {
         this._areLightsDirty = false;
         this._areLightsDisposed = false;
         this._areMiscDirty = false;
+        this._arePrePassDirty = false;
         this._areImageProcessingDirty = false;
     }
 
@@ -127,6 +130,14 @@ export class MaterialDefines {
     }
 
     /**
+     * Marks the prepass state as changed
+     */
+    public markAsPrePassDirty() {
+        this._arePrePassDirty = true;
+        this._isDirty = true;
+    }
+
+    /**
      * Rebuilds the material defines
      */
     public rebuild() {

+ 71 - 23
src/Materials/materialHelper.ts

@@ -9,6 +9,7 @@ import { Mesh } from "../Meshes/mesh";
 import { VertexBuffer } from "../Meshes/buffer";
 import { Light } from "../Lights/light";
 import { Constants } from "../Engines/constants";
+import { PrePassConfiguration } from "../Materials/prePassConfiguration";
 
 import { UniformBuffer } from "./uniformBuffer";
 import { Effect, IEffectCreationOptions } from "./effect";
@@ -203,6 +204,12 @@ export class MaterialHelper {
             } else {
                 defines["BonesPerMesh"] = (mesh.skeleton.bones.length + 1);
                 defines["BONETEXTURE"] = materialSupportsBoneTexture ? false : undefined;
+
+                const prePassRenderer = mesh.getScene().prePassRenderer;
+                if (prePassRenderer && prePassRenderer.enabled) {
+                    const nonExcluded = prePassRenderer.excludedSkinnedMesh.indexOf(mesh) === -1;
+                    defines["BONES_VELOCITY_ENABLED"] = nonExcluded;
+                }
             }
         } else {
             defines["NUM_BONE_INFLUENCERS"] = 0;
@@ -303,37 +310,63 @@ export class MaterialHelper {
      * @param canRenderToMRT Indicates if this material renders to several textures in the prepass
      */
     public static PrepareDefinesForPrePass(scene: Scene, defines: any, canRenderToMRT: boolean) {
-        var previousPrePass = defines.PREPASS;
+        const previousPrePass = defines.PREPASS;
+
+        if (!defines._arePrePassDirty) {
+            return;
+        }
+
+        const texturesList = [
+        {
+            type: Constants.PREPASS_POSITION_TEXTURE_TYPE,
+            define: "PREPASS_POSITION",
+            index: "PREPASS_POSITION_INDEX",
+        },
+        {
+            type: Constants.PREPASS_VELOCITY_TEXTURE_TYPE,
+            define: "PREPASS_VELOCITY",
+            index: "PREPASS_VELOCITY_INDEX",
+        },
+        {
+            type: Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE,
+            define: "PREPASS_REFLECTIVITY",
+            index: "PREPASS_REFLECTIVITY_INDEX",
+        },
+        {
+            type: Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE,
+            define: "PREPASS_IRRADIANCE",
+            index: "PREPASS_IRRADIANCE_INDEX",
+        },
+        {
+            type: Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
+            define: "PREPASS_ALBEDO",
+            index: "PREPASS_ALBEDO_INDEX",
+        },
+        {
+            type: Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+            define: "PREPASS_DEPTHNORMAL",
+            index: "PREPASS_DEPTHNORMAL_INDEX",
+        }];
 
         if (scene.prePassRenderer && scene.prePassRenderer.enabled && canRenderToMRT) {
             defines.PREPASS = true;
             defines.SCENE_MRT_COUNT = scene.prePassRenderer.mrtCount;
 
-            const irradianceIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE);
-            if (irradianceIndex !== -1) {
-                defines.PREPASS_IRRADIANCE = true;
-                defines.PREPASS_IRRADIANCE_INDEX = irradianceIndex;
-            } else {
-                defines.PREPASS_IRRADIANCE = false;
-            }
-
-            const albedoIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_ALBEDO_TEXTURE_TYPE);
-            if (albedoIndex !== -1) {
-                defines.PREPASS_ALBEDO = true;
-                defines.PREPASS_ALBEDO_INDEX = albedoIndex;
-            } else {
-                defines.PREPASS_ALBEDO = false;
+            for (let i = 0; i < texturesList.length; i++) {
+                const index = scene.prePassRenderer.getIndex(texturesList[i].type);
+                if (index !== -1) {
+                    defines[texturesList[i].define] = true;
+                    defines[texturesList[i].index] = index;
+                } else {
+                    defines[texturesList[i].define] = false;
+                }
             }
 
-            const depthNormalIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE);
-            if (depthNormalIndex !== -1) {
-                defines.PREPASS_DEPTHNORMAL = true;
-                defines.PREPASS_DEPTHNORMAL_INDEX = depthNormalIndex;
-            } else {
-                defines.PREPASS_DEPTHNORMAL = false;
-            }
         } else {
             defines.PREPASS = false;
+            for (let i = 0; i < texturesList.length; i++) {
+                defines[texturesList[i].define] = false;
+            }
         }
 
         if (defines.PREPASS != previousPrePass) {
@@ -802,8 +835,9 @@ export class MaterialHelper {
      * Binds the bones information from the mesh to the effect.
      * @param mesh The mesh we are binding the information to render
      * @param effect The effect we are binding the data to
+     * @param prePassConfiguration Configuration for the prepass, in case prepass is activated
      */
-    public static BindBonesParameters(mesh?: AbstractMesh, effect?: Effect): void {
+    public static BindBonesParameters(mesh?: AbstractMesh, effect?: Effect, prePassConfiguration?: PrePassConfiguration): void {
         if (!effect || !mesh) {
             return;
         }
@@ -823,11 +857,25 @@ export class MaterialHelper {
 
                 if (matrices) {
                     effect.setMatrices("mBones", matrices);
+                    if (prePassConfiguration && mesh.getScene().prePassRenderer && mesh.getScene().prePassRenderer!.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE)) {
+                        if (prePassConfiguration.previousBones[mesh.uniqueId]) {
+                            effect.setMatrices("mPreviousBones", prePassConfiguration.previousBones[mesh.uniqueId]);
+                        }
+
+                        MaterialHelper._CopyBonesTransformationMatrices(matrices, prePassConfiguration.previousBones[mesh.uniqueId]);
+                    }
                 }
             }
         }
     }
 
+    // Copies the bones transformation matrices into the target array and returns the target's reference
+    private static _CopyBonesTransformationMatrices(source: Float32Array, target: Float32Array): Float32Array {
+        target.set(source);
+
+        return target;
+    }
+
     /**
      * Binds the morph targets information from the mesh to the effect.
      * @param abstractMesh The mesh we are binding the information to render

+ 70 - 0
src/Materials/prePassConfiguration.ts

@@ -0,0 +1,70 @@
+import { Matrix } from "../Maths/math.vector";
+import { Mesh } from "../Meshes/mesh";
+import { Scene } from "../scene";
+import { Effect } from "../Materials/effect";
+import { Constants } from "../Engines/constants";
+
+/**
+ * Configuration needed for prepass-capable materials
+ */
+export class PrePassConfiguration {
+    /**
+     * Previous world matrices of meshes carrying this material
+     * Used for computing velocity
+     */
+    public previousWorldMatrices: { [index: number]: Matrix } = {};
+    /**
+     * Previous view project matrix
+     * Used for computing velocity
+     */
+    public previousViewProjection: Matrix;
+    /**
+     * Previous bones of meshes carrying this material
+     * Used for computing velocity
+     */
+    public previousBones: { [index: number]: Float32Array } = {};
+
+    /**
+     * Add the required uniforms to the current list.
+     * @param uniforms defines the current uniform list.
+     */
+    public static AddUniforms(uniforms: string[]): void {
+        uniforms.push("previousWorld", "previousViewProjection");
+    }
+
+    /**
+     * Add the required samplers to the current list.
+     * @param samplers defines the current sampler list.
+     */
+    public static AddSamplers(samplers: string[]): void {
+        // pass
+    }
+
+    /**
+     * Binds the material data.
+     * @param effect defines the effect to update
+     * @param scene defines the scene the material belongs to.
+     * @param mesh The mesh
+     * @param world World matrix of this mesh
+     * @param isFrozen Is the material frozen
+     */
+    public bindForSubMesh(effect: Effect, scene: Scene, mesh: Mesh, world: Matrix, isFrozen: boolean): void {
+        if (scene.prePassRenderer && scene.prePassRenderer.enabled) {
+            if (scene.prePassRenderer.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE) !== -1) {
+                if (!this.previousWorldMatrices[mesh.uniqueId]) {
+                    this.previousWorldMatrices[mesh.uniqueId] = Matrix.Identity();
+                }
+
+                if (!this.previousViewProjection) {
+                    this.previousViewProjection = scene.getTransformMatrix();
+                }
+
+                effect.setMatrix("previousWorld", this.previousWorldMatrices[mesh.uniqueId]);
+                effect.setMatrix("previousViewProjection", this.previousViewProjection);
+
+                this.previousWorldMatrices[mesh.uniqueId] = world.clone();
+                this.previousViewProjection = scene.getTransformMatrix().clone();
+            }
+        }
+    }
+}

+ 20 - 0
src/Materials/standardMaterial.ts

@@ -11,6 +11,7 @@ import { VertexBuffer } from "../Meshes/buffer";
 import { SubMesh } from "../Meshes/subMesh";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Mesh } from "../Meshes/mesh";
+import { PrePassConfiguration } from "./prePassConfiguration";
 
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "./imageProcessingConfiguration";
 import { ColorCurves } from "./colorCurves";
@@ -86,6 +87,7 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
+    public BONES_VELOCITY_ENABLED = false;
     public INSTANCES = false;
     public THIN_INSTANCES = false;
     public GLOSSINESS = false;
@@ -132,6 +134,12 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public PREPASS_ALBEDO_INDEX = -1;
     public PREPASS_DEPTHNORMAL = false;
     public PREPASS_DEPTHNORMAL_INDEX = -1;
+    public PREPASS_POSITION = false;
+    public PREPASS_POSITION_INDEX = -1;
+    public PREPASS_VELOCITY = false;
+    public PREPASS_VELOCITY_INDEX = -1;
+    public PREPASS_REFLECTIVITY = false;
+    public PREPASS_REFLECTIVITY_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public RGBDLIGHTMAP = false;
@@ -581,6 +589,11 @@ export class StandardMaterial extends PushMaterial {
     }
 
     /**
+     * Defines additionnal PrePass parameters for the material.
+     */
+    public readonly prePassConfiguration: PrePassConfiguration;
+
+    /**
      * Gets wether the color curves effect is enabled.
      */
     public get cameraColorCurvesEnabled(): boolean {
@@ -713,6 +726,7 @@ export class StandardMaterial extends PushMaterial {
 
         // Setup the default processing configuration to the scene.
         this._attachImageProcessingConfiguration(null);
+        this.prePassConfiguration = new PrePassConfiguration();
 
         this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
             this._renderTargets.reset();
@@ -1190,6 +1204,9 @@ export class StandardMaterial extends PushMaterial {
             DetailMapConfiguration.AddUniforms(uniforms);
             DetailMapConfiguration.AddSamplers(samplers);
 
+            PrePassConfiguration.AddUniforms(uniforms);
+            PrePassConfiguration.AddSamplers(uniforms);
+
             if (ImageProcessingConfiguration) {
                 ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
                 ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
@@ -1362,6 +1379,9 @@ export class StandardMaterial extends PushMaterial {
             this.bindOnlyWorldMatrix(world);
         }
 
+        // PrePass
+        this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen);
+
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
             world.toNormalMatrix(this._normalMatrix);

+ 4 - 21
src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts

@@ -119,8 +119,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
     */
     private _sampleSphere: number[];
 
-    private _ssao2PrePassConfiguration: SSAO2Configuration;
-
     /**
     * Blur filter offsets
     */
@@ -212,7 +210,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             scene.enableGeometryBufferRenderer();
         } else {
             this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
-            this._prePassRenderer.markAsDirty();
         }
 
         this._createRandomTexture();
@@ -235,7 +232,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         if (cameras) {
             scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
         }
-
     }
 
     // Public Methods
@@ -269,7 +265,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         }
 
         this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
-        this._ssao2PrePassConfiguration.enabled = false;
 
         super.dispose();
     }
@@ -450,6 +445,10 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             effect.setTextureFromPostProcess("originalColor", this._originalColorPostProcess);
         };
         this._ssaoCombinePostProcess.samples = this.textureSamples;
+
+        if (!this._forceGeometryBuffer) {
+            this._ssaoCombinePostProcess._prePassEffectConfiguration = new SSAO2Configuration();
+        }
     }
 
     private _createRandomTexture(): void {
@@ -508,22 +507,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
     public static Parse(source: any, scene: Scene, rootUrl: string): SSAO2RenderingPipeline {
         return SerializationHelper.Parse(() => new SSAO2RenderingPipeline(source._name, scene, source._ratio), source, scene, rootUrl);
     }
-
-    /**
-     * Sets the required values to the prepass renderer.
-     * @param prePassRenderer defines the prepass renderer to setup
-     * @returns true if the pre pass is needed.
-     */
-    public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
-        let cfg = this._ssao2PrePassConfiguration;
-        if (!cfg) {
-            cfg = new SSAO2Configuration();
-        }
-
-        cfg.enabled = true;
-        this._ssao2PrePassConfiguration = prePassRenderer.addEffectConfiguration(cfg);
-        return true;
-    }
 }
 
 _TypeStore.RegisteredTypes["BABYLON.SSAO2RenderingPipeline"] = SSAO2RenderingPipeline;

+ 48 - 12
src/PostProcesses/motionBlurPostProcess.ts

@@ -7,6 +7,8 @@ import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Constants } from "../Engines/constants";
 import { GeometryBufferRenderer } from "../Rendering/geometryBufferRenderer";
 import { AbstractMesh } from "../Meshes/abstractMesh";
+import { MotionBlurConfiguration } from "../Rendering/motionBlurConfiguration";
+import { PrePassRenderer } from "../Rendering/prePassRenderer";
 
 import "../Animations/animatable";
 import '../Rendering/geometryBufferRendererSceneComponent';
@@ -56,7 +58,10 @@ export class MotionBlurPostProcess extends PostProcess {
 
     @serialize("motionBlurSamples")
     private _motionBlurSamples: number = 32;
+
+    private _forceGeometryBuffer: boolean = false;
     private _geometryBufferRenderer: Nullable<GeometryBufferRenderer>;
+    private _prePassRenderer: PrePassRenderer;
 
     /**
      * Gets a string identifying the name of the class
@@ -77,20 +82,31 @@ export class MotionBlurPostProcess extends PostProcess {
      * @param reusable If the post process can be reused on the same frame. (default: false)
      * @param textureType Type of textures used when performing the post process. (default: 0)
      * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+     * @param forceGeometryBuffer If this post process should use geometry buffer instead of prepass (default: false)
      */
-    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false, forceGeometryBuffer = false) {
         super(name, "motionBlur", ["motionStrength", "motionScale", "screenSize"], ["velocitySampler"], options, camera, samplingMode, engine, reusable, "#define GEOMETRY_SUPPORTED\n#define SAMPLES 64.0", textureType, undefined, null, blockCompilation);
 
-        this._geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+        this._forceGeometryBuffer = forceGeometryBuffer;
+
+        // Set up assets
+        if (this._forceGeometryBuffer) {
+            this._geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+
+            if (this._geometryBufferRenderer) {
+                this._geometryBufferRenderer.enableVelocity = true;
+            }
+        } else {
+            this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
+            this._prePassRenderer.markAsDirty();
+            this._prePassEffectConfiguration = new MotionBlurConfiguration();
+        }
 
-        if (!this._geometryBufferRenderer) {
-            // Geometry buffer renderer is not supported. So, work as a passthrough.
+        if (!this._geometryBufferRenderer && !this._prePassRenderer) {
+            // We can't get a velocity texture. So, work as a passthrough.
             Logger.Warn("Multiple Render Target support needed to compute object based motion blur");
             this.updateEffect();
         } else {
-            // Geometry buffer renderer is supported.
-            this._geometryBufferRenderer.enableVelocity = true;
-
             this.onApply = (effect: Effect) => {
                 effect.setVector2("screenSize", new Vector2(this.width, this.height));
 
@@ -100,6 +116,9 @@ export class MotionBlurPostProcess extends PostProcess {
                 if (this._geometryBufferRenderer) {
                     const velocityIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE);
                     effect.setTexture("velocitySampler", this._geometryBufferRenderer.getGBuffer().textures[velocityIndex]);
+                } else {
+                    const velocityIndex = this._prePassRenderer.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE);
+                    effect.setTexture("velocitySampler", this._prePassRenderer.prePassRT.textures[velocityIndex]);
                 }
             };
         }
@@ -111,8 +130,16 @@ export class MotionBlurPostProcess extends PostProcess {
      * @param skinnedMesh The mesh containing the skeleton to ignore when computing the velocity map.
      */
     public excludeSkinnedMesh(skinnedMesh: AbstractMesh): void {
-        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
-            this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.push(skinnedMesh);
+        if (skinnedMesh.skeleton) {
+            let list;
+            if (this._geometryBufferRenderer) {
+                list = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity;
+            } else if (this._prePassRenderer) {
+                list = this._prePassRenderer.excludedSkinnedMesh;
+            } else {
+                return;
+            }
+            list.push(skinnedMesh);
         }
     }
 
@@ -122,10 +149,19 @@ export class MotionBlurPostProcess extends PostProcess {
      * @see excludeSkinnedMesh to exclude a skinned mesh from bones velocity computation.
      */
     public removeExcludedSkinnedMesh(skinnedMesh: AbstractMesh): void {
-        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
-            const index = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.indexOf(skinnedMesh);
+        if (skinnedMesh.skeleton) {
+            let list;
+            if (this._geometryBufferRenderer) {
+                list = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity;
+            } else if (this._prePassRenderer) {
+                list = this._prePassRenderer.excludedSkinnedMesh;
+            } else {
+                return;
+            }
+
+            const index = list.indexOf(skinnedMesh);
             if (index !== -1) {
-                this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.splice(index, 1);
+                list.splice(index, 1);
             }
         }
     }

+ 23 - 0
src/PostProcesses/postProcess.ts

@@ -19,6 +19,8 @@ declare type Scene = import("../scene").Scene;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
 declare type WebVRFreeCamera = import("../Cameras/VR/webVRCamera").WebVRFreeCamera;
 declare type Animation = import("../Animations/animation").Animation;
+declare type PrePassRenderer = import("../Rendering/prePassRenderer").PrePassRenderer;
+declare type PrePassEffectConfiguration = import("../Rendering/prePassEffectConfiguration").PrePassEffectConfiguration;
 
 /**
  * Size options for a post process
@@ -187,6 +189,12 @@ export class PostProcess {
     private _forcedOutputTexture: Nullable<InternalTexture>;
 
     /**
+    * Prepass configuration in case this post process needs a texture from prepass
+    * @hidden
+    */
+    public _prePassEffectConfiguration: PrePassEffectConfiguration;
+
+    /**
      * Returns the fragment url or shader name used in the post process.
      * @returns the fragment url or name in the shader store.
      */
@@ -679,6 +687,21 @@ export class PostProcess {
     }
 
     /**
+     * Sets the required values to the prepass renderer.
+     * @param prePassRenderer defines the prepass renderer to setup.
+     * @returns true if the pre pass is needed.
+     */
+    public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
+        if (this._prePassEffectConfiguration) {
+            this._prePassEffectConfiguration = prePassRenderer.addEffectConfiguration(this._prePassEffectConfiguration);
+            this._prePassEffectConfiguration.enabled = true;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Disposes the post process.
      * @param camera The camera to dispose the post process on.
      */

+ 47 - 17
src/PostProcesses/screenSpaceReflectionPostProcess.ts

@@ -5,6 +5,8 @@ import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Constants } from "../Engines/constants";
 import { GeometryBufferRenderer } from '../Rendering/geometryBufferRenderer';
 import { serialize, SerializationHelper } from '../Misc/decorators';
+import { PrePassRenderer } from "../Rendering/prePassRenderer";
+import { ScreenSpaceReflectionsConfiguration } from "../Rendering/screenSpaceReflectionsConfiguration";
 
 import "../Shaders/screenSpaceReflection.fragment";
 import { _TypeStore } from '../Misc/typeStore';
@@ -43,7 +45,9 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
     @serialize()
     public roughnessFactor: number = 0.2;
 
+    private _forceGeometryBuffer: boolean = false;
     private _geometryBufferRenderer: Nullable<GeometryBufferRenderer>;
+    private _prePassRenderer: PrePassRenderer;
     private _enableSmoothReflections: boolean = false;
     private _reflectionSamples: number = 64;
     private _smoothSteps: number = 5;
@@ -67,8 +71,9 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
      * @param reusable If the post process can be reused on the same frame. (default: false)
      * @param textureType Type of textures used when performing the post process. (default: 0)
      * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+     * @param forceGeometryBuffer If this post process should use geometry buffer instead of prepass (default: false)
      */
-    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false, forceGeometryBuffer = false) {
         super(name, "screenSpaceReflection", [
             "projection", "view", "threshold", "reflectionSpecularFalloffExponent", "strength", "step", "roughnessFactor"
         ], [
@@ -77,31 +82,53 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
         "#define SSR_SUPPORTED\n#define REFLECTION_SAMPLES 64\n#define SMOOTH_STEPS 5\n",
         textureType, undefined, null, blockCompilation);
 
-        // Get geometry buffer renderer and update effect
-        const geometryBufferRenderer = scene.enableGeometryBufferRenderer();
-        if (geometryBufferRenderer) {
-            if (geometryBufferRenderer.isSupported) {
-                geometryBufferRenderer.enablePosition = true;
-                geometryBufferRenderer.enableReflectivity = true;
-                this._geometryBufferRenderer = geometryBufferRenderer;
+        this._forceGeometryBuffer = forceGeometryBuffer;
+
+        if (this._forceGeometryBuffer) {
+            // Get geometry buffer renderer and update effect
+            const geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+            if (geometryBufferRenderer) {
+                if (geometryBufferRenderer.isSupported) {
+                    geometryBufferRenderer.enablePosition = true;
+                    geometryBufferRenderer.enableReflectivity = true;
+                    this._geometryBufferRenderer = geometryBufferRenderer;
+                }
             }
+        } else {
+            this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
+            this._prePassRenderer.markAsDirty();
+            this._prePassEffectConfiguration = new ScreenSpaceReflectionsConfiguration();
         }
 
         this._updateEffectDefines();
 
         // On apply, send uniforms
         this.onApply = (effect: Effect) => {
-            if (!geometryBufferRenderer) {
+            const geometryBufferRenderer = this._geometryBufferRenderer;
+            const prePassRenderer = this._prePassRenderer;
+
+            if (!prePassRenderer && !geometryBufferRenderer) {
                 return;
             }
 
-            // Samplers
-            const positionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
-            const roughnessIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE);
-
-            effect.setTexture("normalSampler", geometryBufferRenderer.getGBuffer().textures[1]);
-            effect.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[positionIndex]);
-            effect.setTexture("reflectivitySampler", geometryBufferRenderer.getGBuffer().textures[roughnessIndex]);
+            if (geometryBufferRenderer) {
+                // Samplers
+                const positionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
+                const roughnessIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE);
+
+                effect.setTexture("normalSampler", geometryBufferRenderer.getGBuffer().textures[1]);
+                effect.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[positionIndex]);
+                effect.setTexture("reflectivitySampler", geometryBufferRenderer.getGBuffer().textures[roughnessIndex]);
+            } else {
+                // Samplers
+                const positionIndex = prePassRenderer.getIndex(Constants.PREPASS_POSITION_TEXTURE_TYPE);
+                const roughnessIndex = prePassRenderer.getIndex(Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE);
+                const normalIndex = prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE);
+
+                effect.setTexture("normalSampler", prePassRenderer.prePassRT.textures[normalIndex]);
+                effect.setTexture("positionSampler", prePassRenderer.prePassRT.textures[positionIndex]);
+                effect.setTexture("reflectivitySampler", prePassRenderer.prePassRT.textures[roughnessIndex]);
+            }
 
             // Uniforms
             const camera = scene.activeCamera;
@@ -192,8 +219,11 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
 
     private _updateEffectDefines(): void {
         const defines: string[] = [];
-        if (this._geometryBufferRenderer) {
+        if (this._geometryBufferRenderer || this._prePassRenderer) {
             defines.push("#define SSR_SUPPORTED");
+            if (this._prePassRenderer) {
+                defines.push("#define PREPASS_LAYOUT");
+            }
         }
         if (this._enableSmoothReflections) {
             defines.push("#define ENABLE_SMOOTH_REFLECTIONS");

+ 26 - 0
src/Rendering/motionBlurConfiguration.ts

@@ -0,0 +1,26 @@
+import { Constants } from "../Engines/constants";
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+
+/**
+ * Contains all parameters needed for the prepass to perform
+ * motion blur
+ */
+export class MotionBlurConfiguration implements PrePassEffectConfiguration {
+    /**
+     * Is motion blur enabled
+     */
+    public enabled = false;
+
+    /**
+     * Name of the configuration
+     */
+    public name = "motionBlur";
+
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    public readonly texturesRequired: number[] = [
+        Constants.PREPASS_VELOCITY_TEXTURE_TYPE
+    ];
+}

+ 1 - 1
src/Rendering/prePassEffectConfiguration.ts

@@ -23,7 +23,7 @@ export interface PrePassEffectConfiguration {
     /**
      * Disposes the effect configuration
      */
-    dispose(): void;
+    dispose?: () => void;
     /**
      * Creates the associated post process
      */

+ 36 - 35
src/Rendering/prePassRenderer.ts

@@ -5,10 +5,13 @@ import { Constants } from "../Engines/constants";
 import { ImageProcessingPostProcess } from "../PostProcesses/imageProcessingPostProcess";
 import { PostProcess } from "../PostProcesses/postProcess";
 import { Effect } from "../Materials/effect";
-import { Logger } from '../Misc/logger';
 import { _DevTools } from '../Misc/devTools';
 import { Color4 } from "../Maths/math.color";
 import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { Nullable } from "../types";
+import { AbstractMesh } from '../Meshes/abstractMesh';
+import { Material } from '../Materials/material';
+
 /**
  * Renders a pre pass of the scene
  * This means every mesh in the scene will be rendered to a render target texture
@@ -50,7 +53,12 @@ export class PrePassRenderer {
             type: Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
             format: Constants.TEXTURETYPE_UNSIGNED_INT,
         },
-];
+    ];
+
+    /**
+     * To save performance, we can excluded skinned meshes from the prepass
+     */
+    public excludedSkinnedMesh: AbstractMesh[] = [];
 
     private _textureIndices: number[] = [];
 
@@ -86,16 +94,6 @@ export class PrePassRenderer {
      */
     private _effectConfigurations: PrePassEffectConfiguration[] = [];
 
-    /**
-     * Should materials render their geometry on the MRT
-     */
-    public materialsShouldRenderGeometry: boolean = false;
-
-    /**
-     * Should materials render the irradiance information on the MRT
-     */
-    public materialsShouldRenderIrradiance: boolean = false;
-
     private _mrtFormats: number[] = [];
     private _mrtLayout: number[];
 
@@ -259,16 +257,6 @@ export class PrePassRenderer {
         }
     }
 
-    private _checkTextureType(type: number) : boolean {
-        if (type < 0 || type >= this._textureFormats.length) {
-            Logger.Error("PrePassRenderer : Unknown texture type");
-            return false;
-        }
-
-        return true;
-
-    }
-
     /**
      * Adds an effect configuration to the prepass.
      * If an effect has already been added, it won't add it twice and will return the configuration
@@ -294,10 +282,6 @@ export class PrePassRenderer {
      * @return The index
      */
     public getIndex(type: number) : number {
-        if (!this._checkTextureType(type)) {
-            return -1;
-        }
-
         return this._textureIndices[type];
     }
 
@@ -389,9 +373,6 @@ export class PrePassRenderer {
     private _enableTextures(types: number[]) {
         for (let i = 0; i < types.length; i++) {
             let type = types[i];
-            if (!this._checkTextureType(type)) {
-                return;
-            }
 
             if (this._textureIndices[type] === -1) {
                 this._textureIndices[type] = this._mrtLayout.length;
@@ -413,13 +394,22 @@ export class PrePassRenderer {
             }
         }
 
-        const pipelines = this._scene.postProcessRenderPipelineManager.supportedPipelines;
-        for (let i = 0; i < pipelines.length; i++) {
-            if (pipelines[i].setPrePassRenderer(this)) {
-                enablePrePass = true;
+        const camera = this._scene.activeCamera;
+        if (!camera) {
+            return;
+        }
+
+        const postProcesses = (<Nullable<PostProcess[]>>camera._postProcesses.filter((pp) => { return pp != null; }));
+
+        if (postProcesses) {
+            for (let i = 0; i < postProcesses.length; i++) {
+                if (postProcesses[i].setPrePassRenderer(this)) {
+                    enablePrePass = true;
+                }
             }
         }
 
+        this._markAllMaterialsAsPrePassDirty();
         this._isDirty = false;
 
         if (enablePrePass) {
@@ -427,7 +417,16 @@ export class PrePassRenderer {
         }
 
         if (!this.enabled) {
-            this._engine.bindAttachments(this._defaultAttachments);
+            // Prepass disabled, we render only on 1 color attachment
+            this._engine.bindAttachments([this._engine._gl.COLOR_ATTACHMENT0]);
+        }
+    }
+
+    private _markAllMaterialsAsPrePassDirty() {
+        const materials = this._scene.materials;
+
+        for (let i = 0; i < materials.length; i++) {
+            materials[i].markAsDirty(Material.PrePassDirtyFlag);
         }
     }
 
@@ -436,7 +435,9 @@ export class PrePassRenderer {
      */
     public dispose() {
         for (let i = 0; i < this._effectConfigurations.length; i++) {
-            this._effectConfigurations[i].dispose();
+            if (this._effectConfigurations[i].dispose) {
+                this._effectConfigurations[i].dispose!();
+            }
         }
 
         this.imageProcessingPostProcess.dispose();

+ 28 - 0
src/Rendering/screenSpaceReflectionsConfiguration.ts

@@ -0,0 +1,28 @@
+import { Constants } from "../Engines/constants";
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+
+/**
+ * Contains all parameters needed for the prepass to perform
+ * screen space reflections
+ */
+export class ScreenSpaceReflectionsConfiguration implements PrePassEffectConfiguration {
+    /**
+     * Is ssr enabled
+     */
+    public enabled = false;
+
+    /**
+     * Name of the configuration
+     */
+    public name = "screenSpaceReflections";
+
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    public readonly texturesRequired: number[] = [
+        Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+        Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE,
+        Constants.PREPASS_POSITION_TEXTURE_TYPE,
+    ];
+}

+ 0 - 15
src/Rendering/ssao2Configuration.ts

@@ -23,19 +23,4 @@ export class SSAO2Configuration implements PrePassEffectConfiguration {
     public readonly texturesRequired: number[] = [
         Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE
     ];
-
-    /**
-     * Builds a ssao2 configuration object
-     * @param scene The scene
-     */
-    constructor() {
-
-    }
-
-    /**
-     * Disposes the configuration
-     */
-    public dispose() {
-        // pass
-    }
 }

+ 4 - 1
src/Shaders/ShadersInclude/bonesDeclaration.fx

@@ -4,7 +4,10 @@
 		uniform float boneTextureWidth;
 	#else
 		uniform mat4 mBones[BonesPerMesh];
-	#endif	
+		#ifdef BONES_VELOCITY_ENABLED
+		    uniform mat4 mPreviousBones[BonesPerMesh];
+		#endif
+	#endif
 
 	attribute vec4 matricesIndices;
 	attribute vec4 matricesWeights;

+ 3 - 1
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -134,8 +134,10 @@ uniform mat4 view;
     uniform vec3 vDiffusionDistance;
     uniform vec4 vTintColor;
     uniform vec3 vSubSurfaceIntensity;
+#endif
 
-    #ifdef SS_SCATTERING
+#ifdef PREPASS
+    #ifdef PREPASS_IRRADIANCE
         uniform float scatteringDiffusionProfile;
     #endif
 #endif

+ 1 - 5
src/Shaders/ShadersInclude/pbrFragmentExtraDeclaration.fx

@@ -27,8 +27,4 @@ varying vec3 vPositionW;
 
 #ifdef VERTEXCOLOR
     varying vec4 vColor;
-#endif
-
-#ifdef PREPASS
-	varying vec3 vViewPos;
-#endif
+#endif

+ 9 - 0
src/Shaders/ShadersInclude/prePassDeclaration.fx

@@ -2,4 +2,13 @@
 #extension GL_EXT_draw_buffers : require
 layout(location = 0) out vec4 glFragData[{X}];
 vec4 gl_FragColor;
+
+#ifdef PREPASS_DEPTHNORMAL
+    varying vec3 vViewPos;
+#endif
+#ifdef PREPASS_VELOCITY
+    varying vec4 vCurrentPosition;
+    varying vec4 vPreviousPosition;
+#endif
+
 #endif

+ 37 - 0
src/Shaders/ShadersInclude/prePassVertex.fx

@@ -0,0 +1,37 @@
+#ifdef PREPASS_DEPTHNORMAL
+    vViewPos = (view * worldPos).rgb;
+#endif
+
+#if defined(PREPASS_VELOCITY) && defined(BONES_VELOCITY_ENABLED)
+    vCurrentPosition = viewProjection * worldPos;
+
+#if NUM_BONE_INFLUENCERS > 0
+    mat4 previousInfluence;
+    previousInfluence = mPreviousBones[int(matricesIndices[0])] * matricesWeights[0];
+    #if NUM_BONE_INFLUENCERS > 1
+        previousInfluence += mPreviousBones[int(matricesIndices[1])] * matricesWeights[1];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 2
+        previousInfluence += mPreviousBones[int(matricesIndices[2])] * matricesWeights[2];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 3
+        previousInfluence += mPreviousBones[int(matricesIndices[3])] * matricesWeights[3];
+    #endif
+    #if NUM_BONE_INFLUENCERS > 4
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 5
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 6
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 7
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+    #endif
+
+    vPreviousPosition = previousViewProjection * previousWorld * previousInfluence * vec4(positionUpdated, 1.0);
+#else
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+#endif

+ 11 - 0
src/Shaders/ShadersInclude/prePassVertexDeclaration.fx

@@ -0,0 +1,11 @@
+#ifdef PREPASS
+#ifdef PREPASS_DEPTHNORMAL
+    varying vec3 vViewPos;
+#endif
+#ifdef PREPASS_VELOCITY
+    uniform mat4 previousWorld;
+    uniform mat4 previousViewProjection;
+    varying vec4 vCurrentPosition;
+    varying vec4 vPreviousPosition;
+#endif
+#endif

+ 6 - 0
src/Shaders/ShadersInclude/subSurfaceScatteringFunctions.fx

@@ -1,8 +1,14 @@
+#ifdef SS_SCATTERING
 vec3 tagLightingForSSS(vec3 color) {
     color.b = max(color.b, HALF_MIN);
 
     return color;
 }
+#else
+vec3 tagLightingForSSS(vec3 color) {
+    return vec3(0., 0., 0.);
+}
+#endif
 
 bool testLightingForSSS(vec3 color)
 {

+ 21 - 4
src/Shaders/default.fragment.fx

@@ -37,10 +37,6 @@ varying vec4 vColor;
 	varying vec2 vMainUV2;
 #endif
 
-#ifdef PREPASS
-	varying vec3 vViewPos;
-#endif
-
 // Helper functions
 #include<helperFunctions>
 
@@ -482,6 +478,20 @@ color.rgb = max(color.rgb, 0.);
 #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 #ifdef PREPASS
     gl_FragData[0] = color; // We can't split irradiance on std material
+    
+    #ifdef PREPASS_POSITION
+    gl_FragData[PREPASS_POSITION_INDEX] = vec4(vPositionW, 1.0);
+    #endif
+
+    #ifdef PREPASS_VELOCITY
+    vec2 a = (vCurrentPosition.xy / vCurrentPosition.w) * 0.5 + 0.5;
+    vec2 b = (vPreviousPosition.xy / vPreviousPosition.w) * 0.5 + 0.5;
+
+    vec2 velocity = abs(a - b);
+    velocity = vec2(pow(velocity.x, 1.0 / 3.0), pow(velocity.y, 1.0 / 3.0)) * sign(a - b) * 0.5 + 0.5;
+
+    gl_FragData[PREPASS_VELOCITY_INDEX] = vec4(velocity, 0.0, 1.0);
+    #endif
 
     #ifdef PREPASS_IRRADIANCE
         gl_FragData[PREPASS_IRRADIANCE_INDEX] = vec4(0.0, 0.0, 0.0, 1.0); //  We can't split irradiance on std material
@@ -494,6 +504,13 @@ color.rgb = max(color.rgb, 0.);
     #ifdef PREPASS_ALBEDO
         gl_FragData[PREPASS_ALBEDO_INDEX] = vec4(0.0, 0.0, 0.0, 1.0); // We can't split albedo on std material
     #endif
+    #ifdef PREPASS_REFLECTIVITY
+        #if defined(SPECULAR)
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = specularMapColor;
+        #else
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(0.0, 0.0, 0.0, 1.0);
+        #endif
+    #endif
 #endif
 	gl_FragColor = color;
 

+ 10 - 7
src/Shaders/default.vertex.fx

@@ -26,10 +26,7 @@ attribute vec4 color;
 
 // Uniforms
 #include<instancesDeclaration>
-
-#ifdef PREPASS
-varying vec3 vViewPos;
-#endif
+#include<prePassVertexDeclaration>
 
 #ifdef MAINUV1
 	varying vec2 vMainUV1;
@@ -128,6 +125,13 @@ void main(void) {
 #define CUSTOM_VERTEX_UPDATE_NORMAL
 
 #include<instancesVertex>
+
+#if defined(PREPASS) && defined(PREPASS_VELOCITY) && !defined(BONES_VELOCITY_ENABLED)
+    // Compute velocity before bones computation
+    vCurrentPosition = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+
 #include<bonesVertex>
 
 	vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
@@ -160,9 +164,8 @@ void main(void) {
 #endif	
 
 	vPositionW = vec3(worldPos);
-	#ifdef PREPASS
-	    vViewPos = (view * worldPos).rgb;
-	#endif
+	
+#include<prePassVertex>
 
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
 	vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0)));

+ 23 - 0
src/Shaders/pbr.fragment.fx

@@ -143,6 +143,7 @@ void main(void) {
 
 #if defined(REFLECTIVITY)
     vec4 surfaceMetallicOrReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
+    vec4 baseReflectivity = surfaceMetallicOrReflectivityColorMap;
     #ifndef METALLICWORKFLOW
         surfaceMetallicOrReflectivityColorMap = toLinearSpace(surfaceMetallicOrReflectivityColorMap);
         surfaceMetallicOrReflectivityColorMap.rgb *= vReflectivityInfos.y;
@@ -502,6 +503,20 @@ void main(void) {
     #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 
 #ifdef PREPASS
+    #ifdef PREPASS_POSITION
+    gl_FragData[PREPASS_POSITION_INDEX] = vec4(vPositionW, 1.0);
+    #endif
+
+    #ifdef PREPASS_VELOCITY
+    vec2 a = (vCurrentPosition.xy / vCurrentPosition.w) * 0.5 + 0.5;
+    vec2 b = (vPreviousPosition.xy / vPreviousPosition.w) * 0.5 + 0.5;
+
+    vec2 velocity = abs(a - b);
+    velocity = vec2(pow(velocity.x, 1.0 / 3.0), pow(velocity.y, 1.0 / 3.0)) * sign(a - b) * 0.5 + 0.5;
+
+    gl_FragData[PREPASS_VELOCITY_INDEX] = vec4(velocity, 0.0, 1.0);
+    #endif
+
     #ifdef PREPASS_IRRADIANCE
         vec3 irradiance = finalDiffuse;
         #ifndef UNLIT
@@ -529,6 +544,14 @@ void main(void) {
     #ifdef PREPASS_ALBEDO
         gl_FragData[PREPASS_ALBEDO_INDEX] = vec4(sqAlbedo, 1.0); // albedo, for pre and post scatter
     #endif
+
+    #ifdef PREPASS_REFLECTIVITY
+        #if defined(REFLECTIVITY)
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(baseReflectivity.rgb, 1.0);
+        #else
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(0.0, 0.0, 0.0, 1.0);
+        #endif
+    #endif
 #endif
 
     gl_FragColor = finalColor;

+ 10 - 7
src/Shaders/pbr.vertex.fx

@@ -33,10 +33,7 @@ attribute vec4 color;
 
 // Uniforms
 #include<instancesDeclaration>
-
-#ifdef PREPASS
-varying vec3 vViewPos;
-#endif
+#include<prePassVertexDeclaration>
 
 #if defined(ALBEDO) && ALBEDODIRECTUV == 0
 varying vec2 vAlbedoUV;
@@ -173,13 +170,19 @@ void main(void) {
 #define CUSTOM_VERTEX_UPDATE_NORMAL
 
 #include<instancesVertex>
+
+#if defined(PREPASS) && defined(PREPASS_VELOCITY) && !defined(BONES_VELOCITY_ENABLED)
+    // Compute velocity before bones computation
+    vCurrentPosition = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+
 #include<bonesVertex>
 
     vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
     vPositionW = vec3(worldPos);
-#ifdef PREPASS
-    vViewPos = (view * worldPos).rgb;
-#endif
+
+#include<prePassVertex>
 
 #ifdef NORMAL
     mat3 normalWorld = mat3(finalWorld);

+ 4 - 0
src/Shaders/screenSpaceReflection.fragment.fx

@@ -135,7 +135,11 @@ void main()
         }
         
         // Get coordinates of the pixel to pick according to the pixel's position and normal.
+        #ifdef PREPASS_LAYOUT
+        vec3 normal = (texture2D(normalSampler, vUV)).gba;
+        #else
         vec3 normal = (texture2D(normalSampler, vUV)).xyz;
+        #endif
         vec3 position = (view * texture2D(positionSampler, vUV)).xyz;
         vec3 reflected = normalize(reflect(normalize(position), normalize(normal)));
 

二进制
tests/validation/ReferenceImages/geometrybufferrenderer.png


二进制
tests/validation/ReferenceImages/motionBlur.png


二进制
tests/validation/ReferenceImages/ssr.png


+ 21 - 0
tests/validation/config.json

@@ -908,6 +908,27 @@
             "playgroundId": "#EIJH8L#1",
             "referenceImage": "ktx2decoder.png",
             "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Motion Blur",
+            "playgroundId": "#E5YGEL#2",
+            "referenceImage": "motionBlur.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Screen space reflections",
+            "playgroundId": "#PIZ1GK#172",
+            "referenceImage": "ssr.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Geometry buffer renderer",
+            "playgroundId": "#PIZ1GK#173",
+            "referenceImage": "geometrybufferrenderer.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
         }
     ]
 }