瀏覽代碼

Associated with #6012

David Catuhe 6 年之前
父節點
當前提交
74aa0ad5a1

+ 71 - 39
src/Materials/Node/Blocks/Dual/lightBlock.ts

@@ -26,7 +26,7 @@ export class LightBlock extends NodeMaterialBlock {
         this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Vertex);
         this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Vertex);
 
-        this.registerInput("light", NodeMaterialBlockConnectionPointTypes.Light, false, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("light", NodeMaterialBlockConnectionPointTypes.Light, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("cameraPosition", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("specularOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -55,7 +55,8 @@ export class LightBlock extends NodeMaterialBlock {
     }
 
     /**
-    * Gets the light input component
+    * Gets the light input component.
+    * If not defined, all lights will be considered
     */
     public get light(): NodeMaterialConnectionPoint {
         return this._inputs[2];
@@ -89,31 +90,48 @@ export class LightBlock extends NodeMaterialBlock {
     }
 
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        const scene = mesh.getScene();
+
         if (!this.light.value) {
-            return;
+            MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, true, nodeMaterial.maxSimultaneousLights);
+        } else {
+            let state = {
+                needNormals: false,
+                needRebuild: false,
+                lightmapMode: false,
+                shadowEnabled: false,
+                specularEnabled: false
+            };
+
+            MaterialHelper.PrepareDefinesForLight(scene, mesh, this.light.value, this._lightId, defines, true, state);
+
+            if (state.needRebuild) {
+                defines.rebuild();
+            }
         }
+    }
 
-        let state = {
-            needNormals: false,
-            needRebuild: false,
-            lightmapMode: false,
-            shadowEnabled: false,
-            specularEnabled: false
-        };
-
-        MaterialHelper.PrepareDefinesForLight(mesh.getScene(), mesh, this.light.value, this._lightId, defines, true, state);
-
-        if (state.needRebuild) {
-            defines.rebuild();
+    public updateUniformsAndSamples(state: NodeMaterialBuildState, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        for (var lightIndex = 0; lightIndex < nodeMaterial.maxSimultaneousLights; lightIndex++) {
+            if (!defines["LIGHT" + lightIndex]) {
+                break;
+            }
+            MaterialHelper.PrepareUniformsAndSamplersForLight(lightIndex, state.uniforms, state.samplers, false, state.uniformBuffers);
         }
     }
 
     public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
-        if (!mesh || !this.light.value) {
+        if (!mesh) {
             return;
         }
 
-        MaterialHelper.BindLight(this.light.value, this._lightId, mesh.getScene(), mesh, effect, true, false);
+        const scene = mesh.getScene();
+
+        if (!this.light.value) {
+            MaterialHelper.BindLights(scene, mesh, effect, true, nodeMaterial.maxSimultaneousLights, false);
+        } else {
+            MaterialHelper.BindLight(this.light.value, this._lightId, scene, mesh, effect, true, false);
+        }
     }
 
     private _injectVertexCode(state: NodeMaterialBuildState) {
@@ -145,26 +163,34 @@ export class LightBlock extends NodeMaterialBlock {
         state.sharedData.bindableBlocks.push(this);
         state.sharedData.blocksWithDefines.push(this);
 
-        this._lightId = (state.counters["lightCounter"] !== undefined ? state.counters["lightCounter"] : -1) + 1;
-        state.counters["lightCounter"] = this._lightId;
-
         let comments = `//${this.name}`;
         let worldPos = this.worldPosition;
-        let worldNormal = this.worldNormal;
 
         state._emitFunctionFromInclude("lightsFragmentFunctions", comments, {
             replaceStrings: [
-                { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName },
-                { search: /normalW/g, replace: "v_" + worldNormal.associatedVariableName }
+                { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName }
             ]
         });
 
-        state._emitFunctionFromInclude(state.supportUniformBuffers ? "lightUboDeclaration" : "lightFragmentDeclaration", comments, {
-            replaceStrings: [{ search: /{X}/g, replace: this._lightId.toString() }]
-        }, this._lightId.toString());
+        if (!this.light.value) { // Emit for all lights
+            state._emitFunctionFromInclude(state.supportUniformBuffers ? "lightUboDeclaration" : "lightFragmentDeclaration", comments, {
+                repeatKey: "maxSimultaneousLights"
+            });
+            this._lightId = 0;
 
-        // Uniforms and samplers
-        MaterialHelper.PrepareUniformsAndSamplersForLight(this._lightId, state.uniforms, state.samplers, undefined, state.uniformBuffers);
+            state.sharedData.dynamicUniformBlocks.push(this);
+        } else {
+
+            this._lightId = (state.counters["lightCounter"] !== undefined ? state.counters["lightCounter"] : -1) + 1;
+            state.counters["lightCounter"] = this._lightId;
+
+            state._emitFunctionFromInclude(state.supportUniformBuffers ? "lightUboDeclaration" : "lightFragmentDeclaration", comments, {
+                replaceStrings: [{ search: /{X}/g, replace: this._lightId.toString() }]
+            }, this._lightId.toString());
+
+            // Uniforms and samplers
+            MaterialHelper.PrepareUniformsAndSamplersForLight(this._lightId, state.uniforms, state.samplers, undefined, state.uniformBuffers);
+        }
 
         // Code
         if (this._lightId === 0) {
@@ -172,25 +198,31 @@ export class LightBlock extends NodeMaterialBlock {
             state.compilationString += `lightingInfo info;\r\n`;
             state.compilationString += `float shadow = 1.;\r\n`;
             state.compilationString += `float glossiness = 0.;\r\n`;
+            state.compilationString += `vec3 diffuseBase = vec3(0., 0., 0.);\r\n`;
+            state.compilationString += `vec3 specularBase = vec3(0., 0., 0.);\r\n`;
+            state.compilationString += `vec3 normalW = v_${this.worldNormal.associatedVariableName};\r\n`;
+        }
+
+        if (this.light.value) {
+            state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
+                replaceStrings: [
+                    { search: /{X}/g, replace: this._lightId.toString() }
+                ]
+            });
+        } else {
+            state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
+                repeatKey: "maxSimultaneousLights"
+            });
         }
 
         let diffuseOutput = this.diffuseOutput;
         let specularOutput = this.specularOutput;
 
-        state.compilationString += `vec3 ${diffuseOutput.associatedVariableName} = vec3(0., 0., 0.);\r\n`;
+        state.compilationString += this._declareOutput(diffuseOutput, state) + ` = diffuseBase;\r\n`;
         state.compilationString += `#ifdef SPECULARTERM\r\n`;
-        state.compilationString += `vec3 ${specularOutput.associatedVariableName} = vec3(0., 0., 0.);\r\n`;
+        state.compilationString += this._declareOutput(specularOutput, state) + ` = specularBase;\r\n`;
         state.compilationString += `#endif\r\n`;
 
-        state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
-            replaceStrings: [
-                { search: /{X}/g, replace: this._lightId.toString() },
-                { search: /diffuseBase/g, replace: diffuseOutput.associatedVariableName },
-                { search: /specularBase/g, replace: specularOutput.associatedVariableName },
-                { search: /normalW/g, replace: "v_" + worldNormal.associatedVariableName }
-            ]
-        });
-
         return this;
     }
 }

