Quellcode durchsuchen

TSL: Editor (GLSL) (#26283)

* Added GLSLNodeBuilder

* WebGLNodeBuilder: Fix redefinitions

* update

* add preview option

* improve styles variables
sunag vor 2 Jahren
Ursprung
Commit
e2d1338067

+ 2 - 1
examples/jsm/nodes/accessors/CameraNode.js

@@ -1,5 +1,6 @@
 import Object3DNode from './Object3DNode.js';
 import { addNodeClass } from '../core/Node.js';
+import { label } from '../core/ContextNode.js';
 import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class CameraNode extends Object3DNode {
@@ -86,7 +87,7 @@ CameraNode.FAR = 'far';
 
 export default CameraNode;
 
-export const cameraProjectionMatrix = nodeImmutable( CameraNode, CameraNode.PROJECTION_MATRIX );
+export const cameraProjectionMatrix = label( nodeImmutable( CameraNode, CameraNode.PROJECTION_MATRIX ), 'projectionMatrix' );
 export const cameraNear = nodeImmutable( CameraNode, CameraNode.NEAR );
 export const cameraFar = nodeImmutable( CameraNode, CameraNode.FAR );
 export const cameraViewMatrix = nodeImmutable( CameraNode, CameraNode.VIEW_MATRIX );

+ 2 - 1
examples/jsm/nodes/accessors/ModelNode.js

@@ -1,5 +1,6 @@
 import Object3DNode from './Object3DNode.js';
 import { addNodeClass } from '../core/Node.js';
+import { label } from '../core/ContextNode.js';
 import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class ModelNode extends Object3DNode {
@@ -23,7 +24,7 @@ class ModelNode extends Object3DNode {
 export default ModelNode;
 
 export const modelDirection = nodeImmutable( ModelNode, ModelNode.DIRECTION );
-export const modelViewMatrix = nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX );
+export const modelViewMatrix = label( nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX ), 'modelViewMatrix' );
 export const modelNormalMatrix = nodeImmutable( ModelNode, ModelNode.NORMAL_MATRIX );
 export const modelWorldMatrix = nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX );
 export const modelPosition = nodeImmutable( ModelNode, ModelNode.POSITION );

+ 334 - 0
examples/jsm/renderers/webgl/nodes/GLSLNodeBuilder.js

@@ -0,0 +1,334 @@
+import { MathNode, GLSLNodeParser, NodeBuilder, NodeMaterial } from 'three/nodes';
+
+const glslMethods = {
+	[ MathNode.ATAN2 ]: 'atan'
+};
+
+const precisionLib = {
+	low: 'lowp',
+	medium: 'mediump',
+	high: 'highp'
+};
+
+class GLSLNodeBuilder extends NodeBuilder {
+
+	constructor( object, renderer ) {
+
+		super( object, renderer, new GLSLNodeParser() );
+
+	}
+
+	getMethod( method ) {
+
+		return glslMethods[ method ] || method;
+
+	}
+
+	getTexture( texture, textureProperty, uvSnippet ) {
+
+		if ( texture.isTextureCube ) {
+
+			return `textureCube( ${textureProperty}, ${uvSnippet} )`;
+
+		} else {
+
+			return `texture2D( ${textureProperty}, ${uvSnippet} )`;
+
+		}
+
+	}
+
+	getTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) {
+
+		if ( this.material.extensions !== undefined ) this.material.extensions.shaderTextureLOD = true;
+
+		return `textureLod( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
+
+	}
+
+	getVars( shaderStage ) {
+
+		const snippets = [];
+
+		const vars = this.vars[ shaderStage ];
+
+		for ( const variable of vars ) {
+
+			snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
+
+		}
+
+		return snippets.join( '\n\t' );
+
+	}
+
+	getUniforms( shaderStage ) {
+
+		const uniforms = this.uniforms[ shaderStage ];
+
+		let output = '';
+
+		for ( const uniform of uniforms ) {
+
+			let snippet = null;
+
+			if ( uniform.type === 'texture' ) {
+
+				snippet = `sampler2D ${uniform.name};\n`;
+
+			} else if ( uniform.type === 'cubeTexture' ) {
+
+				snippet = `samplerCube ${uniform.name};\n`;
+
+			} else {
+
+				const vectorType = this.getVectorType( uniform.type );
+
+				snippet = `${vectorType} ${uniform.name};\n`;
+
+			}
+
+			const precision = uniform.node.precision;
+
+			if ( precision !== null ) {
+
+				snippet = 'uniform ' + precisionLib[ precision ] + ' ' + snippet;
+
+			} else {
+
+				snippet = 'uniform ' + snippet;
+
+			}
+
+			output += snippet;
+
+		}
+
+		return output;
+
+	}
+
+	getAttributes( shaderStage ) {
+
+		let snippet = '';
+
+		if ( shaderStage === 'vertex' ) {
+
+			const attributes = this.attributes;
+
+			for ( const attribute of attributes ) {
+
+				snippet += `attribute ${attribute.type} ${attribute.name};\n`;
+
+			}
+
+		}
+
+		return snippet;
+
+	}
+
+	getVaryings( shaderStage ) {
+
+		let snippet = '';
+
+		const varyings = this.varyings;
+
+		if ( shaderStage === 'vertex' ) {
+
+			for ( const varying of varyings ) {
+
+				snippet += `${varying.needsInterpolation ? 'varying' : '/*varying*/'} ${varying.type} ${varying.name};\n`;
+
+			}
+
+		} else if ( shaderStage === 'fragment' ) {
+
+			for ( const varying of varyings ) {
+
+				if ( varying.needsInterpolation ) {
+
+					snippet += `varying ${varying.type} ${varying.name};\n`;
+
+				}
+
+			}
+
+		}
+
+		return snippet;
+
+	}
+
+	getFrontFacing() {
+
+		return 'gl_FrontFacing';
+
+	}
+
+	getFragCoord() {
+
+		return 'gl_FragCoord';
+
+	}
+
+	isFlipY() {
+
+		return true;
+
+	}
+
+	_getGLSLVertexCode( shaderData ) {
+
+		return `${ this.getSignature() }
+
+// uniforms
+${shaderData.uniforms}
+
+// varyings
+${shaderData.varyings}
+
+// attributes
+${shaderData.attributes}
+
+// codes
+${shaderData.codes}
+
+void main() {
+
+	// vars
+	${shaderData.vars}
+
+	// flow
+	${shaderData.flow}
+
+}
+`;
+
+	}
+
+	_getGLSLFragmentCode( shaderData ) {
+
+		return `${ this.getSignature() }
+
+// precision
+precision highp float;
+precision highp int;
+
+// uniforms
+${shaderData.uniforms}
+
+// varyings
+${shaderData.varyings}
+
+// codes
+${shaderData.codes}
+
+void main() {
+
+	// vars
+	${shaderData.vars}
+
+	// flow
+	${shaderData.flow}
+
+}
+`;
+
+	}
+
+	buildCode() {
+
+		const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} };
+
+		for ( const shaderStage in shadersData ) {
+
+			let flow = '// code\n\n';
+			flow += this.flowCode[ shaderStage ];
+
+			const flowNodes = this.flowNodes[ shaderStage ];
+			const mainNode = flowNodes[ flowNodes.length - 1 ];
+
+			for ( const node of flowNodes ) {
+
+				const flowSlotData = this.getFlowData( node/*, shaderStage*/ );
+				const slotName = node.name;
+
+				if ( slotName ) {
+
+					if ( flow.length > 0 ) flow += '\n';
+
+					flow += `\t// flow -> ${ slotName }\n\t`;
+
+				}
+
+				flow += `${ flowSlotData.code }\n\t`;
+
+				if ( node === mainNode && shaderStage !== 'compute' ) {
+
+					flow += '// result\n\t';
+
+					if ( shaderStage === 'vertex' ) {
+
+						flow += 'gl_Position = ';
+
+					} else if ( shaderStage === 'fragment' ) {
+
+						flow += 'gl_FragColor = ';
+
+					}
+
+					flow += `${ flowSlotData.result };`;
+
+				}
+
+			}
+
+			const stageData = shadersData[ shaderStage ];
+
+			stageData.uniforms = this.getUniforms( shaderStage );
+			stageData.attributes = this.getAttributes( shaderStage );
+			stageData.varyings = this.getVaryings( shaderStage );
+			stageData.vars = this.getVars( shaderStage );
+			stageData.codes = this.getCodes( shaderStage );
+			stageData.flow = flow;
+
+		}
+
+		if ( this.material !== null ) {
+
+			this.vertexShader = this._getGLSLVertexCode( shadersData.vertex );
+			this.fragmentShader = this._getGLSLFragmentCode( shadersData.fragment );
+
+		} else {
+
+			console.warn( 'GLSLNodeBuilder: compute shaders are not supported.' );
+			//this.computeShader = this._getGLSLComputeCode( shadersData.compute );
+
+		}
+
+	}
+
+	build() {
+
+		// @TODO: Move this code to super.build()
+
+		const { object, material } = this;
+
+		if ( material !== null ) {
+
+			NodeMaterial.fromMaterial( material ).build( this );
+
+		} else {
+
+			this.addFlow( 'compute', object );
+
+		}
+
+		return super.build();
+
+	}
+
+}
+
+export default GLSLNodeBuilder;

