Pārlūkot izejas kodu

Merge branches 'master' and 'master' of https://github.com/BabylonJS/Babylon.js

David Catuhe 5 gadi atpakaļ
vecāks
revīzija
89eaaa87d4

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

@@ -95,6 +95,7 @@
 - Allow parenthesis usage in `#if` expressions in shader code ([Popov72](https://github.com/Popov72))
 - Added to `StandardMaterial` RGBD ReflectionTexture, RefractionTexture and LightmapTexture support. ([MackeyK24](https://github.com/MackeyK24))
 - Allow using the single comment syntax `// comment` in a `#if` construct in shader code ([Popov72](https://github.com/Popov72))
+- Added the possibility to update the shader code before being compiled ([Popov72](https://github.com/Popov72))
 
 ### WebXR
 

+ 26 - 11
src/Engines/Processors/shaderCodeInliner.ts

@@ -6,28 +6,43 @@ interface IInlineFunctionDescr {
     callIndex: number;
 }
 
-/** @hidden */
+/**
+ * Class used to inline functions in shader code
+*/
 export class ShaderCodeInliner {
 
-    static readonly InlineToken = "#define inline";
     static readonly RegexpFindFunctionNameAndType = /((\s+?)(\w+)\s+(\w+)\s*?)$/;
 
     private _sourceCode: string;
     private _functionDescr: IInlineFunctionDescr[];
     private _numMaxIterations: number;
 
+    /** Gets or sets the token used to mark the functions to inline */
+    public inlineToken: string;
+
+    /** Gets or sets the debug mode */
     public debug: boolean = false;
 
+    /** Gets the code after the inlining process */
     public get code(): string {
         return this._sourceCode;
     }
 
+    /**
+     * Initializes the inliner
+     * @param sourceCode shader code source to inline
+     * @param numMaxIterations maximum number of iterations (used to detect recursive calls)
+     */
     constructor(sourceCode: string, numMaxIterations = 20) {
         this._sourceCode = sourceCode;
         this._numMaxIterations = numMaxIterations;
         this._functionDescr = [];
+        this.inlineToken = "#define inline";
     }
 
+    /**
+     * Start the processing of the shader code
+     */
     public processCode() {
         if (this.debug) {
             console.log(`Start inlining process (code size=${this._sourceCode.length})...`);
@@ -44,26 +59,26 @@ export class ShaderCodeInliner {
 
         while (startIndex < this._sourceCode.length) {
             // locate the function to inline and extract its name
-            const inlineTokenIndex = this._sourceCode.indexOf(ShaderCodeInliner.InlineToken, startIndex);
+            const inlineTokenIndex = this._sourceCode.indexOf(this.inlineToken, startIndex);
             if (inlineTokenIndex < 0) {
                 break;
             }
 
-            const funcParamsStartIndex = this._sourceCode.indexOf("(", inlineTokenIndex + ShaderCodeInliner.InlineToken.length);
+            const funcParamsStartIndex = this._sourceCode.indexOf("(", inlineTokenIndex + this.inlineToken.length);
             if (funcParamsStartIndex < 0) {
                 if (this.debug) {
                     console.warn(`Could not find the opening parenthesis after the token. startIndex=${startIndex}`);
                 }
-                startIndex = inlineTokenIndex + ShaderCodeInliner.InlineToken.length;
+                startIndex = inlineTokenIndex + this.inlineToken.length;
                 continue;
             }
 
-            const funcNameMatch = ShaderCodeInliner.RegexpFindFunctionNameAndType.exec(this._sourceCode.substring(inlineTokenIndex + ShaderCodeInliner.InlineToken.length, funcParamsStartIndex));
+            const funcNameMatch = ShaderCodeInliner.RegexpFindFunctionNameAndType.exec(this._sourceCode.substring(inlineTokenIndex + this.inlineToken.length, funcParamsStartIndex));
             if (!funcNameMatch) {
                 if (this.debug) {
-                    console.warn(`Could not extract the name/type of the function from: ${this._sourceCode.substring(inlineTokenIndex + ShaderCodeInliner.InlineToken.length, funcParamsStartIndex)}`);
+                    console.warn(`Could not extract the name/type of the function from: ${this._sourceCode.substring(inlineTokenIndex + this.inlineToken.length, funcParamsStartIndex)}`);
                 }
-                startIndex = inlineTokenIndex + ShaderCodeInliner.InlineToken.length;
+                startIndex = inlineTokenIndex + this.inlineToken.length;
                 continue;
             }
             const [funcType, funcName] = [funcNameMatch[3], funcNameMatch[4]];
@@ -74,7 +89,7 @@ export class ShaderCodeInliner {
                 if (this.debug) {
                     console.warn(`Could not extract the parameters the function '${funcName}' (type=${funcType}). funcParamsStartIndex=${funcParamsStartIndex}`);
                 }
-                startIndex = inlineTokenIndex + ShaderCodeInliner.InlineToken.length;
+                startIndex = inlineTokenIndex + this.inlineToken.length;
                 continue;
             }
             const funcParams = this._sourceCode.substring(funcParamsStartIndex + 1, funcParamsEndIndex);
@@ -85,7 +100,7 @@ export class ShaderCodeInliner {
                 if (this.debug) {
                     console.warn(`Could not extract the body of the function '${funcName}' (type=${funcType}). funcParamsEndIndex=${funcParamsEndIndex}`);
                 }
-                startIndex = inlineTokenIndex + ShaderCodeInliner.InlineToken.length;
+                startIndex = inlineTokenIndex + this.inlineToken.length;
                 continue;
             }
 
@@ -94,7 +109,7 @@ export class ShaderCodeInliner {
                 if (this.debug) {
                     console.warn(`Could not extract the body of the function '${funcName}' (type=${funcType}). funcBodyStartIndex=${funcBodyStartIndex}`);
                 }
-                startIndex = inlineTokenIndex + ShaderCodeInliner.InlineToken.length;
+                startIndex = inlineTokenIndex + this.inlineToken.length;
                 continue;
             }
             const funcBody = this._sourceCode.substring(funcBodyStartIndex, funcBodyEndIndex + 1);

+ 1 - 0
src/Engines/index.ts

@@ -10,3 +10,4 @@ export * from "./IPipelineContext";
 export * from "./WebGL/webGLPipelineContext";
 export * from "./WebGL/webGL2ShaderProcessors";
 export * from "./nativeEngine";
+export * from "./Processors/shaderCodeInliner";

+ 6 - 3
src/Materials/PBR/pbrBaseMaterial.ts

@@ -21,7 +21,7 @@ import { Scalar } from "../../Maths/math.scalar";
 
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "../../Materials/imageProcessingConfiguration";
 import { Effect, IEffectCreationOptions } from "../../Materials/effect";
-import { Material, IMaterialCompilationOptions } from "../../Materials/material";
+import { Material, IMaterialCompilationOptions, ICustomShaderNameResolveOptions } from "../../Materials/material";
 import { MaterialDefines } from "../../Materials/materialDefines";
 import { PushMaterial } from "../../Materials/pushMaterial";
 import { MaterialHelper } from "../../Materials/materialHelper";
@@ -1257,8 +1257,10 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             maxSimultaneousLights: this._maxSimultaneousLights
         });
 
+        const csnrOptions: ICustomShaderNameResolveOptions = {};
+
         if (this.customShaderNameResolve) {
-            shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs);
+            shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs, csnrOptions);
         }
 
         var join = defines.toString();
@@ -1271,7 +1273,8 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             fallbacks: fallbacks,
             onCompiled: onCompiled,
             onError: onError,
-            indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
+            indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS },
+            processFinalCode: csnrOptions.processFinalCode,
         }, engine);
     }
 

+ 14 - 0
src/Materials/effect.ts

@@ -65,6 +65,10 @@ export interface IEffectCreationOptions {
      * See https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/transformFeedbackVaryings
      */
     transformFeedbackVaryings?: Nullable<string[]>;
+    /**
+     * If provided, will be called two times with the vertex and fragment code so that this code can be updated before it is compiled by the GPU
+     */
+    processFinalCode?: Nullable<(shaderType: string, code: string) => string>;
 }
 
 /**
@@ -189,6 +193,8 @@ export class Effect implements IDisposable {
         fallbacks: Nullable<IEffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any) {
         this.name = baseName;
 
+        let processFinalCode: Nullable<(shaderType: string, code: string) => string> = null;
+
         if ((<IEffectCreationOptions>attributesNamesOrOptions).attributes) {
             var options = <IEffectCreationOptions>attributesNamesOrOptions;
             this._engine = <Engine>uniformsNamesOrEngine;
@@ -209,6 +215,8 @@ export class Effect implements IDisposable {
                     this._uniformBuffersNames[options.uniformBuffersNames[i]] = i;
                 }
             }
+
+            processFinalCode = options.processFinalCode ?? null;
         } else {
             this._engine = <Engine>engine;
             this.defines = (defines == null ? "" : defines);
@@ -273,8 +281,14 @@ export class Effect implements IDisposable {
         this._loadShader(vertexSource, "Vertex", "", (vertexCode) => {
             this._loadShader(fragmentSource, "Fragment", "Pixel", (fragmentCode) => {
                 ShaderProcessor.Process(vertexCode, processorOptions, (migratedVertexCode) => {
+                    if (processFinalCode) {
+                        migratedVertexCode = processFinalCode("vertex", migratedVertexCode);
+                    }
                     processorOptions.isFragment = true;
                     ShaderProcessor.Process(fragmentCode, processorOptions, (migratedFragmentCode) => {
+                        if (processFinalCode) {
+                            migratedFragmentCode = processFinalCode("fragment", migratedFragmentCode);
+                        }
                         this._useFinalCode(migratedVertexCode, migratedFragmentCode, baseName);
                     });
                 });

+ 11 - 1
src/Materials/material.ts

@@ -43,6 +43,16 @@ export interface IMaterialCompilationOptions {
 }
 
 /**
+ * Options passed when calling customShaderNameResolve
+ */
+export interface ICustomShaderNameResolveOptions {
+    /**
+     * If provided, will be called two times with the vertex and fragment code so that this code can be updated before it is compiled by the GPU
+     */
+    processFinalCode?: Nullable<(shaderType: string, code: string) => string>;
+}
+
+/**
  * Base class for the main features of a material in Babylon.js
  */
 export class Material implements IAnimatable {
@@ -147,7 +157,7 @@ export class Material implements IAnimatable {
     /**
      * Custom callback helping to override the default shader used in the material.
      */
-    public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: MaterialDefines | string[], attributes?: string[]) => string;
+    public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: MaterialDefines | string[], attributes?: string[], options?: ICustomShaderNameResolveOptions) => string;
 
     /**
      * Custom shadow depth material to use for shadow rendering instead of the in-built one

+ 6 - 3
src/Materials/standardMaterial.ts

@@ -15,7 +15,7 @@ import { Mesh } from "../Meshes/mesh";
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "./imageProcessingConfiguration";
 import { ColorCurves } from "./colorCurves";
 import { FresnelParameters } from "./fresnelParameters";
-import { Material } from "../Materials/material";
+import { Material, ICustomShaderNameResolveOptions } from "../Materials/material";
 import { MaterialDefines } from "../Materials/materialDefines";
 import { PushMaterial } from "./pushMaterial";
 import { MaterialHelper } from "./materialHelper";
@@ -1164,8 +1164,10 @@ export class StandardMaterial extends PushMaterial {
                 maxSimultaneousLights: this._maxSimultaneousLights
             });
 
+            const csnrOptions: ICustomShaderNameResolveOptions = {};
+
             if (this.customShaderNameResolve) {
-                shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs);
+                shaderName = this.customShaderNameResolve(shaderName, uniforms, uniformBuffers, samplers, defines, attribs, csnrOptions);
             }
 
             var join = defines.toString();
@@ -1180,7 +1182,8 @@ export class StandardMaterial extends PushMaterial {
                 fallbacks: fallbacks,
                 onCompiled: this.onCompiled,
                 onError: this.onError,
-                indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
+                indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS },
+                processFinalCode: csnrOptions.processFinalCode,
             }, engine);
 
             if (effect) {

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockAlbedoOpacity.fx

@@ -4,6 +4,7 @@ struct albedoOpacityOutParams
     float alpha;
 };
 
+#define pbr_inline
 void albedoOpacityBlock(
     const in vec4 vAlbedoColor,
 #ifdef ALBEDO

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockAlphaFresnel.fx

@@ -5,6 +5,7 @@
         float alpha;
     };
 
+    #define pbr_inline
     void alphaFresnelBlock(
         const in vec3 normalW,
         const in vec3 viewDirectionW,

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockAmbientOcclusion.fx

@@ -6,6 +6,7 @@ struct ambientOcclusionOutParams
 #endif
 };
 
+#define pbr_inline
 void ambientOcclusionBlock(
 #ifdef AMBIENT
     const in vec3 ambientOcclusionColorMap_,

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockAnisotropic.fx

@@ -10,6 +10,7 @@
     #endif
     };
 
+    #define pbr_inline
     void anisotropicBlock(
         const in vec3 vAnisotropy,
     #ifdef ANISOTROPIC_TEXTURE

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockClearcoat.fx

@@ -29,6 +29,7 @@ struct clearcoatOutParams
 };
 
 #ifdef CLEARCOAT
+    #define pbr_inline
     #define inline
     void clearcoatBlock(
         const in vec3 vPositionW,

+ 3 - 0
src/Shaders/ShadersInclude/pbrBlockReflection.fx

@@ -17,6 +17,7 @@
     #endif
     };
 
+    #define pbr_inline
     void createReflectionCoords(
         const in vec3 vPositionW,
         const in vec3 normalW,
@@ -52,6 +53,7 @@
         #endif
     }
 
+    #define pbr_inline
     #define inline
     void sampleReflectionTexture(
         const in float alphaG,
@@ -150,6 +152,7 @@
         environmentRadiance.rgb *= vReflectionColor.rgb;
     }
 
+    #define pbr_inline
     #define inline
     void reflectionBlock(
         const in vec3 vPositionW,

+ 3 - 2
src/Shaders/ShadersInclude/pbrBlockReflectivity.fx

@@ -17,6 +17,7 @@ struct reflectivityOutParams
 #endif
 };
 
+#define pbr_inline
 void reflectivityBlock(
     const in vec4 vReflectivityColor,
 #ifdef METALLICWORKFLOW
@@ -28,7 +29,7 @@ void reflectivityBlock(
     const in vec4 surfaceMetallicOrReflectivityColorMap,
 #endif
 #if defined(METALLICWORKFLOW) && defined(REFLECTIVITY)  && defined(AOSTOREINMETALMAPRED)
-    const in vec3 ambientOcclusionColor,
+    const in vec3 ambientOcclusionColorIn,
 #endif
 #ifdef MICROSURFACEMAP
     const in vec4 microSurfaceTexel,
@@ -49,7 +50,7 @@ void reflectivityBlock(
 
             #ifdef AOSTOREINMETALMAPRED
                 vec3 aoStoreInMetalMap = vec3(surfaceMetallicOrReflectivityColorMap.r, surfaceMetallicOrReflectivityColorMap.r, surfaceMetallicOrReflectivityColorMap.r);
-                outParams.ambientOcclusionColor = mix(ambientOcclusionColor, aoStoreInMetalMap, reflectivityInfos.z);
+                outParams.ambientOcclusionColor = mix(ambientOcclusionColorIn, aoStoreInMetalMap, vReflectivityInfos.z);
             #endif
 
             #ifdef METALLNESSSTOREINMETALMAPBLUE

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockSheen.fx

@@ -19,6 +19,7 @@
     #endif
     };
 
+    #define pbr_inline
     #define inline
     void sheenBlock(
         const in vec4 vSheenColor,

+ 1 - 0
src/Shaders/ShadersInclude/pbrBlockSubSurface.fx

@@ -25,6 +25,7 @@ struct subSurfaceOutParams
 };
 
 #ifdef SUBSURFACE
+    #define pbr_inline
     #define inline
     void subSurfaceBlock(
         const in vec3 vSubSurfaceIntensity,