|
@@ -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;
|
|
|
}
|
|
|
}
|