Browse Source

PBR reflection block implementation continued

Popov72 5 years ago
parent
commit
3167ccd429

+ 15 - 6
src/Materials/Node/Blocks/Fragment/PBR/pbrMetallicRoughnessBlock.ts

@@ -136,6 +136,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state._excludeVariableName("eho");
 
         state._excludeVariableName("environmentRadiance");
+        state._excludeVariableName("irradianceVector");
+        state._excludeVariableName("environmentIrradiance");
 
         state._excludeVariableName("diffuseBase");
         state._excludeVariableName("specularBase");
@@ -453,6 +455,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         if (reflectionBlock) {
             reflectionBlock.worldPositionConnectionPoint = this.worldPosition;
             reflectionBlock.cameraPositionConnectionPoint = this.cameraPosition;
+            reflectionBlock.worldNormalConnectionPoint = this.worldNormal;
         }
 
         if (state.target !== NodeMaterialBlockTargets.Fragment) {
@@ -489,6 +492,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state._emitFunctionFromInclude("helperFunctions", comments);
         state._emitFunctionFromInclude("pbrHelperFunctions", comments);
+        state._emitFunctionFromInclude("imageProcessingFunctions", comments);
 
         state._emitFunctionFromInclude("shadowsFragmentFunctions", comments, {
             replaceStrings: [
@@ -496,8 +500,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             ]
         });
 
-        state._emitFunctionFromInclude("harmonicsFunctions", comments);
-
         state._emitFunctionFromInclude("pbrDirectLightingSetupFunctions", comments, {
             replaceStrings: [
                 { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName + ".xyz" }
@@ -574,8 +576,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         // _____________________________ Reflection _______________________________________
         if (reflectionBlock && reflectionBlock.texture) {
-            reflectionBlock.worldNormalConnectionPoint = this.worldNormal;
-
             state.compilationString += `
                 struct reflectionOutParams
                 {
@@ -597,10 +597,13 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             `;
 
             state.compilationString += `reflectionOutParams reflectionOut;\r\n`;
-            state.compilationString += reflectionBlock.getCode(state, anisotropyBlock ? "anisotropicOut.anisotropicNormal" : this.worldNormal.associatedVariableName, "environmentRadiance");
+            state.compilationString += reflectionBlock.getCode(state, anisotropyBlock ? "anisotropicOut.anisotropicNormal" : "normalW", "environmentRadiance", "irradianceVector", "environmentIrradiance");
             state.compilationString += `
+                #ifdef SS_TRANSLUCENCY
+                    reflectionOut.irradianceVector = irradianceVector;
+                #endif
                 reflectionOut.environmentRadiance = environmentRadiance;
-                reflectionOut.environmentIrradiance = vec3(0.);
+                reflectionOut.environmentIrradiance = environmentIrradiance;
                 reflectionOut.reflectionCoords = ${reflectionBlock._reflectionCoordsName};\r\n`;
         }
 
@@ -666,6 +669,12 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             ]
         });
 
+        state.compilationString += state._emitCodeFromInclude("pbrBlockImageProcessing", comments, {
+            replaceStrings: [
+                { search: /visibility/g, replace: "1." },
+            ]
+        });
+
         if (this.lighting.hasEndpoints) {
             state.compilationString += this._declareOutput(this.lighting, state) + ` = finalColor;\r\n`;
         }

+ 176 - 2
src/Materials/Node/Blocks/Fragment/PBR/reflectionBlock.ts

@@ -8,17 +8,31 @@ import { NodeMaterialConnectionPointCustomObject } from "../../../nodeMaterialCo
 import { ReflectionTextureBaseBlock } from '../../Dual/reflectionTextureBaseBlock';
 import { AbstractMesh } from '../../../../../Meshes/abstractMesh';
 import { Engine } from '../../../../../Engines/engine';
+import { Nullable } from '../../../../../types';
+import { Texture } from '../../../../Textures/texture';
+import { BaseTexture } from '../../../../Textures/baseTexture';
+import { Mesh } from '../../../../../Meshes/mesh';
+import { SubMesh } from '../../../../../Meshes/subMesh';
+import { Effect } from '../../../../effect';
+import { editableInPropertyPage, PropertyTypeForEdition } from "../../../nodeMaterialDecorator";
 
 export class ReflectionBlock extends ReflectionTextureBaseBlock {
 
     private _defineLODReflectionAlpha: string;
     private _defineLinearSpecularReflection: string;
     private _defineLODBasedMicroSurface: string;
+    private _vEnvironmentIrradianceName: string;
 
     public worldPositionConnectionPoint: NodeMaterialConnectionPoint;
     public worldNormalConnectionPoint: NodeMaterialConnectionPoint;
     public cameraPositionConnectionPoint: NodeMaterialConnectionPoint;
 
+    @editableInPropertyPage("Spherical Harmonics", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "rebuild": false }})
+    public useSphericalHarmonics: boolean = true;
+
+    @editableInPropertyPage("Force irradiance in fragment", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "rebuild": false }})
+    public forceIrradianceInFragment: boolean = false;
+
     public constructor(name: string) {
         super(name);
 
@@ -90,6 +104,18 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         return this._outputs[0];
     }
 