+ 4 - 0
src/Materials/Node/nodeMaterial.ts

@@ -571,6 +571,10 @@ export class NodeMaterial extends PushMaterial {
             });
 
             // Uniforms
+            this._sharedData.dynamicUniformBlocks.forEach((b) => {
+                b.updateUniformsAndSamples(this._vertexCompilationState, this, defines);
+            });
+
             let mergedUniforms = this._vertexCompilationState.uniforms;
 
             this._fragmentCompilationState.uniforms.forEach((u) => {

+ 10 - 0
src/Materials/Node/nodeMaterialBlock.ts

@@ -269,6 +269,16 @@ export class NodeMaterialBlock {
     }
 
     /**
+     * Add uniforms, samplers and uniform buffers at compilation time
+     * @param state defines the state to update
+     * @param nodeMaterial defines the node material requesting the update
+     * @param defines defines the material defines to update
+     */
+    public updateUniformsAndSamples(state: NodeMaterialBuildState, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        // Do nothing
+    }
+
+    /**
      * Add potential fallbacks if shader compilation fails
      * @param mesh defines the mesh to be rendered
      * @param fallbacks defines the current prioritized list of fallbacks

+ 5 - 0
src/Materials/Node/nodeMaterialBuildState.ts

@@ -189,7 +189,12 @@ export class NodeMaterialBuildState {
     /** @hidden */
     public _emitCodeFromInclude(includeName: string, comments: string, options?: {
         replaceStrings?: { search: RegExp, replace: string }[],
+        repeatKey?: string
     }) {
+        if (options && options.repeatKey) {
+            return `#include<${includeName}>[0..${options.repeatKey}]\r\n`;
+        }
+
         let code = Effect.IncludesShadersStore[includeName] + "\r\n";
 
         if (this.sharedData.emitComments) {

+ 7 - 0
src/Materials/Node/nodeMaterialBuildStateSharedData.ts

@@ -41,6 +41,11 @@ export class NodeMaterialBuildStateSharedData {
     public repeatableContentBlocks = new Array<NodeMaterialBlock>();
 
     /**
+    * List of blocks that can provide a dynamic list of uniforms
+    */
+    public dynamicUniformBlocks = new Array<NodeMaterialBlock>();
+
+    /**
      * List of blocks that can block the isReady function for the material
      */
     public blockingBlocks = new Array<NodeMaterialBlock>();
@@ -99,6 +104,8 @@ export class NodeMaterialBuildStateSharedData {
         this.variableNames["matricesWeights"] = 0;
         this.variableNames["matricesIndicesExtra"] = 0;
         this.variableNames["matricesWeightsExtra"] = 0;
+        this.variableNames["diffuseBase"] = 0;
+        this.variableNames["specularBase"] = 0;
 
         // Exclude defines
         this.defineNames["MAINUV0"] = 0;

+ 1 - 1
src/Materials/materialHelper.ts

@@ -719,7 +719,7 @@ export class MaterialHelper {
         for (var i = 0; i < len; i++) {
 
             let light = mesh.lightSources[i];
-            this.BindLight(light, i, scene, mesh, effect, defines, usePhysicalLightFalloff);
+            this.BindLight(light, i, scene, mesh, effect, typeof defines === "boolean" ? defines : defines["SPECULAR"], usePhysicalLightFalloff);
         }
     }