Browse Source

Associated with #6012: export shaders + factorize transform block

David Catuhe 6 năm trước cách đây
mục cha
commit
2c316e037e

+ 1 - 1
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -17,7 +17,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps>
             Vertex: ["BonesBlock", "InstancesBlock", "MorphTargetsBlock"],
             Fragment: ["AlphaTestBlock", "ImageProcessingBlock", "RGBAMergerBlock", "RGBASplitterBlock", "TextureBlock", "LightBlock", "FogBlock"],
             Outputs: ["VertexOutputBlock", "FragmentOutputBlock"],
-            Math: ["AddBlock", "ClampBlock", "MultiplyBlock", "Vector2TransformBlock", "Vector3TransformBlock", "Vector4TransformBlock"],
+            Math: ["AddBlock", "ClampBlock", "MultiplyBlock", "VectorTransformBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "Matrix"],
         }
 

+ 6 - 0
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -5,6 +5,7 @@ import { Nullable } from 'babylonjs/types';
 import { DefaultNodeModel } from '../../components/diagram/defaultNodeModel';
 import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
 import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { StringTools } from '../../stringTools';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
@@ -65,6 +66,11 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                             this.props.globalState.onReOrganizedRequiredObservable.notifyObservers();
                         }} />
                     </LineContainerComponent>
+                    <LineContainerComponent title="FILE">
+                        <ButtonLineComponent label="Export shaders" onClick={() => {
+                            StringTools.DownloadAsFile(this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");
+                        }} />
+                    </LineContainerComponent>
                 </div>
             </div>
         );

+ 14 - 18
nodeEditor/src/graphEditor.tsx

@@ -44,9 +44,7 @@ import { FragmentOutputBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fr
 import { AddBlock } from 'babylonjs/Materials/Node/Blocks/addBlock';
 import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
 import { MultiplyBlock } from 'babylonjs/Materials/Node/Blocks/multiplyBlock';
-import { Vector2TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector2TransformBlock';
-import { Vector3TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector3TransformBlock';
-import { Vector4TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector4TransformBlock';
+import { VectorTransformBlock } from 'babylonjs/Materials/Node/Blocks/vectorTransformBlock';
 
 require("storm-react-diagrams/dist/style.min.css");
 require("./main.scss");
@@ -433,9 +431,10 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
 
     emitNewBlock(event: React.DragEvent<HTMLDivElement>) {
         var data = event.dataTransfer.getData("babylonjs-material-node") as string;
+        let nodeModel: Nullable<DefaultNodeModel> = null;
 
         if (data.indexOf("Block") === -1) {
-            this.addValueNode(data);
+            nodeModel = this.addValueNode(data);
         } else {
             let block: Nullable<NodeMaterialBlock> = null;
 
@@ -485,27 +484,24 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
                 case "MultiplyBlock":
                     block = new MultiplyBlock("Multiply");
                     break;
-                case "Vector2TransformBlock":
-                    block = new Vector2TransformBlock("Vector2Transform");
-                    break;
-                case "Vector3TransformBlock":
-                    block = new Vector3TransformBlock("Vector3Transform");
-                    break;
-                case "Vector4TransformBlock":
-                    block = new Vector4TransformBlock("Vector4Transform");
+                case "VectorTransformBlock":
+                    block = new VectorTransformBlock("VectorTransform");
                     break;
             }
 
             if (block) {
-                let nodeModel = this.createNodeFromObject({ nodeMaterialBlock: block });
-                const zoomLevel = this._engine.diagramModel.getZoomLevel() / 100.0;
-
-                let x = (event.clientX - event.currentTarget.offsetLeft - this._engine.diagramModel.getOffsetX()) / zoomLevel;
-                let y = (event.clientY - event.currentTarget.offsetTop - this._engine.diagramModel.getOffsetY()) / zoomLevel;
-                nodeModel.setPosition(x, y);
+                nodeModel = this.createNodeFromObject({ nodeMaterialBlock: block });
             }
         };
 
+        if (nodeModel) {
+            const zoomLevel = this._engine.diagramModel.getZoomLevel() / 100.0;
+
+            let x = (event.clientX - event.currentTarget.offsetLeft - this._engine.diagramModel.getOffsetX() - 100) / zoomLevel;
+            let y = (event.clientY - event.currentTarget.offsetTop - this._engine.diagramModel.getOffsetY() - 20) / zoomLevel;
+            nodeModel.setPosition(x, y);
+        }
+
         this.forceUpdate();
     }
 

+ 38 - 0
nodeEditor/src/stringTools.ts

@@ -22,4 +22,42 @@ export class StringTools {
             }
         }
     }
+
+    /**
+     * Download a string into a file that will be saved locally by the browser
+     * @param content defines the string to download locally as a file
+     */
+    public static DownloadAsFile(content: string, filename: string) {
+        let blob = new Blob([content],
+            {
+                type: "application/octet-stream"
+            });
+
+        if (window.navigator.msSaveOrOpenBlob) {
+            window.navigator.msSaveOrOpenBlob(blob, filename);
+            return;
+        }
+
+        var file = new Blob([content], { type: "application/octet-stream" });
+
+        var reader = new FileReader();
+        reader.onload = function(e) {
+            var bdata = btoa(reader.result as string);
+
+            var datauri = 'data:text/plain;base64,' + bdata;
+            setTimeout(() => {
+                let link = document.createElement("a");
+                link.setAttribute("href", datauri);
+                link.setAttribute("download", filename);
+                link.target = "_self";
+                link.style.visibility = 'hidden';
+                document.body.appendChild(link);
+                link.click();
+                setTimeout(function() {
+                    document.body.removeChild(link);
+                }, 0);
+            }, 10);
+        };
+        reader.readAsBinaryString(file);
+    }
 }

