Prechádzať zdrojové kódy

Add native shader processor

Gary Hsu 6 rokov pred
rodič
commit
f7c88ff1b8

+ 95 - 0
src/Engines/Native/nativeShaderProcessor.ts

@@ -0,0 +1,95 @@
+import { WebGL2ShaderProcessor } from "../WebGL/webGL2ShaderProcessors";
+import { VertexBuffer } from "../../Meshes/buffer";
+
+// These must match the values for bgfx::Attrib::Enum
+const attributeLocations: { [kind: string]: number } = {
+    [VertexBuffer.PositionKind]: 0,
+    [VertexBuffer.NormalKind]: 1,
+    [VertexBuffer.TangentKind]: 2,
+    [VertexBuffer.UVKind]: 10,
+    [VertexBuffer.UV2Kind]: 11,
+    [VertexBuffer.ColorKind]: 4,
+    [VertexBuffer.MatricesIndicesKind]: 8,
+    [VertexBuffer.MatricesWeightsKind]: 9,
+};
+
+/** @hidden */
+export class NativeShaderProcessor extends WebGL2ShaderProcessor {
+    private _varyingLocationCount: number;
+    private _varyingLocationMap: { [name: string]: number };
+    private _replacements: Array<{ searchValue: RegExp, replaceValue: string }>;
+    private _textureCount: number;
+    private _uniforms: Array<string>;
+
+    public linePreProcessor(line: string): string {
+        for (const replacement of this._replacements) {
+            line = line.replace(replacement.searchValue, replacement.replaceValue);
+        }
+
+        return line;
+    }
+
+    public attributeProcessor(attribute: string): string {
+        const match = attribute.match(/attribute\s+\w+\s+(\w+)\s*;/)!;
+        const name = match[1];
+
+        const location = attributeLocations[name];
+        if (location === undefined) {
+            throw new Error(`Unsupported attribute ${name}`);
+        }
+
+        return `layout(location=${location}) ${super.attributeProcessor(attribute)}`;
+    }
+
+    public varyingProcessor(varying: string, isFragment: boolean): string {
+        let location: number;
+
+        if (isFragment) {
+            location = this._varyingLocationMap[varying];
+        }
+        else {
+            location = this._varyingLocationCount++;
+            this._varyingLocationMap[varying] = location;
+        }
+
+        return `layout(location=${location}) ${super.varyingProcessor(varying, isFragment)}`
+    }
+
+    public uniformProcessor(uniform: string): string {
+        const match = uniform.match(/uniform\s+(\w+)\s+(\w+)\s*;/)!;
+        const type = match[1];
+        const name = match[2];
+
+        switch (type) {
+            case "sampler2D":
+            case "samplerCube": {
+                const suffix = type.substr(7);
+                const binding = this._textureCount++;
+                this._replacements.push({ searchValue: new RegExp(`\\b${name}\\b`), replaceValue: `sampler${suffix}(${name}Texture, ${name})` });
+                return `layout(binding=${binding}) uniform texture${suffix} ${name}Texture;\nlayout(binding=${binding}) uniform sampler ${name};`;
+            }
+        }
+
+        this._uniforms.push(uniform);
+        return this._uniforms.length === 1 ? "<UNIFORM>" : "";
+    }
+
+    public preProcessor(code: string, defines: string[], isFragment: boolean): string {
+        if (!isFragment) {
+            this._varyingLocationCount = 0;
+            this._varyingLocationMap = {};
+        }
+
+        this._replacements = [];
+        this._textureCount = 0;
+        this._uniforms = [];
+        return code;
+    }
+
+   public postProcessor(code: string, defines: string[], isFragment: boolean): string {
+        code = super.postProcessor(code, defines, isFragment);
+        code = code.replace("<UNIFORM>", `uniform Frame {\n${this._uniforms.join("\n")}\n};`);
+        code = code.replace("out vec4 glFragColor", "layout(location=0) out vec4 glFragColor");
+        return code;
+    }
+}

