GLSLNodeBuilder.js 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629
  1. import { GLSLNodeParser, NodeBuilder, TextureNode, vectorComponents, CodeNode } from '../../../nodes/Nodes.js';
  2. import NodeUniformBuffer from '../../common/nodes/NodeUniformBuffer.js';
  3. import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js';
  4. import { NodeSampledTexture, NodeSampledCubeTexture, NodeSampledTexture3D } from '../../common/nodes/NodeSampledTexture.js';
  5. import { NoColorSpace, ByteType, ShortType, RGBAIntegerFormat, RGBIntegerFormat, RedIntegerFormat, RGIntegerFormat, UnsignedByteType, UnsignedIntType, UnsignedShortType, RedFormat, RGFormat, IntType, RGBFormat, RGBAFormat, FloatType } from '../../../constants.js';
  6. import { DataTexture } from '../../../textures/DataTexture.js';
  7. import { error } from '../../../utils.js';
  8. const glslPolyfills = {
  9. bitcast_int_uint: new CodeNode( /* glsl */'uint tsl_bitcast_int_to_uint ( int x ) { return floatBitsToUint( intBitsToFloat ( x ) ); }' ),
  10. bitcast_uint_int: new CodeNode( /* glsl */'uint tsl_bitcast_uint_to_int ( uint x ) { return floatBitsToInt( uintBitsToFloat ( x ) ); }' )
  11. };
  12. const glslMethods = {
  13. textureDimensions: 'textureSize',
  14. equals: 'equal',
  15. bitcast_float_int: 'floatBitsToInt',
  16. bitcast_int_float: 'intBitsToFloat',
  17. bitcast_uint_float: 'uintBitsToFloat',
  18. bitcast_float_uint: 'floatBitsToUint',
  19. bitcast_uint_int: 'tsl_bitcast_uint_to_int',
  20. bitcast_int_uint: 'tsl_bitcast_int_to_uint',
  21. floatpack_snorm_2x16: 'packSnorm2x16',
  22. floatpack_unorm_2x16: 'packUnorm2x16',
  23. floatpack_float16_2x16: 'packHalf2x16',
  24. floatunpack_snorm_2x16: 'unpackSnorm2x16',
  25. floatunpack_unorm_2x16: 'unpackUnorm2x16',
  26. floatunpack_float16_2x16: 'unpackHalf2x16'
  27. };
  28. const precisionLib = {
  29. low: 'lowp',
  30. medium: 'mediump',
  31. high: 'highp'
  32. };
  33. const supports = {
  34. swizzleAssign: true,
  35. storageBuffer: false
  36. };
  37. const interpolationTypeMap = {
  38. perspective: 'smooth',
  39. linear: 'noperspective'
  40. };
  41. const interpolationModeMap = {
  42. 'centroid': 'centroid'
  43. };
  44. const defaultPrecisions = `
  45. precision highp float;
  46. precision highp int;
  47. precision highp sampler2D;
  48. precision highp sampler3D;
  49. precision highp samplerCube;
  50. precision highp sampler2DArray;
  51. precision highp usampler2D;
  52. precision highp usampler3D;
  53. precision highp usamplerCube;
  54. precision highp usampler2DArray;
  55. precision highp isampler2D;
  56. precision highp isampler3D;
  57. precision highp isamplerCube;
  58. precision highp isampler2DArray;
  59. precision lowp sampler2DShadow;
  60. precision lowp sampler2DArrayShadow;
  61. precision lowp samplerCubeShadow;
  62. `;
  63. /**
  64. * A node builder targeting GLSL.
  65. *
  66. * This module generates GLSL shader code from node materials and also
  67. * generates the respective bindings and vertex buffer definitions. These
  68. * data are later used by the renderer to create render and compute pipelines
  69. * for render objects.
  70. *
  71. * @augments NodeBuilder
  72. */
  73. class GLSLNodeBuilder extends NodeBuilder {
  74. /**
  75. * Constructs a new GLSL node builder renderer.
  76. *
  77. * @param {Object3D} object - The 3D object.
  78. * @param {Renderer} renderer - The renderer.
  79. */
  80. constructor( object, renderer ) {
  81. super( object, renderer, new GLSLNodeParser() );
  82. /**
  83. * A dictionary holds for each shader stage ('vertex', 'fragment', 'compute')
  84. * another dictionary which manages UBOs per group ('render','frame','object').
  85. *
  86. * @type {Object<string,Object<string,NodeUniformsGroup>>}
  87. */
  88. this.uniformGroups = {};
  89. /**
  90. * An array that holds objects defining the varying and attribute data in
  91. * context of Transform Feedback.
  92. *
  93. * @type {Array<Object<string,AttributeNode|string>>}
  94. */
  95. this.transforms = [];
  96. /**
  97. * A dictionary that holds for each shader stage a Map of used extensions.
  98. *
  99. * @type {Object<string,Map<string,Object>>}
  100. */
  101. this.extensions = {};
  102. /**
  103. * A dictionary that holds for each shader stage an Array of used builtins.
  104. *
  105. * @type {Object<string,Array<string>>}
  106. */
  107. this.builtins = { vertex: [], fragment: [], compute: [] };
  108. }
  109. /**
  110. * Checks if the given texture requires a manual conversion to the working color space.
  111. *
  112. * @param {Texture} texture - The texture to check.
  113. * @return {boolean} Whether the given texture requires a conversion to working color space or not.
  114. */
  115. needsToWorkingColorSpace( texture ) {
  116. return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace;
  117. }
  118. /**
  119. * Includes the given method name into the current
  120. * function node.
  121. *
  122. * @private
  123. * @param {string} name - The method name to include.
  124. * @return {CodeNode} The respective code node.
  125. */
  126. _include( name ) {
  127. const codeNode = glslPolyfills[ name ];
  128. codeNode.build( this );
  129. this.addInclude( codeNode );
  130. return codeNode;
  131. }
  132. /**
  133. * Returns the native shader method name for a given generic name.
  134. *
  135. * @param {string} method - The method name to resolve.
  136. * @return {string} The resolved GLSL method name.
  137. */
  138. getMethod( method ) {
  139. if ( glslPolyfills[ method ] !== undefined ) {
  140. this._include( method );
  141. }
  142. return glslMethods[ method ] || method;
  143. }
  144. /**
  145. * Returns the bitcast method name for a given input and outputType.
  146. *
  147. * @param {string} type - The output type to bitcast to.
  148. * @param {string} inputType - The input type of the.
  149. * @return {string} The resolved WGSL bitcast invocation.
  150. */
  151. getBitcastMethod( type, inputType ) {
  152. return this.getMethod( `bitcast_${ inputType }_${ type }` );
  153. }
  154. /**
  155. * Returns the float packing method name for a given numeric encoding.
  156. *
  157. * @param {string} encoding - The numeric encoding that describes how the float values are mapped to the integer range.
  158. * @returns {string} The resolved GLSL float packing method name.
  159. */
  160. getFloatPackingMethod( encoding ) {
  161. return this.getMethod( `floatpack_${ encoding }_2x16` );
  162. }
  163. /**
  164. * Returns the float unpacking method name for a given numeric encoding.
  165. *
  166. * @param {string} encoding - The numeric encoding that describes how the integer values are mapped to the float range.
  167. * @returns {string} The resolved GLSL float unpacking method name.
  168. */
  169. getFloatUnpackingMethod( encoding ) {
  170. return this.getMethod( `floatunpack_${ encoding }_2x16` );
  171. }
  172. /**
  173. * Returns the native snippet for a ternary operation.
  174. *
  175. * @param {string} condSnippet - The condition determining which expression gets resolved.
  176. * @param {string} ifSnippet - The expression to resolve to if the condition is true.
  177. * @param {string} elseSnippet - The expression to resolve to if the condition is false.
  178. * @return {string} The resolved method name.
  179. */
  180. getTernary( condSnippet, ifSnippet, elseSnippet ) {
  181. return `${condSnippet} ? ${ifSnippet} : ${elseSnippet}`;
  182. }
  183. /**
  184. * Returns the output struct name. Not relevant for GLSL.
  185. *
  186. * @return {string}
  187. */
  188. getOutputStructName() {
  189. return '';
  190. }
  191. /**
  192. * Builds the given shader node.
  193. *
  194. * @param {ShaderNodeInternal} shaderNode - The shader node.
  195. * @return {string} The GLSL function code.
  196. */
  197. buildFunctionCode( shaderNode ) {
  198. const layout = shaderNode.layout;
  199. const flowData = this.flowShaderNode( shaderNode );
  200. const parameters = [];
  201. for ( const input of layout.inputs ) {
  202. parameters.push( this.getType( input.type ) + ' ' + input.name );
  203. }
  204. //
  205. const code = `${ this.getType( layout.type ) } ${ layout.name }( ${ parameters.join( ', ' ) } ) {
  206. ${ flowData.vars }
  207. ${ flowData.code }
  208. return ${ flowData.result };
  209. }`;
  210. //
  211. return code;
  212. }
  213. /**
  214. * Setups the Pixel Buffer Object (PBO) for the given storage
  215. * buffer node.
  216. *
  217. * @param {StorageBufferNode} storageBufferNode - The storage buffer node.
  218. */
  219. setupPBO( storageBufferNode ) {
  220. const attribute = storageBufferNode.value;
  221. if ( attribute.pbo === undefined ) {
  222. const originalArray = attribute.array;
  223. const numElements = attribute.count * attribute.itemSize;
  224. const { itemSize } = attribute;
  225. const isInteger = attribute.array.constructor.name.toLowerCase().includes( 'int' );
  226. let format = isInteger ? RedIntegerFormat : RedFormat;
  227. if ( itemSize === 2 ) {
  228. format = isInteger ? RGIntegerFormat : RGFormat;
  229. } else if ( itemSize === 3 ) {
  230. format = isInteger ? RGBIntegerFormat : RGBFormat;
  231. } else if ( itemSize === 4 ) {
  232. format = isInteger ? RGBAIntegerFormat : RGBAFormat;
  233. }
  234. const typeMap = {
  235. Float32Array: FloatType,
  236. Uint8Array: UnsignedByteType,
  237. Uint16Array: UnsignedShortType,
  238. Uint32Array: UnsignedIntType,
  239. Int8Array: ByteType,
  240. Int16Array: ShortType,
  241. Int32Array: IntType,
  242. Uint8ClampedArray: UnsignedByteType,
  243. };
  244. const width = Math.pow( 2, Math.ceil( Math.log2( Math.sqrt( numElements / itemSize ) ) ) );
  245. let height = Math.ceil( ( numElements / itemSize ) / width );
  246. if ( width * height * itemSize < numElements ) height ++; // Ensure enough space
  247. const newSize = width * height * itemSize;
  248. const newArray = new originalArray.constructor( newSize );
  249. newArray.set( originalArray, 0 );
  250. attribute.array = newArray;
  251. const pboTexture = new DataTexture( attribute.array, width, height, format, typeMap[ attribute.array.constructor.name ] || FloatType );
  252. pboTexture.needsUpdate = true;
  253. pboTexture.isPBOTexture = true;
  254. const pbo = new TextureNode( pboTexture, null, null );
  255. pbo.setPrecision( 'high' );
  256. attribute.pboNode = pbo;
  257. attribute.pbo = pbo.value;
  258. this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.nodeName );
  259. }
  260. }
  261. /**
  262. * Returns a GLSL snippet that represents the property name of the given node.
  263. *
  264. * @param {Node} node - The node.
  265. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
  266. * @return {string} The property name.
  267. */
  268. getPropertyName( node, shaderStage = this.shaderStage ) {
  269. if ( node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true ) {
  270. return shaderStage.charAt( 0 ) + '_' + node.name;
  271. }
  272. return super.getPropertyName( node, shaderStage );
  273. }
  274. /**
  275. * Setups the Pixel Buffer Object (PBO) for the given storage
  276. * buffer node.
  277. *
  278. * @param {StorageArrayElementNode} storageArrayElementNode - The storage array element node.
  279. * @return {string} The property name.
  280. */
  281. generatePBO( storageArrayElementNode ) {
  282. const { node, indexNode } = storageArrayElementNode;
  283. const attribute = node.value;
  284. if ( this.renderer.backend.has( attribute ) ) {
  285. const attributeData = this.renderer.backend.get( attribute );
  286. attributeData.pbo = attribute.pbo;
  287. }
  288. const nodeUniform = this.getUniformFromNode( attribute.pboNode, 'texture', this.shaderStage, this.context.nodeName );
  289. const textureName = this.getPropertyName( nodeUniform );
  290. this.increaseUsage( indexNode ); // force cache generate to be used as index in x,y
  291. const indexSnippet = indexNode.build( this, 'uint' );
  292. const elementNodeData = this.getDataFromNode( storageArrayElementNode );
  293. let propertyName = elementNodeData.propertyName;
  294. if ( propertyName === undefined ) {
  295. // property element
  296. const nodeVar = this.getVarFromNode( storageArrayElementNode );
  297. propertyName = this.getPropertyName( nodeVar );
  298. // property size
  299. const bufferNodeData = this.getDataFromNode( node );
  300. let propertySizeName = bufferNodeData.propertySizeName;
  301. if ( propertySizeName === undefined ) {
  302. propertySizeName = propertyName + 'Size';
  303. this.getVarFromNode( node, propertySizeName, 'uint' );
  304. this.addLineFlowCode( `${ propertySizeName } = uint( textureSize( ${ textureName }, 0 ).x )`, storageArrayElementNode );
  305. bufferNodeData.propertySizeName = propertySizeName;
  306. }
  307. //
  308. const { itemSize } = attribute;
  309. const channel = '.' + vectorComponents.join( '' ).slice( 0, itemSize );
  310. const uvSnippet = `ivec2(${indexSnippet} % ${ propertySizeName }, ${indexSnippet} / ${ propertySizeName })`;
  311. const snippet = this.generateTextureLoad( null, textureName, uvSnippet, '0', null, null );
  312. //
  313. let prefix = 'vec4';
  314. if ( attribute.pbo.type === UnsignedIntType ) {
  315. prefix = 'uvec4';
  316. } else if ( attribute.pbo.type === IntType ) {
  317. prefix = 'ivec4';
  318. }
  319. this.addLineFlowCode( `${ propertyName } = ${prefix}(${ snippet })${channel}`, storageArrayElementNode );
  320. elementNodeData.propertyName = propertyName;
  321. }
  322. return propertyName;
  323. }
  324. /**
  325. * Generates the GLSL snippet that reads a single texel from a texture without sampling or filtering.
  326. *
  327. * @param {?Texture} texture - The texture.
  328. * @param {string} textureProperty - The name of the texture uniform in the shader.
  329. * @param {string} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  330. * @param {?string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
  331. * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample.
  332. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  333. * @return {string} The GLSL snippet.
  334. */
  335. generateTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) {
  336. if ( levelSnippet === null ) levelSnippet = '0';
  337. let snippet;
  338. if ( depthSnippet ) {
  339. if ( offsetSnippet ) {
  340. snippet = `texelFetchOffset( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet }, ${ offsetSnippet } )`;
  341. } else {
  342. snippet = `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet } )`;
  343. }
  344. } else {
  345. if ( offsetSnippet ) {
  346. snippet = `texelFetchOffset( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`;
  347. } else {
  348. snippet = `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`;
  349. }
  350. }
  351. if ( texture !== null && texture.isDepthTexture ) {
  352. snippet += '.x';
  353. }
  354. return snippet;
  355. }
  356. /**
  357. * Generates the GLSL snippet for sampling/loading the given texture.
  358. *
  359. * @param {Texture} texture - The texture.
  360. * @param {string} textureProperty - The name of the texture uniform in the shader.
  361. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  362. * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample.
  363. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  364. * @return {string} The GLSL snippet.
  365. */
  366. generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ) {
  367. if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`;
  368. if ( texture.isDepthTexture ) {
  369. if ( offsetSnippet ) return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet } ).x`;
  370. return `texture( ${ textureProperty }, ${ uvSnippet } ).x`;
  371. }
  372. if ( offsetSnippet ) return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet } )`;
  373. return `texture( ${ textureProperty }, ${ uvSnippet } )`;
  374. }
  375. /**
  376. * Generates the GLSL snippet when sampling textures with explicit mip level.
  377. *
  378. * @param {Texture} texture - The texture.
  379. * @param {string} textureProperty - The name of the texture uniform in the shader.
  380. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  381. * @param {string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture.
  382. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  383. * @return {string} The GLSL snippet.
  384. */
  385. generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, offsetSnippet ) {
  386. if ( offsetSnippet ) {
  387. return `textureLodOffset( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`;
  388. }
  389. return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`;
  390. }
  391. /**
  392. * Generates the GLSL snippet when sampling textures with a bias to the mip level.
  393. *
  394. * @param {Texture} texture - The texture.
  395. * @param {string} textureProperty - The name of the texture uniform in the shader.
  396. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  397. * @param {string} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling.
  398. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  399. * @return {string} The GLSL snippet.
  400. */
  401. generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, offsetSnippet ) {
  402. if ( offsetSnippet ) {
  403. return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet }, ${ biasSnippet } )`;
  404. }
  405. return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`;
  406. }
  407. /**
  408. * Generates the GLSL snippet for sampling/loading the given texture using explicit gradients.
  409. *
  410. * @param {Texture} texture - The texture.
  411. * @param {string} textureProperty - The name of the texture uniform in the shader.
  412. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  413. * @param {Array<string>} gradSnippet - An array holding both gradient GLSL snippets.
  414. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  415. * @return {string} The GLSL snippet.
  416. */
  417. generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, offsetSnippet ) {
  418. if ( offsetSnippet ) {
  419. return `textureGradOffset( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] }, ${ offsetSnippet } )`;
  420. }
  421. return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`;
  422. }
  423. /**
  424. * Generates the GLSL snippet for sampling a depth texture and comparing the sampled depth values
  425. * against a reference value.
  426. *
  427. * @param {Texture} texture - The texture.
  428. * @param {string} textureProperty - The name of the texture uniform in the shader.
  429. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling.
  430. * @param {string} compareSnippet - A GLSL snippet that represents the reference value.
  431. * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample.
  432. * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture.
  433. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for.
  434. * @return {string} The GLSL snippet.
  435. */
  436. generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) {
  437. if ( shaderStage === 'fragment' ) {
  438. // Cube shadow maps use vec4(direction, compareValue)
  439. if ( texture.isCubeTexture ) {
  440. return `texture( ${ textureProperty }, vec4( ${ uvSnippet }, ${ compareSnippet } ) )`;
  441. }
  442. if ( depthSnippet ) {
  443. if ( offsetSnippet ) {
  444. return `textureOffset( ${ textureProperty }, vec4( ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet } ), ${ offsetSnippet } )`;
  445. }
  446. return `texture( ${ textureProperty }, vec4( ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet } ) )`;
  447. }
  448. if ( offsetSnippet ) {
  449. return `textureOffset( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ), ${ offsetSnippet } )`;
  450. }
  451. return `texture( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ) )`;
  452. } else {
  453. error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` );
  454. }
  455. }
  456. /**
  457. * Returns the variables of the given shader stage as a GLSL string.
  458. *
  459. * @param {string} shaderStage - The shader stage.
  460. * @return {string} The GLSL snippet that defines the variables.
  461. */
  462. getVars( shaderStage ) {
  463. const snippets = [];
  464. const vars = this.vars[ shaderStage ];
  465. if ( vars !== undefined ) {
  466. for ( const variable of vars ) {
  467. snippets.push( `${ this.getVar( variable.type, variable.name, variable.count ) };` );
  468. }
  469. }
  470. return snippets.join( '\n\t' );
  471. }
  472. /**
  473. * Returns the uniforms of the given shader stage as a GLSL string.
  474. *
  475. * @param {string} shaderStage - The shader stage.
  476. * @return {string} The GLSL snippet that defines the uniforms.
  477. */
  478. getUniforms( shaderStage ) {
  479. const uniforms = this.uniforms[ shaderStage ];
  480. const bindingSnippets = [];
  481. const uniformGroups = {};
  482. for ( const uniform of uniforms ) {
  483. let snippet = null;
  484. let group = false;
  485. if ( uniform.type === 'texture' || uniform.type === 'texture3D' ) {
  486. const texture = uniform.node.value;
  487. let typePrefix = '';
  488. if ( texture.isDataTexture === true || texture.isData3DTexture === true ) {
  489. if ( texture.type === UnsignedIntType ) {
  490. typePrefix = 'u';
  491. } else if ( texture.type === IntType ) {
  492. typePrefix = 'i';
  493. }
  494. }
  495. if ( uniform.type === 'texture3D' && texture.isArrayTexture === false ) {
  496. snippet = `${typePrefix}sampler3D ${ uniform.name };`;
  497. } else if ( texture.compareFunction ) {
  498. if ( texture.isArrayTexture === true ) {
  499. snippet = `sampler2DArrayShadow ${ uniform.name };`;
  500. } else {
  501. snippet = `sampler2DShadow ${ uniform.name };`;
  502. }
  503. } else if ( texture.isArrayTexture === true || texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) {
  504. snippet = `${typePrefix}sampler2DArray ${ uniform.name };`;
  505. } else {
  506. snippet = `${typePrefix}sampler2D ${ uniform.name };`;
  507. }
  508. } else if ( uniform.type === 'cubeTexture' ) {
  509. snippet = `samplerCube ${ uniform.name };`;
  510. } else if ( uniform.type === 'cubeDepthTexture' ) {
  511. snippet = `samplerCubeShadow ${ uniform.name };`;
  512. } else if ( uniform.type === 'buffer' ) {
  513. const bufferNode = uniform.node;
  514. const bufferType = this.getType( bufferNode.bufferType );
  515. const bufferCount = bufferNode.bufferCount;
  516. const bufferCountSnippet = bufferCount > 0 ? bufferCount : '';
  517. snippet = `${bufferNode.name} {\n\t${ bufferType } ${ uniform.name }[${ bufferCountSnippet }];\n};\n`;
  518. } else {
  519. const vectorType = this.getVectorType( uniform.type );
  520. snippet = `${ vectorType } ${ this.getPropertyName( uniform, shaderStage ) };`;
  521. group = true;
  522. }
  523. const precision = uniform.node.precision;
  524. if ( precision !== null ) {
  525. snippet = precisionLib[ precision ] + ' ' + snippet;
  526. }
  527. if ( group ) {
  528. snippet = '\t' + snippet;
  529. const groupName = uniform.groupNode.name;
  530. const groupSnippets = uniformGroups[ groupName ] || ( uniformGroups[ groupName ] = [] );
  531. groupSnippets.push( snippet );
  532. } else {
  533. snippet = 'uniform ' + snippet;
  534. bindingSnippets.push( snippet );
  535. }
  536. }
  537. let output = '';
  538. for ( const name in uniformGroups ) {
  539. const groupSnippets = uniformGroups[ name ];
  540. output += this._getGLSLUniformStruct( shaderStage + '_' + name, groupSnippets.join( '\n' ) ) + '\n';
  541. }
  542. output += bindingSnippets.join( '\n' );
  543. return output;
  544. }
  545. /**
  546. * Returns the type for a given buffer attribute.
  547. *
  548. * @param {BufferAttribute} attribute - The buffer attribute.
  549. * @return {string} The type.
  550. */
  551. getTypeFromAttribute( attribute ) {
  552. let nodeType = super.getTypeFromAttribute( attribute );
  553. if ( /^[iu]/.test( nodeType ) && attribute.gpuType !== IntType ) {
  554. let dataAttribute = attribute;
  555. if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data;
  556. const array = dataAttribute.array;
  557. if ( ( array instanceof Uint32Array || array instanceof Int32Array ) === false ) {
  558. nodeType = nodeType.slice( 1 );
  559. }
  560. }
  561. return nodeType;
  562. }
  563. /**
  564. * Returns the shader attributes of the given shader stage as a GLSL string.
  565. *
  566. * @param {string} shaderStage - The shader stage.
  567. * @return {string} The GLSL snippet that defines the shader attributes.
  568. */
  569. getAttributes( shaderStage ) {
  570. let snippet = '';
  571. if ( shaderStage === 'vertex' || shaderStage === 'compute' ) {
  572. const attributes = this.getAttributesArray();
  573. let location = 0;
  574. for ( const attribute of attributes ) {
  575. snippet += `layout( location = ${ location ++ } ) in ${ attribute.type } ${ attribute.name };\n`;
  576. }
  577. }
  578. return snippet;
  579. }
  580. /**
  581. * Returns the members of the given struct type node as a GLSL string.
  582. *
  583. * @param {StructTypeNode} struct - The struct type node.
  584. * @return {string} The GLSL snippet that defines the struct members.
  585. */
  586. getStructMembers( struct ) {
  587. const snippets = [];
  588. for ( const member of struct.members ) {
  589. snippets.push( `\t${ member.type } ${ member.name };` );
  590. }
  591. return snippets.join( '\n' );
  592. }
  593. /**
  594. * Returns the structs of the given shader stage as a GLSL string.
  595. *
  596. * @param {string} shaderStage - The shader stage.
  597. * @return {string} The GLSL snippet that defines the structs.
  598. */
  599. getStructs( shaderStage ) {
  600. const snippets = [];
  601. const structs = this.structs[ shaderStage ];
  602. const outputSnippet = [];
  603. for ( const struct of structs ) {
  604. if ( struct.output ) {
  605. for ( const member of struct.members ) {
  606. outputSnippet.push( `layout( location = ${ member.index } ) out ${ member.type } ${ member.name };` );
  607. }
  608. } else {
  609. let snippet = 'struct ' + struct.name + ' {\n';
  610. snippet += this.getStructMembers( struct );
  611. snippet += '\n};\n';
  612. snippets.push( snippet );
  613. }
  614. }
  615. if ( outputSnippet.length === 0 ) {
  616. outputSnippet.push( 'layout( location = 0 ) out vec4 fragColor;' );
  617. }
  618. return '\n' + outputSnippet.join( '\n' ) + '\n\n' + snippets.join( '\n' );
  619. }
  620. /**
  621. * Returns the varyings of the given shader stage as a GLSL string.
  622. *
  623. * @param {string} shaderStage - The shader stage.
  624. * @return {string} The GLSL snippet that defines the varyings.
  625. */
  626. getVaryings( shaderStage ) {
  627. let snippet = '';
  628. const varyings = this.varyings;
  629. if ( shaderStage === 'vertex' || shaderStage === 'compute' ) {
  630. for ( const varying of varyings ) {
  631. if ( shaderStage === 'compute' ) varying.needsInterpolation = true;
  632. const type = this.getType( varying.type );
  633. if ( varying.needsInterpolation ) {
  634. if ( varying.interpolationType ) {
  635. const interpolationType = interpolationTypeMap[ varying.interpolationType ] || varying.interpolationType;
  636. const sampling = interpolationModeMap[ varying.interpolationSampling ] || '';
  637. snippet += `${ interpolationType } ${ sampling } out ${ type } ${ varying.name };\n`;
  638. } else {
  639. const flat = type.includes( 'int' ) || type.includes( 'uv' ) || type.includes( 'iv' ) ? 'flat ' : '';
  640. snippet += `${ flat }out ${ type } ${ varying.name };\n`;
  641. }
  642. } else {
  643. snippet += `${type} ${varying.name};\n`; // generate variable (no varying required)
  644. }
  645. }
  646. } else if ( shaderStage === 'fragment' ) {
  647. for ( const varying of varyings ) {
  648. if ( varying.needsInterpolation ) {
  649. const type = this.getType( varying.type );
  650. if ( varying.interpolationType ) {
  651. const interpolationType = interpolationTypeMap[ varying.interpolationType ] || varying.interpolationType;
  652. const sampling = interpolationModeMap[ varying.interpolationSampling ] || '';
  653. snippet += `${ interpolationType } ${ sampling } in ${ type } ${ varying.name };\n`;
  654. } else {
  655. const flat = type.includes( 'int' ) || type.includes( 'uv' ) || type.includes( 'iv' ) ? 'flat ' : '';
  656. snippet += `${ flat }in ${ type } ${ varying.name };\n`;
  657. }
  658. }
  659. }
  660. }
  661. for ( const builtin of this.builtins[ shaderStage ] ) {
  662. snippet += `${builtin};\n`;
  663. }
  664. return snippet;
  665. }
  666. /**
  667. * Returns the vertex index builtin.
  668. *
  669. * @return {string} The vertex index.
  670. */
  671. getVertexIndex() {
  672. return 'uint( gl_VertexID )';
  673. }
  674. /**
  675. * Contextually returns either the vertex stage instance index builtin
  676. * or the linearized index of an compute invocation within a grid of workgroups.
  677. *
  678. * @return {string} The instance index.
  679. */
  680. getInstanceIndex() {
  681. return 'uint( gl_InstanceID )';
  682. }
  683. /**
  684. * Returns a builtin representing the index of an invocation within its workgroup.
  685. *
  686. * @return {string} The invocation local index.
  687. */
  688. getInvocationLocalIndex() {
  689. const workgroupSize = this.object.workgroupSize;
  690. const size = workgroupSize.reduce( ( acc, curr ) => acc * curr, 1 );
  691. return `uint( gl_InstanceID ) % ${size}u`;
  692. }
  693. /**
  694. * Returns a builtin representing the size of a subgroup within the current shader.
  695. */
  696. getSubgroupSize() {
  697. error( 'GLSLNodeBuilder: WebGLBackend does not support the subgroupSize node' );
  698. }
  699. /**
  700. * Returns a builtin representing the index of an invocation within its subgroup.
  701. */
  702. getInvocationSubgroupIndex() {
  703. error( 'GLSLNodeBuilder: WebGLBackend does not support the invocationSubgroupIndex node' );
  704. }
  705. /**
  706. * Returns a builtin representing the index of the current invocation's subgroup within its workgroup.
  707. */
  708. getSubgroupIndex() {
  709. error( 'GLSLNodeBuilder: WebGLBackend does not support the subgroupIndex node' );
  710. }
  711. /**
  712. * Returns the draw index builtin.
  713. *
  714. * @return {?string} The drawIndex shader string. Returns `null` if `WEBGL_multi_draw` isn't supported by the device.
  715. */
  716. getDrawIndex() {
  717. const extensions = this.renderer.backend.extensions;
  718. if ( extensions.has( 'WEBGL_multi_draw' ) ) {
  719. return 'uint( gl_DrawID )';
  720. }
  721. return null;
  722. }
  723. /**
  724. * Returns the front facing builtin.
  725. *
  726. * @return {string} The front facing builtin.
  727. */
  728. getFrontFacing() {
  729. return 'gl_FrontFacing';
  730. }
  731. /**
  732. * Returns the frag coord builtin.
  733. *
  734. * @return {string} The frag coord builtin.
  735. */
  736. getFragCoord() {
  737. return 'gl_FragCoord.xy';
  738. }
  739. /**
  740. * Returns the frag depth builtin.
  741. *
  742. * @return {string} The frag depth builtin.
  743. */
  744. getFragDepth() {
  745. return 'gl_FragDepth';
  746. }
  747. /**
  748. * Enables the given extension.
  749. *
  750. * @param {string} name - The extension name.
  751. * @param {string} behavior - The extension behavior.
  752. * @param {string} [shaderStage=this.shaderStage] - The shader stage.
  753. */
  754. enableExtension( name, behavior, shaderStage = this.shaderStage ) {
  755. const map = this.extensions[ shaderStage ] || ( this.extensions[ shaderStage ] = new Map() );
  756. if ( map.has( name ) === false ) {
  757. map.set( name, {
  758. name,
  759. behavior
  760. } );
  761. }
  762. }
  763. /**
  764. * Returns the enabled extensions of the given shader stage as a GLSL string.
  765. *
  766. * @param {string} shaderStage - The shader stage.
  767. * @return {string} The GLSL snippet that defines the enabled extensions.
  768. */
  769. getExtensions( shaderStage ) {
  770. const snippets = [];
  771. if ( shaderStage === 'vertex' ) {
  772. const ext = this.renderer.backend.extensions;
  773. const isBatchedMesh = this.object.isBatchedMesh;
  774. if ( isBatchedMesh && ext.has( 'WEBGL_multi_draw' ) ) {
  775. this.enableExtension( 'GL_ANGLE_multi_draw', 'require', shaderStage );
  776. }
  777. }
  778. const extensions = this.extensions[ shaderStage ];
  779. if ( extensions !== undefined ) {
  780. for ( const { name, behavior } of extensions.values() ) {
  781. snippets.push( `#extension ${name} : ${behavior}` );
  782. }
  783. }
  784. return snippets.join( '\n' );
  785. }
  786. /**
  787. * Returns the clip distances builtin.
  788. *
  789. * @return {string} The clip distances builtin.
  790. */
  791. getClipDistance() {
  792. return 'gl_ClipDistance';
  793. }
  794. /**
  795. * Whether the requested feature is available or not.
  796. *
  797. * @param {string} name - The requested feature.
  798. * @return {boolean} Whether the requested feature is supported or not.
  799. */
  800. isAvailable( name ) {
  801. let result = supports[ name ];
  802. if ( result === undefined ) {
  803. let extensionName;
  804. result = false;
  805. switch ( name ) {
  806. case 'float32Filterable':
  807. extensionName = 'OES_texture_float_linear';
  808. break;
  809. case 'clipDistance':
  810. extensionName = 'WEBGL_clip_cull_distance';
  811. break;
  812. }
  813. if ( extensionName !== undefined ) {
  814. const extensions = this.renderer.backend.extensions;
  815. if ( extensions.has( extensionName ) ) {
  816. extensions.get( extensionName );
  817. result = true;
  818. }
  819. }
  820. supports[ name ] = result;
  821. }
  822. return result;
  823. }
  824. /**
  825. * Whether to flip texture data along its vertical axis or not.
  826. *
  827. * @return {boolean} Returns always `true` in context of GLSL.
  828. */
  829. isFlipY() {
  830. return true;
  831. }
  832. /**
  833. * Enables hardware clipping.
  834. *
  835. * @param {string} planeCount - The clipping plane count.
  836. */
  837. enableHardwareClipping( planeCount ) {
  838. this.enableExtension( 'GL_ANGLE_clip_cull_distance', 'require' );
  839. this.builtins[ 'vertex' ].push( `out float gl_ClipDistance[ ${ planeCount } ]` );
  840. }
  841. /**
  842. * Enables multiview.
  843. */
  844. enableMultiview() {
  845. this.enableExtension( 'GL_OVR_multiview2', 'require', 'fragment' );
  846. this.enableExtension( 'GL_OVR_multiview2', 'require', 'vertex' );
  847. this.builtins[ 'vertex' ].push( 'layout(num_views = 2) in' );
  848. }
  849. /**
  850. * Registers a transform in context of Transform Feedback.
  851. *
  852. * @param {string} varyingName - The varying name.
  853. * @param {AttributeNode} attributeNode - The attribute node.
  854. */
  855. registerTransform( varyingName, attributeNode ) {
  856. this.transforms.push( { varyingName, attributeNode } );
  857. }
  858. /**
  859. * Returns the transforms of the given shader stage as a GLSL string.
  860. *
  861. * @param {string} shaderStage - The shader stage.
  862. * @return {string} The GLSL snippet that defines the transforms.
  863. */
  864. getTransforms( /* shaderStage */ ) {
  865. const transforms = this.transforms;
  866. let snippet = '';
  867. for ( let i = 0; i < transforms.length; i ++ ) {
  868. const transform = transforms[ i ];
  869. const attributeName = this.getPropertyName( transform.attributeNode );
  870. if ( attributeName ) snippet += `${ transform.varyingName } = ${ attributeName };\n\t`;
  871. }
  872. return snippet;
  873. }
  874. /**
  875. * Returns a GLSL struct based on the given name and variables.
  876. *
  877. * @private
  878. * @param {string} name - The struct name.
  879. * @param {string} vars - The struct variables.
  880. * @return {string} The GLSL snippet representing a struct.
  881. */
  882. _getGLSLUniformStruct( name, vars ) {
  883. return `
  884. layout( std140 ) uniform ${name} {
  885. ${vars}
  886. };`;
  887. }
  888. /**
  889. * Returns a GLSL vertex shader based on the given shader data.
  890. *
  891. * @private
  892. * @param {Object} shaderData - The shader data.
  893. * @return {string} The vertex shader.
  894. */
  895. _getGLSLVertexCode( shaderData ) {
  896. return `#version 300 es
  897. ${ this.getSignature() }
  898. // extensions
  899. ${shaderData.extensions}
  900. // precision
  901. ${ defaultPrecisions }
  902. // uniforms
  903. ${shaderData.uniforms}
  904. // varyings
  905. ${shaderData.varyings}
  906. // attributes
  907. ${shaderData.attributes}
  908. // codes
  909. ${shaderData.codes}
  910. void main() {
  911. // vars
  912. ${shaderData.vars}
  913. // transforms
  914. ${shaderData.transforms}
  915. // flow
  916. ${shaderData.flow}
  917. gl_PointSize = 1.0;
  918. }
  919. `;
  920. }
  921. /**
  922. * Returns a GLSL fragment shader based on the given shader data.
  923. *
  924. * @private
  925. * @param {Object} shaderData - The shader data.
  926. * @return {string} The vertex shader.
  927. */
  928. _getGLSLFragmentCode( shaderData ) {
  929. return `#version 300 es
  930. ${ this.getSignature() }
  931. // extensions
  932. ${shaderData.extensions}
  933. // precision
  934. ${ defaultPrecisions }
  935. // structs
  936. ${shaderData.structs}
  937. // uniforms
  938. ${shaderData.uniforms}
  939. // varyings
  940. ${shaderData.varyings}
  941. // codes
  942. ${shaderData.codes}
  943. void main() {
  944. // vars
  945. ${shaderData.vars}
  946. // flow
  947. ${shaderData.flow}
  948. }
  949. `;
  950. }
  951. /**
  952. * Controls the code build of the shader stages.
  953. */
  954. buildCode() {
  955. const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} };
  956. this.sortBindingGroups();
  957. for ( const shaderStage in shadersData ) {
  958. let flow = '// code\n\n';
  959. flow += this.flowCode[ shaderStage ];
  960. const flowNodes = this.flowNodes[ shaderStage ];
  961. const mainNode = flowNodes[ flowNodes.length - 1 ];
  962. for ( const node of flowNodes ) {
  963. const flowSlotData = this.getFlowData( node/*, shaderStage*/ );
  964. const slotName = node.name;
  965. if ( slotName ) {
  966. if ( flow.length > 0 ) flow += '\n';
  967. flow += `\t// flow -> ${ slotName }\n\t`;
  968. }
  969. flow += `${ flowSlotData.code }\n\t`;
  970. if ( node === mainNode && shaderStage !== 'compute' ) {
  971. flow += '// result\n\t';
  972. if ( shaderStage === 'vertex' ) {
  973. flow += 'gl_Position = ';
  974. flow += `${ flowSlotData.result };`;
  975. } else if ( shaderStage === 'fragment' ) {
  976. if ( ! node.outputNode.isOutputStructNode ) {
  977. flow += 'fragColor = ';
  978. flow += `${ flowSlotData.result };`;
  979. }
  980. }
  981. }
  982. }
  983. const stageData = shadersData[ shaderStage ];
  984. stageData.extensions = this.getExtensions( shaderStage );
  985. stageData.uniforms = this.getUniforms( shaderStage );
  986. stageData.attributes = this.getAttributes( shaderStage );
  987. stageData.varyings = this.getVaryings( shaderStage );
  988. stageData.vars = this.getVars( shaderStage );
  989. stageData.structs = this.getStructs( shaderStage );
  990. stageData.codes = this.getCodes( shaderStage );
  991. stageData.transforms = this.getTransforms( shaderStage );
  992. stageData.flow = flow;
  993. }
  994. if ( this.material !== null ) {
  995. this.vertexShader = this._getGLSLVertexCode( shadersData.vertex );
  996. this.fragmentShader = this._getGLSLFragmentCode( shadersData.fragment );
  997. } else {
  998. this.computeShader = this._getGLSLVertexCode( shadersData.compute );
  999. }
  1000. }
  1001. /**
  1002. * This method is one of the more important ones since it's responsible
  1003. * for generating a matching binding instance for the given uniform node.
  1004. *
  1005. * These bindings are later used in the renderer to create bind groups
  1006. * and layouts.
  1007. *
  1008. * @param {UniformNode} node - The uniform node.
  1009. * @param {string} type - The node data type.
  1010. * @param {string} shaderStage - The shader stage.
  1011. * @param {?string} [name=null] - An optional uniform name.
  1012. * @return {NodeUniform} The node uniform object.
  1013. */
  1014. getUniformFromNode( node, type, shaderStage, name = null ) {
  1015. const uniformNode = super.getUniformFromNode( node, type, shaderStage, name );
  1016. const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache );
  1017. let uniformGPU = nodeData.uniformGPU;
  1018. if ( uniformGPU === undefined ) {
  1019. const group = node.groupNode;
  1020. const groupName = group.name;
  1021. const bindings = this.getBindGroupArray( groupName, shaderStage );
  1022. if ( type === 'texture' ) {
  1023. uniformGPU = new NodeSampledTexture( uniformNode.name, uniformNode.node, group );
  1024. bindings.push( uniformGPU );
  1025. } else if ( type === 'cubeTexture' || type === 'cubeDepthTexture' ) {
  1026. uniformGPU = new NodeSampledCubeTexture( uniformNode.name, uniformNode.node, group );
  1027. bindings.push( uniformGPU );
  1028. } else if ( type === 'texture3D' ) {
  1029. uniformGPU = new NodeSampledTexture3D( uniformNode.name, uniformNode.node, group );
  1030. bindings.push( uniformGPU );
  1031. } else if ( type === 'buffer' ) {
  1032. uniformNode.name = `buffer${ node.id }`;
  1033. const sharedData = this.getSharedDataFromNode( node );
  1034. let buffer = sharedData.buffer;
  1035. if ( buffer === undefined ) {
  1036. node.name = `NodeBuffer_${ node.id }`;
  1037. buffer = new NodeUniformBuffer( node, group );
  1038. buffer.name = node.name;
  1039. sharedData.buffer = buffer;
  1040. }
  1041. bindings.push( buffer );
  1042. uniformGPU = buffer;
  1043. } else {
  1044. const uniformsStage = this.uniformGroups[ shaderStage ] || ( this.uniformGroups[ shaderStage ] = {} );
  1045. let uniformsGroup = uniformsStage[ groupName ];
  1046. if ( uniformsGroup === undefined ) {
  1047. uniformsGroup = new NodeUniformsGroup( shaderStage + '_' + groupName, group );
  1048. //uniformsGroup.setVisibility( gpuShaderStageLib[ shaderStage ] );
  1049. uniformsStage[ groupName ] = uniformsGroup;
  1050. bindings.push( uniformsGroup );
  1051. }
  1052. uniformGPU = this.getNodeUniform( uniformNode, type );
  1053. uniformsGroup.addUniform( uniformGPU );
  1054. }
  1055. nodeData.uniformGPU = uniformGPU;
  1056. }
  1057. return uniformNode;
  1058. }
  1059. }
  1060. export default GLSLNodeBuilder;
粤ICP备19079148号