|
@@ -5,29 +5,20 @@ import { AbstractMesh } from '../../Meshes/abstractMesh';
|
|
|
import { Matrix } from '../../Maths/math';
|
|
|
import { Mesh } from '../../Meshes/mesh';
|
|
|
import { Engine } from '../../Engines/engine';
|
|
|
-import { NodeMaterialCompilationState } from './nodeMaterialCompilationState';
|
|
|
-import { EffectCreationOptions } from '../effect';
|
|
|
+import { NodeMaterialBuildState } from './nodeMaterialBuildState';
|
|
|
+import { EffectCreationOptions, EffectFallbacks } from '../effect';
|
|
|
import { BaseTexture } from '../../Materials/Textures/baseTexture';
|
|
|
import { NodeMaterialConnectionPoint } from './nodeMaterialBlockConnectionPoint';
|
|
|
import { NodeMaterialBlockConnectionPointTypes } from './nodeMaterialBlockConnectionPointTypes';
|
|
|
import { Observable } from '../../Misc/observable';
|
|
|
import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
|
|
|
-import { NodeMaterialCompilationStateSharedData } from './nodeMaterialCompilationStateSharedData';
|
|
|
+import { NodeMaterialBuildStateSharedData } from './NodeMaterialBuildStateSharedData';
|
|
|
|
|
|
/**
|
|
|
* Class used to configure NodeMaterial
|
|
|
*/
|
|
|
export interface INodeMaterialOptions {
|
|
|
/**
|
|
|
- * Defines if the material needs alpha blending
|
|
|
- */
|
|
|
- needAlphaBlending: boolean;
|
|
|
- /**
|
|
|
- * Defines if the material needs alpha testing
|
|
|
- */
|
|
|
- needAlphaTesting: boolean;
|
|
|
-
|
|
|
- /**
|
|
|
* Defines if blocks should emit comments
|
|
|
*/
|
|
|
emitComments: boolean;
|
|
@@ -38,8 +29,8 @@ export interface INodeMaterialOptions {
|
|
|
*/
|
|
|
export class NodeMaterial extends Material {
|
|
|
private _options: INodeMaterialOptions;
|
|
|
- private _vertexCompilationState: NodeMaterialCompilationState;
|
|
|
- private _fragmentCompilationState: NodeMaterialCompilationState;
|
|
|
+ private _vertexCompilationState: NodeMaterialBuildState;
|
|
|
+ private _fragmentCompilationState: NodeMaterialBuildState;
|
|
|
private _buildId: number = 0;
|
|
|
private _renderId: number;
|
|
|
private _effectCompileId: number = 0;
|
|
@@ -81,8 +72,6 @@ export class NodeMaterial extends Material {
|
|
|
super(name, scene || Engine.LastCreatedScene!);
|
|
|
|
|
|
this._options = {
|
|
|
- needAlphaBlending: false,
|
|
|
- needAlphaTesting: false,
|
|
|
emitComments: false,
|
|
|
...options
|
|
|
};
|
|
@@ -187,7 +176,7 @@ export class NodeMaterial extends Material {
|
|
|
* @returns a boolean specifying if alpha blending is needed
|
|
|
*/
|
|
|
public needAlphaBlending(): boolean {
|
|
|
- return (this.alpha < 1.0) || this._options.needAlphaBlending;
|
|
|
+ return (this.alpha < 1.0) || this._fragmentCompilationState.sharedData.hints.needAlphaBlending;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -195,16 +184,17 @@ export class NodeMaterial extends Material {
|
|
|
* @returns a boolean specifying if an alpha test is needed.
|
|
|
*/
|
|
|
public needAlphaTesting(): boolean {
|
|
|
- return this._options.needAlphaTesting;
|
|
|
+ return this._fragmentCompilationState.sharedData.hints.needAlphaTesting;
|
|
|
}
|
|
|
|
|
|
- private _propagateTarget(node: NodeMaterialBlock, target: NodeMaterialBlockTargets) {
|
|
|
+ private _propagateTarget(node: NodeMaterialBlock, target: NodeMaterialBlockTargets, state: NodeMaterialBuildState) {
|
|
|
node.target = target;
|
|
|
+ node.initialize(state);
|
|
|
|
|
|
for (var exitPoint of node.outputs) {
|
|
|
for (var block of exitPoint.connectedBlocks) {
|
|
|
if (block) {
|
|
|
- this._propagateTarget(block, target);
|
|
|
+ this._propagateTarget(block, target, state);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -237,34 +227,36 @@ export class NodeMaterial extends Material {
|
|
|
throw "You must define at least one fragmentRootNode";
|
|
|
}
|
|
|
|
|
|
+ // Compilation state
|
|
|
+ this._vertexCompilationState = new NodeMaterialBuildState();
|
|
|
+ this._vertexCompilationState.target = NodeMaterialBlockTargets.Vertex;
|
|
|
+ this._fragmentCompilationState = new NodeMaterialBuildState();
|
|
|
+ this._fragmentCompilationState.target = NodeMaterialBlockTargets.Fragment;
|
|
|
+
|
|
|
+ // Shared data
|
|
|
+ let sharedData = new NodeMaterialBuildStateSharedData();
|
|
|
+ this._vertexCompilationState.sharedData = sharedData;
|
|
|
+ this._fragmentCompilationState.sharedData = sharedData;
|
|
|
+ sharedData.buildId = this._buildId;
|
|
|
+ sharedData.emitComments = this._options.emitComments;
|
|
|
+ sharedData.verbose = verbose;
|
|
|
+
|
|
|
// Propagate targets
|
|
|
for (var vertexRootNode of this._vertexRootNodes) {
|
|
|
- this._propagateTarget(vertexRootNode, NodeMaterialBlockTargets.Vertex);
|
|
|
+ this._propagateTarget(vertexRootNode, NodeMaterialBlockTargets.Vertex, this._vertexCompilationState);
|
|
|
}
|
|
|
|
|
|
for (var fragmentRootNode of this._fragmentRootNodes) {
|
|
|
- this._propagateTarget(fragmentRootNode, NodeMaterialBlockTargets.Fragment);
|
|
|
+ this._propagateTarget(fragmentRootNode, NodeMaterialBlockTargets.Fragment, this._fragmentCompilationState);
|
|
|
}
|
|
|
|
|
|
// Vertex
|
|
|
- this._vertexCompilationState = new NodeMaterialCompilationState();
|
|
|
- this._vertexCompilationState.target = NodeMaterialBlockTargets.Vertex;
|
|
|
- this._fragmentCompilationState = new NodeMaterialCompilationState();
|
|
|
- let sharedData = new NodeMaterialCompilationStateSharedData();
|
|
|
- this._vertexCompilationState.sharedData = sharedData;
|
|
|
- this._fragmentCompilationState.sharedData = sharedData;
|
|
|
- sharedData.buildId = this._buildId;
|
|
|
- sharedData.emitComments = this._options.emitComments;
|
|
|
- sharedData.verbose = verbose;
|
|
|
-
|
|
|
for (var vertexRootNode of this._vertexRootNodes) {
|
|
|
vertexRootNode.build(this._vertexCompilationState);
|
|
|
}
|
|
|
|
|
|
// Fragment
|
|
|
- this._fragmentCompilationState.target = NodeMaterialBlockTargets.Fragment;
|
|
|
this._fragmentCompilationState._vertexState = this._vertexCompilationState;
|
|
|
- this._fragmentCompilationState._uniformConnectionPoints = this._vertexCompilationState._uniformConnectionPoints;
|
|
|
|
|
|
for (var fragmentRootNode of this._fragmentRootNodes) {
|
|
|
this._resetDualBlocks(fragmentRootNode, this._buildId - 1);
|
|
@@ -279,7 +271,7 @@ export class NodeMaterial extends Material {
|
|
|
this._fragmentCompilationState.finalize(this._fragmentCompilationState);
|
|
|
|
|
|
// Textures
|
|
|
- this._textureConnectionPoints = this._fragmentCompilationState._uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture);
|
|
|
+ this._textureConnectionPoints = sharedData.uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture);
|
|
|
|
|
|
this._buildId++;
|
|
|
|
|
@@ -305,6 +297,8 @@ export class NodeMaterial extends Material {
|
|
|
public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
|
|
|
var scene = this.getScene();
|
|
|
var engine = scene.getEngine();
|
|
|
+ let defines: string[] = [];
|
|
|
+ var fallbacks = new EffectFallbacks();
|
|
|
|
|
|
if (!this.checkReadyOnEveryCall) {
|
|
|
if (this._renderId === scene.getRenderId()) {
|
|
@@ -349,10 +343,39 @@ export class NodeMaterial extends Material {
|
|
|
if (index === -1) {
|
|
|
mergedSamplers.push(s);
|
|
|
}
|
|
|
-
|
|
|
});
|
|
|
|
|
|
+ // Bones
|
|
|
+ if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
|
|
|
+ const skeleton = mesh.skeleton;
|
|
|
+
|
|
|
+ defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
|
|
|
+ fallbacks.addCPUSkinningFallback(0, mesh);
|
|
|
+
|
|
|
+ if (skeleton.isUsingTextureForMatrices) {
|
|
|
+ defines.push("#define BONETEXTURE");
|
|
|
+
|
|
|
+ if (mergedUniforms.indexOf("boneTextureWidth") === -1) {
|
|
|
+ mergedUniforms.push("boneTextureWidth");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mergedSamplers.indexOf("boneSampler") === -1) {
|
|
|
+ mergedSamplers.push("boneSampler");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ defines.push("#define BonesPerMesh " + (skeleton.bones.length + 1));
|
|
|
+
|
|
|
+ if (mergedUniforms.indexOf("mBones") === -1) {
|
|
|
+ mergedUniforms.push("mBones");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ defines.push("#define NUM_BONE_INFLUENCERS 0");
|
|
|
+ }
|
|
|
+
|
|
|
// Compilation
|
|
|
+ var join = defines.join("\n");
|
|
|
this._effect = engine.createEffect({
|
|
|
vertex: "nodeMaterial" + this._buildId,
|
|
|
fragment: "nodeMaterial" + this._buildId,
|
|
@@ -361,8 +384,9 @@ export class NodeMaterial extends Material {
|
|
|
}, <EffectCreationOptions>{
|
|
|
attributes: this._vertexCompilationState.attributes,
|
|
|
uniformsNames: mergedUniforms,
|
|
|
- samplers: this._fragmentCompilationState.samplers,
|
|
|
- defines: "",
|
|
|
+ samplers: mergedSamplers,
|
|
|
+ defines: join,
|
|
|
+ fallbacks: fallbacks,
|
|
|
onCompiled: this.onCompiled,
|
|
|
onError: this.onError
|
|
|
}, engine);
|
|
@@ -417,8 +441,9 @@ export class NodeMaterial extends Material {
|
|
|
// Std values
|
|
|
this.bindOnlyWorldMatrix(world);
|
|
|
|
|
|
+ let sharedData = this._fragmentCompilationState.sharedData;
|
|
|
if (this._effect && scene.getCachedMaterial() !== this) {
|
|
|
- let hints = this._fragmentCompilationState.sharedData.hints;
|
|
|
+ let hints = sharedData.hints;
|
|
|
|
|
|
if (hints.needViewMatrix) {
|
|
|
this._effect.setMatrix("view", scene.getViewMatrix());
|
|
@@ -440,9 +465,15 @@ export class NodeMaterial extends Material {
|
|
|
this._effect.setFloat4("fogParameters", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
|
|
|
}
|
|
|
|
|
|
- for (var connectionPoint of this._fragmentCompilationState._uniformConnectionPoints) {
|
|
|
+ // Connection points
|
|
|
+ for (var connectionPoint of sharedData.uniformConnectionPoints) {
|
|
|
connectionPoint.transmit(this._effect);
|
|
|
}
|
|
|
+
|
|
|
+ // Bindable blocks
|
|
|
+ for (var block of sharedData.activeBlocks) {
|
|
|
+ block.bind(this._effect, mesh);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
this._afterBind(mesh);
|