+ 1 - 1
src/Engines/Processors/iShaderProcessor.ts

@@ -1,11 +1,11 @@
 /** @hidden */
 export interface IShaderProcessor {
+    linePreProcessor?: (line: string, isFragment: boolean) => string;
     attributeProcessor?: (attribute: string) => string;
     varyingProcessor?: (varying: string, isFragment: boolean) => string;
     uniformProcessor?: (uniform: string, isFragment: boolean) => string;
     uniformBufferProcessor?: (uniformBuffer: string, isFragment: boolean) => string;
     endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean) => string;
-    lineProcessor?: (line: string, isFragment: boolean) => string;
     preProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
     postProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
 }

+ 4 - 4
src/Engines/Processors/shaderCodeNode.ts

@@ -18,6 +18,10 @@ export class ShaderCodeNode {
             let value: string = this.line;
             let processor = options.processor;
             if (processor) {
+                if (processor.linePreProcessor) {
+                    value = processor.linePreProcessor(value, options.isFragment);
+                }
+
                 if (processor.attributeProcessor && Tools.StartsWith(this.line, "attribute")) {
                     value = processor.attributeProcessor(this.line);
                 } else if (processor.varyingProcessor && Tools.StartsWith(this.line, "varying")) {
@@ -43,10 +47,6 @@ export class ShaderCodeNode {
                         value = processor.endOfUniformBufferProcessor(this.line, options.isFragment);
                     }
                 }
-
-                if (processor.lineProcessor) {
-                    value = processor.lineProcessor(value, options.isFragment);
-                }
             }
 
             result += value + "\r\n";

+ 9 - 12
src/Engines/nativeEngine.ts

@@ -17,6 +17,7 @@ import { Scene } from "../scene";
 import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
 import { IPipelineContext } from './IPipelineContext';
 import { WebRequest } from '../Misc/webRequest';
+import { NativeShaderProcessor } from './Native/nativeShaderProcessor';
 
 interface INativeEngine {
     requestAnimationFrame(callback: () => void): void;
@@ -215,9 +216,11 @@ export class NativeEngine extends Engine {
 
         this._options = options;
 
-        // TODO: Initialize this more correctly based on the hardware capabilities reported by Spectre.
+        this._webGLVersion = 2;
+        this.disableUniformBuffers = true;
+
+        // TODO: Initialize this more correctly based on the hardware capabilities.
         // Init caps
-        // We consider we are on a webgl1 capable device
 
         this._caps = new EngineCapabilities();
         this._caps.maxTexturesImageUnits = 16;
@@ -273,6 +276,9 @@ export class NativeEngine extends Engine {
         if (typeof Blob === "undefined") {
             (window.Blob as any) = function() { };
         }
+
+        // Shader processor
+        this._shaderProcessor = new NativeShaderProcessor();
     }
 
     /**
@@ -486,18 +492,9 @@ export class NativeEngine extends Engine {
     }
 
     public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): any {
-        context = context || this._gl;
-
         this.onBeforeShaderCompilationObservable.notifyObservers(this);
-
-        const shaderVersion = (this._webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
-        const vertexShader = Engine._concatenateShader(vertexCode, defines, shaderVersion);
-        const fragmentShader = Engine._concatenateShader(fragmentCode, defines, shaderVersion);
-
-        const program = this._native.createProgram(vertexShader, fragmentShader);
-
+        const program = this._native.createProgram(vertexCode, fragmentCode);
         this.onAfterShaderCompilationObservable.notifyObservers(this);
-
         return program;
     }
 

+ 5 - 6
src/Shaders/ShadersInclude/bumpFragmentFunctions.fx

@@ -7,16 +7,15 @@
 		uniform mat4 normalMatrix;
 	#endif
 
-	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv, sampler2D textureSampler, float scale)
+	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv, vec3 textureSample, float scale)
 	{
-		vec3 map = texture2D(textureSampler, uv).xyz;
-		map = map * 2.0 - 1.0;
+		textureSample = textureSample * 2.0 - 1.0;
 
 		#ifdef NORMALXYSCALE
-			map = normalize(map * vec3(scale, scale, 1.0));
+			textureSample = normalize(textureSample * vec3(scale, scale, 1.0));
 		#endif
 
-		return normalize(cotangentFrame * map);
+		return normalize(cotangentFrame * textureSample);
 	}
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180
@@ -59,7 +58,7 @@
 
 	vec3 perturbNormal(mat3 cotangentFrame, vec2 uv)
 	{
-		return perturbNormal(cotangentFrame, uv, bumpSampler, vBumpInfos.y);
+		return perturbNormal(cotangentFrame, uv, texture2D(bumpSampler, uv).xyz, vBumpInfos.y);
 	}
 
 	// Thanks to http://www.thetenthplanet.de/archives/1180

+ 2 - 2
src/Shaders/ShadersInclude/pbrBRDFFunctions.fx

@@ -15,12 +15,12 @@
 #endif
 
 #ifdef ENVIRONMENTBRDF
-    vec3 getBRDFLookup(float NdotV, float perceptualRoughness, sampler2D brdfSampler) {
+    vec3 getBRDFLookup(float NdotV, float perceptualRoughness) {
         // Indexed on cos(theta) and roughness
         vec2 UV = vec2(NdotV, perceptualRoughness);
         
         // We can find the scale and offset to apply to the specular value.
-        vec4 brdfLookup = texture2D(brdfSampler, UV);
+        vec4 brdfLookup = texture2D(environmentBrdfSampler, UV);
 
         #ifdef ENVIRONMENTBRDF_RGBD
             brdfLookup.rgb = fromRGBD(brdfLookup.rgba);

+ 6 - 4
src/Shaders/pbr.fragment.fx

@@ -16,7 +16,7 @@ precision highp float;
 
 // Forces linear space for image processing
 #ifndef FROMLINEARSPACE
-    #define FROMLINEARSPACE;
+    #define FROMLINEARSPACE
 #endif
 
 // Declaration
@@ -34,7 +34,9 @@ precision highp float;
 #include<pbrHelperFunctions>
 #include<imageProcessingFunctions>
 #include<shadowsFragmentFunctions>
-#include<harmonicsFunctions>
+#ifndef USESPHERICALINVERTEX
+    #include<harmonicsFunctions>
+#endif
 #include<pbrDirectLightingSetupFunctions>
 #include<pbrDirectLightingFalloffFunctions>
 #include<pbrBRDFFunctions>
@@ -662,7 +664,7 @@ void main(void) {
                 clearCoatNormalW = normalize(texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset).xyz  * 2.0 - 1.0);
                 clearCoatNormalW = normalize(mat3(normalMatrix) * clearCoatNormalW);
             #else
-                clearCoatNormalW = perturbNormal(TBN, vClearCoatBumpUV + uvOffset, clearCoatBumpSampler, vClearCoatBumpInfos.y);
+                clearCoatNormalW = perturbNormal(TBN, vClearCoatBumpUV + uvOffset, texture2D(clearCoatBumpSampler, uv).xyz, vClearCoatBumpInfos.y);
             #endif
         #endif
 
@@ -768,7 +770,7 @@ void main(void) {
     // _____________________________ IBL BRDF + Energy Cons ________________________________
     #if defined(ENVIRONMENTBRDF)
         // BRDF Lookup
-        vec3 environmentBrdf = getBRDFLookup(NdotV, roughness, environmentBrdfSampler);
+        vec3 environmentBrdf = getBRDFLookup(NdotV, roughness);
 
         #ifdef MS_BRDF_ENERGY_CONSERVATION
             vec3 energyConservationFactor = getEnergyConservationFactor(specularEnvironmentR0, environmentBrdf);