+ 0 - 3
src/Materials/Node/Blocks/Dual/textureBlock.ts

@@ -143,9 +143,6 @@ export class TextureBlock extends NodeMaterialBlock {
 
         state._emitUniformFromString(this._textureTransformName, "mat4", this._defineName);
 
-        if (state.sharedData.emitComments) {
-            state.compilationString += `\r\n//${this.name}\r\n`;
-        }
         state.compilationString += `#ifdef ${this._defineName}\r\n`;
         state.compilationString += `${this._transformedUVName} = vec2(${this._textureTransformName} * vec4(${uvInput.associatedVariableName}, 1.0, 0.0));\r\n`;
         state.compilationString += `#else\r\n`;

+ 5 - 0
src/Materials/Node/Blocks/Vertex/morphTargetsBlock.ts

@@ -217,9 +217,11 @@ export class MorphTargetsBlock extends NodeMaterialBlock {
         let position = this.position;
         let normal = this.normal;
         let tangent = this.tangent;
+        let uv = this.uv;
         let positionOutput = this.positionOutput;
         let normalOutput = this.normalOutput;
         let tangentOutput = this.tangentOutput;
+        let uvOutput = this.uvOutput;
         let comments = `//${this.name}`;
 
         state.uniforms.push("morphTargetInfluences");
@@ -236,6 +238,9 @@ export class MorphTargetsBlock extends NodeMaterialBlock {
         state.compilationString += `#ifdef TANGENT\r\n`;
         state.compilationString += `${this._declareOutput(tangentOutput, state)} = ${tangent.associatedVariableName};\r\n`;
         state.compilationString += `#endif\r\n`;
+        state.compilationString += `#ifdef UV1\r\n`;
+        state.compilationString += `${this._declareOutput(uvOutput, state)} = ${uv.associatedVariableName};\r\n`;
+        state.compilationString += `#endif\r\n`;
 
         // Repeatable content
         this._repeatableContentAnchor = state._repeatableContentAnchor;

+ 1 - 3
src/Materials/Node/Blocks/index.ts

@@ -5,6 +5,4 @@ export * from "./Input/index";
 export * from "./multiplyBlock";
 export * from "./addBlock";
 export * from "./clampBlock";
-export * from "./vector2TransformBlock";
-export * from "./vector3TransformBlock";
-export * from "./vector4TransformBlock";
+export * from "./vectorTransformBlock";

+ 0 - 73
src/Materials/Node/Blocks/vector2TransformBlock.ts

@@ -1,73 +0,0 @@
-import { NodeMaterialBlock } from '../nodeMaterialBlock';
-import { NodeMaterialBlockConnectionPointTypes } from '../nodeMaterialBlockConnectionPointTypes';
-import { NodeMaterialBuildState } from '../nodeMaterialBuildState';
-import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
-import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
-
-/**
- * Block used to transform a vector2 with a matrix
- */
-export class Vector2TransformBlock extends NodeMaterialBlock {
-    /**
-     * Defines the value to use to complement Vector2 to transform it to a Vector4
-     */
-    public complementZ = 1;
-
-    /**
-     * Defines the value to use to complement Vector2 to transform it to a Vector4
-     */
-    public complementW = 0;
-
-    /**
-     * Creates a new Vector2TransformBlock
-     * @param name defines the block name
-     */
-    public constructor(name: string) {
-        super(name, NodeMaterialBlockTargets.Neutral);
-
-        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.Vector2);
-        this.registerInput("transform", NodeMaterialBlockConnectionPointTypes.Matrix);
-        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector2);
-    }
-
-    /**
-     * Gets the vector input
-     */
-    public get vector(): NodeMaterialConnectionPoint {
-        return this._inputs[0];
-    }
-
-    /**
-     * Gets the matrix transform input
-     */
-    public get transform(): NodeMaterialConnectionPoint {
-        return this._inputs[1];
-    }
-
-    /**
-     * Gets the output component
-     */
-    public get output(): NodeMaterialConnectionPoint {
-        return this._outputs[0];
-    }
-
-    /**
-     * Gets the current class name
-     * @returns the class name
-     */
-    public getClassName() {
-        return "Vector2TransformBlock";
-    }
-
-    protected _buildBlock(state: NodeMaterialBuildState) {
-        super._buildBlock(state);
-
-        let output = this._outputs[0];
-        let vector = this.vector;
-        let transform = this.transform;
-
-        state.compilationString += this._declareOutput(output, state) + ` = vec2(${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this.complementZ}, ${this.complementW}));\r\n`;
-
-        return this;
-    }
-}

+ 0 - 68
src/Materials/Node/Blocks/vector3TransformBlock.ts

@@ -1,68 +0,0 @@
-import { NodeMaterialBlock } from '../nodeMaterialBlock';
-import { NodeMaterialBlockConnectionPointTypes } from '../nodeMaterialBlockConnectionPointTypes';
-import { NodeMaterialBuildState } from '../nodeMaterialBuildState';
-import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
-import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
-
-/**
- * Block used to transform a vector3 with a matrix
- */
-export class Vector3TransformBlock extends NodeMaterialBlock {
-    /**
-     * Defines the value to use to complement Vector3 to transform it to a Vector4
-     */
-    public complement = 1;
-
-    /**
-     * Creates a new Vector3TransformBlock
-     * @param name defines the block name
-     */
-    public constructor(name: string) {
-        super(name, NodeMaterialBlockTargets.Neutral);
-
-        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.Vector3);
-        this.registerInput("transform", NodeMaterialBlockConnectionPointTypes.Matrix);
-        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
-    }
-
-    /**
-     * Gets the vector input
-     */
-    public get vector(): NodeMaterialConnectionPoint {
-        return this._inputs[0];
-    }
-
-    /**
-     * Gets the matrix transform input
-     */
-    public get transform(): NodeMaterialConnectionPoint {
-        return this._inputs[1];
-    }
-
-    /**
-     * Gets the output component
-     */
-    public get output(): NodeMaterialConnectionPoint {
-        return this._outputs[0];
-    }
-
-    /**
-     * Gets the current class name
-     * @returns the class name
-     */
-    public getClassName() {
-        return "Vector3TransformBlock";
-    }
-
-    protected _buildBlock(state: NodeMaterialBuildState) {
-        super._buildBlock(state);
-
-        let output = this._outputs[0];
-        let vector = this.vector;
-        let transform = this.transform;
-
-        state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this.complement});\r\n`;
-
-        return this;
-    }
-}

+ 22 - 10
src/Materials/Node/Blocks/vector4TransformBlock.ts

@@ -5,22 +5,27 @@ import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
 import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
 
 /**
- * Block used to transform a vector4 with a matrix
+ * Block used to transform a vector (2, 3 or 4) with a matrix. It will generate a Vector4
  */
-export class Vector4TransformBlock extends NodeMaterialBlock {
+export class VectorTransformBlock extends NodeMaterialBlock {
     /**
-     * Defines the value to use to complement Vector3 to transform it to a Vector4
+     * Defines the value to use to complement W value to transform it to a Vector4
      */
     public complementW = 1;
 
     /**
-     * Creates a new Vector4TransformBlock
+     * Defines the value to use to complement z value to transform it to a Vector4
+     */
+    public complementZ = 0;
+
+    /**
+     * Creates a new VectorTransformBlock
      * @param name defines the block name
      */
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.Neutral);
 
-        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.Vector3OrVector4);
+        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.AutoDetect);
         this.registerInput("transform", NodeMaterialBlockConnectionPointTypes.Matrix);
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
     }
@@ -30,7 +35,7 @@ export class Vector4TransformBlock extends NodeMaterialBlock {
      * @returns the class name
      */
     public getClassName() {
-        return "Vector4TransformBlock";
+        return "VectorTransformBlock";
     }
 
     /**
@@ -61,10 +66,17 @@ export class Vector4TransformBlock extends NodeMaterialBlock {
         let vector = this.vector;
         let transform = this.transform;
 
-        if (vector.connectedPoint && vector.connectedPoint!.type === NodeMaterialBlockConnectionPointTypes.Vector3) {
-            state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
-        } else {
-            state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * ${vector.associatedVariableName};\r\n`;
+        if (vector.connectedPoint) {
+            switch (vector.connectedPoint.type) {
+                case NodeMaterialBlockConnectionPointTypes.Vector2:
+                    state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementZ)}, ${this._writeFloat(this.complementW)});\r\n`;
+                case NodeMaterialBlockConnectionPointTypes.Vector3:
+                    state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
+                    break;
+                default:
+                    state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * ${vector.associatedVariableName};\r\n`;
+                    break;
+            }
         }
 
         return this;

