123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- import { MathNode, GLSLNodeParser, NodeBuilder, NodeMaterial, FunctionNode } from '../../../nodes/Nodes.js';
- import UniformBuffer from '../../common/UniformBuffer.js';
- import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js';
- import { NodeSampledTexture, NodeSampledCubeTexture } from '../../common/nodes/NodeSampledTexture.js';
- const glslMethods = {
- [ MathNode.ATAN2 ]: 'atan',
- textureDimensions: 'textureSize'
- };
- const precisionLib = {
- low: 'lowp',
- medium: 'mediump',
- high: 'highp'
- };
- const supports = {
- instance: true
- };
- class GLSLNodeBuilder extends NodeBuilder {
- constructor( object, renderer, scene = null ) {
- super( object, renderer, new GLSLNodeParser(), scene );
- this.uniformGroups = {};
- }
- getMethod( method ) {
- return glslMethods[ method ] || method;
- }
- getPropertyName( node, shaderStage ) {
- if ( node.isOutputStructVar ) return '';
- return super.getPropertyName( node, shaderStage );
- }
- buildFunctionNode( shaderNode ) {
- const layout = shaderNode.layout;
- const flowData = this.flowShaderNode( shaderNode );
- const parameters = [];
- for ( const input of layout.inputs ) {
- parameters.push( this.getType( input.type ) + ' ' + input.name );
- }
- //
- const code = `${ this.getType( layout.type ) } ${ layout.name }( ${ parameters.join( ', ' ) } ) {
- ${ flowData.vars }
- ${ flowData.code }
- return ${ flowData.result };
- }`;
- //
- return new FunctionNode( code );
- }
- getTexture( texture, textureProperty, uvSnippet ) {
- if ( texture.isTextureCube ) {
- return `textureCube( ${textureProperty}, ${uvSnippet} )`;
- } else if ( texture.isDepthTexture ) {
- return `texture( ${textureProperty}, ${uvSnippet} ).x`;
- } else {
- return `texture( ${textureProperty}, ${uvSnippet} )`;
- }
- }
- getTextureLevel( texture, textureProperty, uvSnippet, biasSnippet ) {
- return `textureLod( ${textureProperty}, ${uvSnippet}, ${biasSnippet} )`;
- }
- getTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, shaderStage = this.shaderStage ) {
- if ( shaderStage === 'fragment' ) {
- return `texture( ${textureProperty}, vec3( ${uvSnippet}, ${compareSnippet} ) )`;
- } else {
- console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` );
- }
- }
- getVars( shaderStage ) {
- const snippets = [];
- const vars = this.vars[ shaderStage ];
- if ( vars !== undefined ) {
- for ( const variable of vars ) {
- if ( variable.isOutputStructVar ) continue;
- snippets.push( `${ this.getVar( variable.type, variable.name ) };` );
- }
- }
- return snippets.join( '\n\t' );
- }
- getUniforms( shaderStage ) {
- const uniforms = this.uniforms[ shaderStage ];
- const bindingSnippets = [];
- const uniformGroups = {};
- for ( const uniform of uniforms ) {
- let snippet = null;
- let group = false;
- if ( uniform.type === 'texture' ) {
- if ( uniform.node.value.compareFunction ) {
- snippet = `sampler2DShadow ${uniform.name};`;
- } else {
- snippet = `sampler2D ${uniform.name};`;
- }
- } else if ( uniform.type === 'cubeTexture' ) {
- snippet = `samplerCube ${uniform.name};`;
- } else if ( uniform.type === 'buffer' ) {
- const bufferNode = uniform.node;
- const bufferType = this.getType( bufferNode.bufferType );
- const bufferCount = bufferNode.bufferCount;
- const bufferCountSnippet = bufferCount > 0 ? bufferCount : '';
- snippet = `${bufferNode.name} {\n\t${bufferType} ${uniform.name}[${bufferCountSnippet}];\n};\n`;
- } else {
- const vectorType = this.getVectorType( uniform.type );
- snippet = `${vectorType} ${uniform.name};`;
- group = true;
- }
- const precision = uniform.node.precision;
- if ( precision !== null ) {
- snippet = precisionLib[ precision ] + ' ' + snippet;
- }
- if ( group ) {
- snippet = '\t' + snippet;
- const groupName = uniform.groupNode.name;
- const groupSnippets = uniformGroups[ groupName ] || ( uniformGroups[ groupName ] = [] );
- groupSnippets.push( snippet );
- } else {
- snippet = 'uniform ' + snippet;
- bindingSnippets.push( snippet );
- }
- }
- let output = '';
- for ( const name in uniformGroups ) {
- const groupSnippets = uniformGroups[ name ];
- output += this._getGLSLUniformStruct( shaderStage + '_' + name, groupSnippets.join( '\n' ) ) + '\n';
- }
- output += bindingSnippets.join( '\n' );
- return output;
- }
- getAttributes( shaderStage ) {
- let snippet = '';
- if ( shaderStage === 'vertex' ) {
- const attributes = this.getAttributesArray();
- let location = 0;
- for ( const attribute of attributes ) {
- snippet += `layout( location = ${ location ++ } ) in ${ attribute.type } ${ attribute.name };\n`;
- }
- }
- return snippet;
- }
- getStructMembers( struct ) {
- const snippets = [];
- const members = struct.getMemberTypes();
- for ( let i = 0; i < members.length; i ++ ) {
- const member = members[ i ];
- snippets.push( `layout( location = ${i} ) out ${ member} m${i};` );
- }
- return snippets.join( '\n' );
- }
- getStructs( shaderStage ) {
- const snippets = [];
- const structs = this.structs[ shaderStage ];
- if ( structs.length === 0 ) {
- return 'layout( location = 0 ) out vec4 fragColor;\n';
- }
- for ( let index = 0, length = structs.length; index < length; index ++ ) {
- const struct = structs[ index ];
- let snippet = '\n';
- snippet += this.getStructMembers( struct );
- snippet += '\n';
- snippets.push( snippet );
- }
- return snippets.join( '\n\n' );
- }
- getVaryings( shaderStage ) {
- let snippet = '';
- const varyings = this.varyings;
- if ( shaderStage === 'vertex' ) {
- for ( const varying of varyings ) {
- const type = varying.type;
- const flat = type === 'int' || type === 'uint' ? 'flat ' : '';
- snippet += `${flat}${varying.needsInterpolation ? 'out' : '/*out*/'} ${type} ${varying.name};\n`;
- }
- } else if ( shaderStage === 'fragment' ) {
- for ( const varying of varyings ) {
- if ( varying.needsInterpolation ) {
- const type = varying.type;
- const flat = type === 'int' || type === 'uint' ? 'flat ' : '';
- snippet += `${flat}in ${type} ${varying.name};\n`;
- }
- }
- }
- return snippet;
- }
- getVertexIndex() {
- return 'gl_VertexID';
- }
- getInstanceIndex() {
- return 'uint( gl_InstanceID )';
- }
- getFrontFacing() {
- return 'gl_FrontFacing';
- }
- getFragCoord() {
- return 'gl_FragCoord';
- }
- isAvailable( name ) {
- return supports[ name ] === true;
- }
- isFlipY() {
- return true;
- }
- _getGLSLUniformStruct( name, vars ) {
- return `
- layout( std140 ) uniform ${name} {
- ${vars}
- };`;
- }
- _getGLSLVertexCode( shaderData ) {
- return `#version 300 es
- ${ this.getSignature() }
- // precision
- precision highp float;
- precision highp int;
- // uniforms
- ${shaderData.uniforms}
- // varyings
- ${shaderData.varyings}
- // attributes
- ${shaderData.attributes}
- // codes
- ${shaderData.codes}
- void main() {
- // vars
- ${shaderData.vars}
- // flow
- ${shaderData.flow}
- gl_PointSize = 1.0;
- }
- `;
- }
- _getGLSLFragmentCode( shaderData ) {
- return `#version 300 es
- ${ this.getSignature() }
- // precision
- precision highp float;
- precision highp int;
- precision lowp sampler2DShadow;
- // uniforms
- ${shaderData.uniforms}
- // varyings
- ${shaderData.varyings}
- // codes
- ${shaderData.codes}
- ${shaderData.structs}
- 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 = ';
- flow += `${ flowSlotData.result };`;
- } else if ( shaderStage === 'fragment' ) {
- if ( ! node.outputNode.isOutputStructNode ) {
- flow += '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.structs = this.getStructs( 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 );
- }
- }
- getUniformFromNode( node, type, shaderStage, name = null ) {
- const uniformNode = super.getUniformFromNode( node, type, shaderStage, name );
- const nodeData = this.getDataFromNode( node, shaderStage );
- let uniformGPU = nodeData.uniformGPU;
- if ( uniformGPU === undefined ) {
- if ( type === 'texture' ) {
- uniformGPU = new NodeSampledTexture( uniformNode.name, uniformNode.node );
- this.bindings[ shaderStage ].push( uniformGPU );
- } else if ( type === 'cubeTexture' ) {
- uniformGPU = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node );
- this.bindings[ shaderStage ].push( uniformGPU );
- } else if ( type === 'buffer' ) {
- node.name = `NodeBuffer_${node.id}`;
- const buffer = new UniformBuffer( node.name, node.value );
- uniformNode.name = `buffer${node.id}`;
- this.bindings[ shaderStage ].push( buffer );
- uniformGPU = buffer;
- } else {
- const group = node.groupNode;
- const groupName = group.name;
- const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} );
- let uniformsGroup = uniformsStage[ groupName ];
- if ( uniformsGroup === undefined ) {
- uniformsGroup = new NodeUniformsGroup( shaderStage + '_' + groupName, group );
- //uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] );
- uniformsStage[ groupName ] = uniformsGroup;
- this.bindings[ shaderStage ].push( uniformsGroup );
- }
- uniformGPU = this.getNodeUniform( uniformNode, type );
- uniformsGroup.addUniform( uniformGPU );
- }
- nodeData.uniformGPU = uniformGPU;
- }
- return uniformNode;
- }
- 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;
|