+    /**
+     * Returns the texture used for reflections.
+     * @returns - Reflection texture if present.  Otherwise, returns the environment texture.
+     */
+    private _getReflectionTexture(): Nullable<BaseTexture> {
+        if (this.texture) {
+            return this.texture;
+        }
+
+        return Engine.LastCreatedScene!.environmentTexture;
+    }
+
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
         super.prepareDefines(mesh, nodeMaterial, defines);
 
@@ -106,6 +132,70 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         defines.setValue(this._defineLODBasedMicroSurface, Engine.LastCreatedScene?.getEngine()?.getCaps().textureLOD ?? false);
 
         defines.setValue("SPHERICAL_HARMONICS", this.useSphericalHarmonics);
+
+        const reflectionTexture = this._getReflectionTexture();
+
+        if (reflectionTexture && reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
+            if (reflectionTexture.isCube) {
+                defines.setValue("USESPHERICALFROMREFLECTIONMAP", true);
+                defines.setValue("USEIRRADIANCEMAP", false);
+                if (this.forceIrradianceInFragment || Engine.LastCreatedScene!.getEngine().getCaps().maxVaryingVectors <= 8) {
+                    defines.setValue("USESPHERICALINVERTEX", false);
+                }
+                else {
+                    defines.setValue("USESPHERICALINVERTEX", true);
+                }
+            }
+        }
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
+        super.bind(effect, nodeMaterial, mesh);
+
+        const reflectionTexture = this._getReflectionTexture();
+
+        if (!reflectionTexture || !subMesh) {
+            return;
+        }
+
+        if (reflectionTexture.isCube) {
+            effect.setTexture(this._cubeSamplerName, reflectionTexture);
+        } else {
+            effect.setTexture(this._2DSamplerName, reflectionTexture);
+        }
+
+        const defines = subMesh._materialDefines as  NodeMaterialDefines;
+
+        const polynomials = reflectionTexture.sphericalPolynomial;
+        if (defines.USESPHERICALFROMREFLECTIONMAP && polynomials) {
+            if (defines.SPHERICAL_HARMONICS) {
+                const preScaledHarmonics = polynomials.preScaledHarmonics;
+                effect.setVector3("vSphericalL00", preScaledHarmonics.l00);
+                effect.setVector3("vSphericalL1_1", preScaledHarmonics.l1_1);
+                effect.setVector3("vSphericalL10", preScaledHarmonics.l10);
+                effect.setVector3("vSphericalL11", preScaledHarmonics.l11);
+                effect.setVector3("vSphericalL2_2", preScaledHarmonics.l2_2);
+                effect.setVector3("vSphericalL2_1", preScaledHarmonics.l2_1);
+                effect.setVector3("vSphericalL20", preScaledHarmonics.l20);
+                effect.setVector3("vSphericalL21", preScaledHarmonics.l21);
+                effect.setVector3("vSphericalL22", preScaledHarmonics.l22);
+            }
+            else {
+                effect.setFloat3("vSphericalX", polynomials.x.x, polynomials.x.y, polynomials.x.z);
+                effect.setFloat3("vSphericalY", polynomials.y.x, polynomials.y.y, polynomials.y.z);
+                effect.setFloat3("vSphericalZ", polynomials.z.x, polynomials.z.y, polynomials.z.z);
+                effect.setFloat3("vSphericalXX_ZZ", polynomials.xx.x - polynomials.zz.x,
+                    polynomials.xx.y - polynomials.zz.y,
+                    polynomials.xx.z - polynomials.zz.z);
+                effect.setFloat3("vSphericalYY_ZZ", polynomials.yy.x - polynomials.zz.x,
+                    polynomials.yy.y - polynomials.zz.y,
+                    polynomials.yy.z - polynomials.zz.z);
+                effect.setFloat3("vSphericalZZ", polynomials.zz.x, polynomials.zz.y, polynomials.zz.z);
+                effect.setFloat3("vSphericalXY", polynomials.xy.x, polynomials.xy.y, polynomials.xy.z);
+                effect.setFloat3("vSphericalYZ", polynomials.yz.x, polynomials.yz.y, polynomials.yz.z);
+                effect.setFloat3("vSphericalZX", polynomials.zx.x, polynomials.zx.y, polynomials.zx.z);
+            }
+        }
     }
 
     private _formatNumberForGLSL(val: number): string {
@@ -118,7 +208,55 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         return s;
     }
 