+ 12 - 8
src/Materials/Node/nodeMaterial.ts

@@ -19,7 +19,7 @@ import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } fr
 import { Nullable } from '../../types';
 import { VertexBuffer } from '../../Meshes/buffer';
 import { Tools } from '../../Misc/tools';
-import { Vector4TransformBlock } from './Blocks/vector4TransformBlock';
+import { VectorTransformBlock } from './Blocks/vectorTransformBlock';
 import { VertexOutputBlock } from './Blocks/Vertex/vertexOutputBlock';
 import { FragmentOutputBlock } from './Blocks/Fragment/fragmentOutputBlock';
 import { InputBlock } from './Blocks/Input/inputBlock';
@@ -515,15 +515,15 @@ export class NodeMaterial extends PushMaterial {
     }
 
     private _prepareDefinesForAttributes(mesh: AbstractMesh, defines: NodeMaterialDefines) {
-        if (!defines._areAttributesDirty && defines._needNormals === defines._normals && defines._needUVs === defines._uvs) {
+        if (!defines._areAttributesDirty) {
             return;
         }
 
-        defines._normals = defines._needNormals;
-        defines._uvs = defines._needUVs;
+        defines["NORMAL"] = mesh.isVerticesDataPresent(VertexBuffer.NormalKind);
 
-        defines.setValue("NORMAL", (defines._needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)));
-        defines.setValue("TANGENT", mesh.isVerticesDataPresent(VertexBuffer.TangentKind));
+        defines["TANGENT"] = mesh.isVerticesDataPresent(VertexBuffer.TangentKind);
+
+        defines["UV1"] = mesh.isVerticesDataPresent(VertexBuffer.UVKind);
     }
 
     /**
@@ -672,6 +672,10 @@ export class NodeMaterial extends PushMaterial {
         return true;
     }
 
+    public get compiledShaders() {
+        return `// Vertex shader\r\n${this._vertexCompilationState.compilationString}\r\n\r\n// Fragment shader\r\n${this._fragmentCompilationState.compilationString}`;
+    }
+
     /**
      * Binds the world matrix to the material
      * @param world defines the world transformation matrix
@@ -838,14 +842,14 @@ export class NodeMaterial extends PushMaterial {
         var worldInput = new InputBlock("world");
         worldInput.setAsWellKnownValue(BABYLON.NodeMaterialWellKnownValues.World);
 
-        var worldPos = new Vector4TransformBlock("worldPos");
+        var worldPos = new VectorTransformBlock("worldPos");
         positionInput.connectTo(worldPos);
         worldInput.connectTo(worldPos);
 
         var viewProjectionInput = new InputBlock("viewProjection");
         viewProjectionInput.setAsWellKnownValue(BABYLON.NodeMaterialWellKnownValues.ViewProjection);
 
-        var worldPosdMultipliedByViewProjection = new Vector4TransformBlock("worldPos * viewProjectionTransform");
+        var worldPosdMultipliedByViewProjection = new VectorTransformBlock("worldPos * viewProjectionTransform");
         worldPos.connectTo(worldPosdMultipliedByViewProjection);
         viewProjectionInput.connectTo(worldPosdMultipliedByViewProjection);