123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- import WebGPUNodeUniformsGroup from './WebGPUNodeUniformsGroup.js';
- import { FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform, ColorNodeUniform } from './WebGPUNodeUniform.js';
- import WebGPUSampler from '../WebGPUSampler.js';
- import { WebGPUSampledTexture } from '../WebGPUSampledTexture.js';
- import NodeSlot from '../../nodes/core/NodeSlot.js';
- import NodeBuilder from '../../nodes/core/NodeBuilder.js';
- import ShaderLib from './ShaderLib.js';
- class WebGPUNodeBuilder extends NodeBuilder {
- constructor( material, renderer ) {
- super( material, renderer );
- this.bindingIndex = 2;
- this.bindings = { vertex: [], fragment: [] };
- this.attributeIndex = 1;
- this.varyIndex = 0;
- this.uniformsGroup = {};
- this.nativeShader = null;
- this._parseMaterial();
- }
- _parseMaterial() {
- const material = this.material;
- // get shader
- if ( material.isMeshBasicMaterial ) {
- this.nativeShader = ShaderLib.meshBasic;
- } else if ( material.isPointsMaterial ) {
- this.nativeShader = ShaderLib.pointsBasic;
- } else if ( material.isLineBasicMaterial ) {
- this.nativeShader = ShaderLib.lineBasic;
- } else {
- console.error( 'THREE.WebGPURenderer: Unknwon shader type.' );
- }
- // parse inputs
- if ( material.isMeshBasicMaterial || material.isPointsMaterial || material.isLineBasicMaterial ) {
- if ( material.colorNode !== undefined ) {
- this.addSlot( 'fragment', new NodeSlot( material.colorNode, 'COLOR', 'vec4' ) );
- }
- if ( material.opacityNode !== undefined ) {
- this.addSlot( 'fragment', new NodeSlot( material.opacityNode, 'OPACITY', 'float' ) );
- }
- }
- }
- getTexture( textureProperty, uvSnippet ) {
- return `texture( sampler2D( ${textureProperty}, ${textureProperty}_sampler ), ${uvSnippet} )`;
- }
- getPropertyName( nodeUniform ) {
- if ( nodeUniform.type === 'texture' ) {
- return nodeUniform.name;
- } else {
- return `nodeUniforms.${nodeUniform.name}`;
- }
- }
- getBindings( shaderStage ) {
- return this.bindings[ shaderStage ];
- }
- getUniformFromNode( node, shaderStage, type ) {
- const uniformNode = super.getUniformFromNode( node, shaderStage, type );
- const nodeData = this.getDataFromNode( node, shaderStage );
- if ( nodeData.uniformGPU === undefined ) {
- let uniformGPU;
- const bindings = this.bindings[ shaderStage ];
- if ( type === 'texture' ) {
- const sampler = new WebGPUSampler( `${uniformNode.name}_sampler`, uniformNode.value );
- const texture = new WebGPUSampledTexture( uniformNode.name, uniformNode.value );
- // add first textures in sequence and group for last
- const lastBinding = bindings[ bindings.length - 1 ];
- const index = lastBinding && lastBinding.isUniformsGroup ? bindings.length - 1 : bindings.length;
- bindings.splice( index, 0, sampler, texture );
- uniformGPU = { sampler, texture };
- } else {
- let uniformsGroup = this.uniformsGroup[ shaderStage ];
- if ( uniformsGroup === undefined ) {
- uniformsGroup = new WebGPUNodeUniformsGroup( shaderStage );
- this.uniformsGroup[ shaderStage ] = uniformsGroup;
- bindings.push( uniformsGroup );
- }
- if ( type === 'float' ) {
- uniformGPU = new FloatNodeUniform( uniformNode );
- } else if ( type === 'vec2' ) {
- uniformGPU = new Vector2NodeUniform( uniformNode );
- } else if ( type === 'vec3' ) {
- uniformGPU = new Vector3NodeUniform( uniformNode );
- } else if ( type === 'vec4' ) {
- uniformGPU = new Vector4NodeUniform( uniformNode );
- } else if ( type === 'color' ) {
- uniformGPU = new ColorNodeUniform( uniformNode );
- } else {
- throw new Error( `Uniform "${type}" not declared.` );
- }
- uniformsGroup.addUniform( uniformGPU );
- }
- nodeData.uniformGPU = uniformGPU;
- }
- return uniformNode;
- }
- getAttributesHeaderSnippet( shaderStage ) {
- let snippet = '';
- const attributes = this.attributes;
- let attributeIndex = this.attributeIndex;
- let varyIndex = this.varyIndex;
- for ( let name in attributes ) {
- let attribute = attributes[ name ];
- let type = attribute.type;
- let property = attribute.property;
- if ( shaderStage === 'vertex' ) {
- snippet += `layout(location = ${attributeIndex ++}) in ${type} ${name};`;
- snippet += `layout(location = ${varyIndex ++}) out ${type} ${property};`;
- } else if ( shaderStage === 'fragment' ) {
- snippet += `layout(location = ${varyIndex ++}) in ${type} ${property};`;
- }
- }
- return snippet;
- }
- getAttributesBodySnippet( shaderStage ) {
- let snippet = '';
- const attributes = this.attributes;
- for ( let name in attributes ) {
- let attribute = attributes[ name ];
- let property = attribute.property;
- snippet += `${property} = ${name};`;
- }
- return snippet;
- }
- getUniformsHeaderSnippet( shaderStage ) {
- const uniforms = this.uniforms[ shaderStage ];
- let snippet = '';
- let groupSnippet = '';
- let bindingIndex = this.bindingIndex;
- for ( let uniform of uniforms ) {
- if ( uniform.type === 'texture' ) {
- snippet += `layout(set = 0, binding = ${bindingIndex ++}) uniform sampler ${uniform.name}_sampler;`;
- snippet += `layout(set = 0, binding = ${bindingIndex ++}) uniform texture2D ${uniform.name};`;
- } else {
- let vectorType = this.getVectorType( uniform.type );
- groupSnippet += `uniform ${vectorType} ${uniform.name};`;
- }
- }
- if ( groupSnippet ) {
- snippet += `layout(set = 0, binding = ${bindingIndex ++}) uniform NodeUniforms { ${groupSnippet} } nodeUniforms;`;
- }
- return snippet;
- }
- composeShaderCode( code, snippet ) {
- // use regex maybe for security?
- const versionStrIndex = code.indexOf( "\n" );
- let finalCode = code.substr( 0, versionStrIndex ) + "\n\n";
- finalCode += snippet;
- finalCode += code.substr( versionStrIndex );
- return finalCode;
- }
- build() {
- super.build();
- this.vertexShader = this.composeShaderCode( this.nativeShader.vertexShader, this.vertexShader );
- this.fragmentShader = this.composeShaderCode( this.nativeShader.fragmentShader, this.fragmentShader );
- return this;
- }
- }
- export default WebGPUNodeBuilder;
|