+ 3 - 0
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -447,6 +447,9 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 		for ( const uniform of uniforms ) {
 
+			if ( /^(modelViewMatrix|projectionMatrix)$/.test( uniform.name ) )
+				continue;
+
 			let snippet = null;
 
 			if ( uniform.type === 'texture' ) {

+ 20 - 5
examples/webgpu_tsl_editor.html

@@ -24,8 +24,8 @@
 			}
 			#renderer {
 				position: absolute;
-				top: 0;
-				right: 50%;
+				bottom: 15px;
+				right: calc( 50% + 15px );
 				width: 200px;
 				height: 200px;
 				z-index: 100;
@@ -59,6 +59,7 @@
 			import WebGPU from 'three/addons/capabilities/WebGPU.js';
 			import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
 			import WGSLNodeBuilder from 'three/addons/renderers/webgpu/nodes/WGSLNodeBuilder.js';
+			import GLSLNodeBuilder from 'three/addons/renderers/webgl/nodes/GLSLNodeBuilder.js';
 
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
@@ -112,7 +113,12 @@
 
 				require( [ 'vs/editor/editor.main' ], () => {
 
-					const options = { shader: 'fragment', outputColorSpace: THREE.LinearSRGBColorSpace };
+					const options = {
+						shader: 'fragment',
+						outputColorSpace: THREE.LinearSRGBColorSpace,
+						output: 'WGSL',
+						preview: true
+					};
 
 					let timeout = null;
 					let nodeBuilder = null;
@@ -120,7 +126,7 @@
 					const editorDOM = document.getElementById( 'source' );
 					const resultDOM = document.getElementById( 'result' );
 
-					const tslCode = `// Example: Desaturate texture
+					const tslCode = `// Simple example
 
 const { texture, uniform, vec4 } = TSL;
 
@@ -171,7 +177,9 @@ output = vec4( finalColor, opacity );
 							mesh.material.outputNode = nodes.output;
 							mesh.material.needsUpdate = true;
 
-							nodeBuilder = new WGSLNodeBuilder( mesh, renderer );
+							const NodeBuilder = options.output === 'WGSL' ? WGSLNodeBuilder : GLSLNodeBuilder;
+
+							nodeBuilder = new NodeBuilder( mesh, renderer );
 							nodeBuilder.build();
 
 							showCode();
@@ -207,6 +215,7 @@ output = vec4( finalColor, opacity );
 
 					const gui = new GUI();
 
+					gui.add( options, 'output', [ 'GLSL', 'WGSL' ] ).onChange( build );
 					gui.add( options, 'shader', [ 'vertex', 'fragment' ] ).onChange( showCode );
 
 					gui.add( options, 'outputColorSpace', [ THREE.LinearSRGBColorSpace, THREE.SRGBColorSpace ] ).onChange( ( value ) => {
@@ -217,6 +226,12 @@ output = vec4( finalColor, opacity );
 
 					} );
 
+					gui.add( options, 'preview' ).onChange( ( value ) => {
+
+						rendererDOM.style.display = value ? '' : 'none';
+
+					} );
+
 				} );
 
 			}