-    public getCode(state: NodeMaterialBuildState, normalVarName: string, finalColorVarName: string): string {
+    public handleVertexSide(state: NodeMaterialBuildState): string {
+        let code = super.handleVertexSide(state);
+
+        state._emitFunctionFromInclude("harmonicsFunctions", `//${this.name}`, {
+            replaceStrings: [
+                { search: /uniform vec3 vSphericalL00;[\s\S]*?uniform vec3 vSphericalL22;/g, replace: "" },
+                { search: /uniform vec3 vSphericalX;[\s\S]*?uniform vec3 vSphericalZX;/g, replace: "" },
+            ]
+        });
+
+        const reflectionVectorName = state._getFreeVariableName("reflectionVector");
+
+        this._vEnvironmentIrradianceName = state._getFreeVariableName("vEnvironmentIrradiance");
+
+        state._emitVaryingFromString(this._vEnvironmentIrradianceName, "vec3", "defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX");
+
+        state._emitUniformFromString("vSphericalL00", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL1_1", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL10", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL11", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL2_2", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL2_1", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL20", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL21", "vec3", "SPHERICAL_HARMONICS");
+        state._emitUniformFromString("vSphericalL22", "vec3", "SPHERICAL_HARMONICS");
+
+        state._emitUniformFromString("vSphericalX", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalY", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalZ", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalXX_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalYY_ZZ", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalZZ", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalXY", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalYZ", "vec3", "SPHERICAL_HARMONICS", true);
+        state._emitUniformFromString("vSphericalZX", "vec3", "SPHERICAL_HARMONICS", true);
+
+        code +=
+            `#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
+                vec3 ${reflectionVectorName} = vec3(${this._reflectionMatrixName} * vec4(${this.worldNormal.associatedVariableName}.xyz, 0)).xyz;
+                #ifdef REFLECTIONMAP_OPPOSITEZ
+                    ${reflectionVectorName}.z *= -1.0;
+                #endif
+                ${this._vEnvironmentIrradianceName} = computeEnvironmentIrradiance(${reflectionVectorName});
+            #endif\r\n`;
+
+        return code;
+    }
+
+    public getCode(state: NodeMaterialBuildState, normalVarName: string, finalColorVarName: string, finalIrradianceVector: string, finalIrradianceVarName: string): string {
         let code = "";
 
         this.handleFragmentSideInits(state);
@@ -165,6 +303,26 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
                 // ***not handled***
             #endif\r\n`;
 
+        code += `
+            vec3 ${finalIrradianceVarName} = vec3(0.);
+            #ifdef USESPHERICALFROMREFLECTIONMAP
+                #if defined(USESPHERICALINVERTEX)
+                    ${finalIrradianceVarName} = ${this._vEnvironmentIrradianceName};
+                #else
+                    #ifdef ANISOTROPIC
+                        vec3 ${finalIrradianceVector} = vec3(${this._reflectionMatrixName} * vec4(anisotropicOut.anisotropicNormal, 0)).xyz;
+                    #else
+                        vec3 ${finalIrradianceVector} = vec3(${this._reflectionMatrixName} * vec4(${normalVarName}.xyz, 0)).xyz;
+                    #endif
+
+                    #ifdef REFLECTIONMAP_OPPOSITEZ
+                    ${finalIrradianceVector}.z *= -1.0;
+                    #endif
+
+                    ${finalIrradianceVarName} = computeEnvironmentIrradiance(${finalIrradianceVector});
+                #endif
+            #endif\r\n`;
+
         return code;
     }
 
@@ -177,6 +335,22 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
 
         return this;
     }
+
+    public serialize(): any {
+        let serializationObject = super.serialize();
+
+        serializationObject.useSphericalHarmonics = this.useSphericalHarmonics;
+        serializationObject.forceIrradianceInFragment = this.forceIrradianceInFragment;
+
+        return serializationObject;
+    }
+
+    public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
+        super._deserialize(serializationObject, scene, rootUrl);
+
+        this.useSphericalHarmonics = serializationObject.useSphericalHarmonics;
+        this.forceIrradianceInFragment = serializationObject.forceIrradianceInFragment;
+    }
 }
 
-_TypeStore.RegisteredTypes["BABYLON.ReflectionBlock"] = ReflectionBlock;
+_TypeStore.RegisteredTypes["BABYLON.ReflectionBlock"] = ReflectionBlock;