NodeBuilder.js 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652
  1. import NodeUniform from './NodeUniform.js';
  2. import NodeAttribute from './NodeAttribute.js';
  3. import NodeVarying from './NodeVarying.js';
  4. import NodeVar from './NodeVar.js';
  5. import NodeCode from './NodeCode.js';
  6. import NodeCache from './NodeCache.js';
  7. import ParameterNode from './ParameterNode.js';
  8. import StructType from './StructType.js';
  9. import FunctionNode from '../code/FunctionNode.js';
  10. import NodeMaterial from '../../materials/nodes/NodeMaterial.js';
  11. import { getTypeFromLength } from './NodeUtils.js';
  12. import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js';
  13. import {
  14. NumberNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform,
  15. ColorNodeUniform, Matrix2NodeUniform, Matrix3NodeUniform, Matrix4NodeUniform
  16. } from '../../renderers/common/nodes/NodeUniform.js';
  17. import { stack } from './StackNode.js';
  18. import { getCurrentStack, setCurrentStack } from '../tsl/TSLBase.js';
  19. import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js';
  20. import ChainMap from '../../renderers/common/ChainMap.js';
  21. import BindGroup from '../../renderers/common/BindGroup.js';
  22. import { REVISION, IntType, UnsignedIntType, LinearFilter, LinearMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapLinearFilter } from '../../constants.js';
  23. import { RenderTarget } from '../../core/RenderTarget.js';
  24. import { Color } from '../../math/Color.js';
  25. import { Vector2 } from '../../math/Vector2.js';
  26. import { Vector3 } from '../../math/Vector3.js';
  27. import { Vector4 } from '../../math/Vector4.js';
  28. import { Float16BufferAttribute } from '../../core/BufferAttribute.js';
  29. const rendererCache = new WeakMap();
  30. const typeFromArray = new Map( [
  31. [ Int8Array, 'int' ],
  32. [ Int16Array, 'int' ],
  33. [ Int32Array, 'int' ],
  34. [ Uint8Array, 'uint' ],
  35. [ Uint16Array, 'uint' ],
  36. [ Uint32Array, 'uint' ],
  37. [ Float32Array, 'float' ]
  38. ] );
  39. const toFloat = ( value ) => {
  40. if ( /e/g.test( value ) ) {
  41. return String( value ).replace( /\+/g, '' );
  42. } else {
  43. value = Number( value );
  44. return value + ( value % 1 ? '' : '.0' );
  45. }
  46. };
  47. /**
  48. * Base class for builders which generate a shader program based
  49. * on a 3D object and its node material definition.
  50. */
  51. class NodeBuilder {
  52. /**
  53. * Constructs a new node builder.
  54. *
  55. * @param {Object3D} object - The 3D object.
  56. * @param {Renderer} renderer - The current renderer.
  57. * @param {NodeParser} parser - A reference to a node parser.
  58. */
  59. constructor( object, renderer, parser ) {
  60. /**
  61. * The 3D object.
  62. *
  63. * @type {Object3D}
  64. */
  65. this.object = object;
  66. /**
  67. * The material of the 3D object.
  68. *
  69. * @type {?Material}
  70. */
  71. this.material = ( object && object.material ) || null;
  72. /**
  73. * The geometry of the 3D object.
  74. *
  75. * @type {?BufferGeometry}
  76. */
  77. this.geometry = ( object && object.geometry ) || null;
  78. /**
  79. * The current renderer.
  80. *
  81. * @type {Renderer}
  82. */
  83. this.renderer = renderer;
  84. /**
  85. * A reference to a node parser.
  86. *
  87. * @type {NodeParser}
  88. */
  89. this.parser = parser;
  90. /**
  91. * The scene the 3D object belongs to.
  92. *
  93. * @type {?Scene}
  94. * @default null
  95. */
  96. this.scene = null;
  97. /**
  98. * The camera the 3D object is rendered with.
  99. *
  100. * @type {?Camera}
  101. * @default null
  102. */
  103. this.camera = null;
  104. /**
  105. * A list of all nodes the builder is processing
  106. * for this 3D object.
  107. *
  108. * @type {Array<Node>}
  109. */
  110. this.nodes = [];
  111. /**
  112. * A list of all sequential nodes.
  113. *
  114. * @type {Array<Node>}
  115. */
  116. this.sequentialNodes = [];
  117. /**
  118. * A list of all nodes which {@link Node#update} method should be executed.
  119. *
  120. * @type {Array<Node>}
  121. */
  122. this.updateNodes = [];
  123. /**
  124. * A list of all nodes which {@link Node#updateBefore} method should be executed.
  125. *
  126. * @type {Array<Node>}
  127. */
  128. this.updateBeforeNodes = [];
  129. /**
  130. * A list of all nodes which {@link Node#updateAfter} method should be executed.
  131. *
  132. * @type {Array<Node>}
  133. */
  134. this.updateAfterNodes = [];
  135. /**
  136. * A dictionary that assigns each node to a unique hash.
  137. *
  138. * @type {Object<number,Node>}
  139. */
  140. this.hashNodes = {};
  141. /**
  142. * A reference to a node material observer.
  143. *
  144. * @type {?NodeMaterialObserver}
  145. * @default null
  146. */
  147. this.observer = null;
  148. /**
  149. * A reference to the current lights node.
  150. *
  151. * @type {?LightsNode}
  152. * @default null
  153. */
  154. this.lightsNode = null;
  155. /**
  156. * A reference to the current environment node.
  157. *
  158. * @type {?Node}
  159. * @default null
  160. */
  161. this.environmentNode = null;
  162. /**
  163. * A reference to the current fog node.
  164. *
  165. * @type {?FogNode}
  166. * @default null
  167. */
  168. this.fogNode = null;
  169. /**
  170. * The current clipping context.
  171. *
  172. * @type {?ClippingContext}
  173. */
  174. this.clippingContext = null;
  175. /**
  176. * The generated vertex shader.
  177. *
  178. * @type {?string}
  179. */
  180. this.vertexShader = null;
  181. /**
  182. * The generated fragment shader.
  183. *
  184. * @type {?string}
  185. */
  186. this.fragmentShader = null;
  187. /**
  188. * The generated compute shader.
  189. *
  190. * @type {?string}
  191. */
  192. this.computeShader = null;
  193. /**
  194. * Nodes used in the primary flow of code generation.
  195. *
  196. * @type {Object<string,Array<Node>>}
  197. */
  198. this.flowNodes = { vertex: [], fragment: [], compute: [] };
  199. /**
  200. * Nodes code from `.flowNodes`.
  201. *
  202. * @type {Object<string,string>}
  203. */
  204. this.flowCode = { vertex: '', fragment: '', compute: '' };
  205. /**
  206. * This dictionary holds the node uniforms of the builder.
  207. * The uniforms are maintained in an array for each shader stage.
  208. *
  209. * @type {Object}
  210. */
  211. this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 };
  212. /**
  213. * This dictionary holds the output structs of the builder.
  214. * The structs are maintained in an array for each shader stage.
  215. *
  216. * @type {Object}
  217. */
  218. this.structs = { vertex: [], fragment: [], compute: [], index: 0 };
  219. /**
  220. * This dictionary holds the bindings for each shader stage.
  221. *
  222. * @type {Object}
  223. */
  224. this.bindings = { vertex: {}, fragment: {}, compute: {} };
  225. /**
  226. * This dictionary maintains the binding indices per bind group.
  227. *
  228. * @type {Object}
  229. */
  230. this.bindingsIndexes = {};
  231. /**
  232. * Reference to the array of bind groups.
  233. *
  234. * @type {?Array<BindGroup>}
  235. */
  236. this.bindGroups = null;
  237. /**
  238. * This array holds the node attributes of this builder
  239. * created via {@link AttributeNode}.
  240. *
  241. * @type {Array<NodeAttribute>}
  242. */
  243. this.attributes = [];
  244. /**
  245. * This array holds the node attributes of this builder
  246. * created via {@link BufferAttributeNode}.
  247. *
  248. * @type {Array<NodeAttribute>}
  249. */
  250. this.bufferAttributes = [];
  251. /**
  252. * This array holds the node varyings of this builder.
  253. *
  254. * @type {Array<NodeVarying>}
  255. */
  256. this.varyings = [];
  257. /**
  258. * This dictionary holds the (native) node codes of this builder.
  259. * The codes are maintained in an array for each shader stage.
  260. *
  261. * @type {Object<string,Array<NodeCode>>}
  262. */
  263. this.codes = {};
  264. /**
  265. * This dictionary holds the node variables of this builder.
  266. * The variables are maintained in an array for each shader stage.
  267. * This dictionary is also used to count the number of variables
  268. * according to their type (const, vars).
  269. *
  270. * @type {Object<string,Array<NodeVar>|number>}
  271. */
  272. this.vars = {};
  273. /**
  274. * Current code flow.
  275. * All code generated in this stack will be stored in `.flow`.
  276. *
  277. * @type {{code: string}}
  278. */
  279. this.flow = { code: '' };
  280. /**
  281. * A chain of nodes.
  282. * Used to check recursive calls in node-graph.
  283. *
  284. * @type {Array<Node>}
  285. */
  286. this.chaining = [];
  287. /**
  288. * The current stack.
  289. * This reflects the current process in the code block hierarchy,
  290. * it is useful to know if the current process is inside a conditional for example.
  291. *
  292. * @type {StackNode}
  293. */
  294. this.stack = stack();
  295. /**
  296. * List of stack nodes.
  297. * The current stack hierarchy is stored in an array.
  298. *
  299. * @type {Array<StackNode>}
  300. */
  301. this.stacks = [];
  302. /**
  303. * A tab value. Used for shader string generation.
  304. *
  305. * @type {string}
  306. * @default '\t'
  307. */
  308. this.tab = '\t';
  309. /**
  310. * Reference to the current function node.
  311. *
  312. * @type {?FunctionNode}
  313. * @default null
  314. */
  315. this.currentFunctionNode = null;
  316. /**
  317. * The builder's context.
  318. *
  319. * @type {Object}
  320. */
  321. this.context = {
  322. material: this.material
  323. };
  324. /**
  325. * The builder's cache.
  326. *
  327. * @type {NodeCache}
  328. */
  329. this.cache = new NodeCache();
  330. /**
  331. * Since the {@link NodeBuilder#cache} might be temporarily
  332. * overwritten by other caches, this member retains the reference
  333. * to the builder's own cache.
  334. *
  335. * @type {NodeCache}
  336. * @default this.cache
  337. */
  338. this.globalCache = this.cache;
  339. this.flowsData = new WeakMap();
  340. /**
  341. * The current shader stage.
  342. *
  343. * @type {?('vertex'|'fragment'|'compute'|'any')}
  344. */
  345. this.shaderStage = null;
  346. /**
  347. * The current build stage.
  348. *
  349. * @type {?('setup'|'analyze'|'generate')}
  350. */
  351. this.buildStage = null;
  352. /**
  353. * Whether comparison in shader code are generated with methods or not.
  354. *
  355. * @type {boolean}
  356. * @default false
  357. */
  358. this.useComparisonMethod = false;
  359. }
  360. /**
  361. * Returns the bind groups of the current renderer.
  362. *
  363. * @return {ChainMap} The cache.
  364. */
  365. getBindGroupsCache() {
  366. let bindGroupsCache = rendererCache.get( this.renderer );
  367. if ( bindGroupsCache === undefined ) {
  368. bindGroupsCache = new ChainMap();
  369. rendererCache.set( this.renderer, bindGroupsCache );
  370. }
  371. return bindGroupsCache;
  372. }
  373. /**
  374. * Factory method for creating an instance of {@link RenderTarget} with the given
  375. * dimensions and options.
  376. *
  377. * @param {number} width - The width of the render target.
  378. * @param {number} height - The height of the render target.
  379. * @param {Object} options - The options of the render target.
  380. * @return {RenderTarget} The render target.
  381. */
  382. createRenderTarget( width, height, options ) {
  383. return new RenderTarget( width, height, options );
  384. }
  385. /**
  386. * Factory method for creating an instance of {@link CubeRenderTarget} with the given
  387. * dimensions and options.
  388. *
  389. * @param {number} size - The size of the cube render target.
  390. * @param {Object} options - The options of the cube render target.
  391. * @return {CubeRenderTarget} The cube render target.
  392. */
  393. createCubeRenderTarget( size, options ) {
  394. return new CubeRenderTarget( size, options );
  395. }
  396. /**
  397. * Whether the given node is included in the internal array of nodes or not.
  398. *
  399. * @param {Node} node - The node to test.
  400. * @return {boolean} Whether the given node is included in the internal array of nodes or not.
  401. */
  402. includes( node ) {
  403. return this.nodes.includes( node );
  404. }
  405. /**
  406. * Returns the output struct name which is required by
  407. * {@link OutputStructNode}.
  408. *
  409. * @abstract
  410. * @return {string} The name of the output struct.
  411. */
  412. getOutputStructName() {}
  413. /**
  414. * Returns a bind group for the given group name and binding.
  415. *
  416. * @private
  417. * @param {string} groupName - The group name.
  418. * @param {Array<NodeUniformsGroup>} bindings - List of bindings.
  419. * @return {BindGroup} The bind group
  420. */
  421. _getBindGroup( groupName, bindings ) {
  422. const bindGroupsCache = this.getBindGroupsCache();
  423. //
  424. const bindingsArray = [];
  425. let sharedGroup = true;
  426. for ( const binding of bindings ) {
  427. bindingsArray.push( binding );
  428. sharedGroup = sharedGroup && binding.groupNode.shared !== true;
  429. }
  430. //
  431. let bindGroup;
  432. if ( sharedGroup ) {
  433. bindGroup = bindGroupsCache.get( bindingsArray );
  434. if ( bindGroup === undefined ) {
  435. bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray );
  436. bindGroupsCache.set( bindingsArray, bindGroup );
  437. }
  438. } else {
  439. bindGroup = new BindGroup( groupName, bindingsArray, this.bindingsIndexes[ groupName ].group, bindingsArray );
  440. }
  441. return bindGroup;
  442. }
  443. /**
  444. * Returns an array of node uniform groups for the given group name and shader stage.
  445. *
  446. * @param {string} groupName - The group name.
  447. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  448. * @return {Array<NodeUniformsGroup>} The array of node uniform groups.
  449. */
  450. getBindGroupArray( groupName, shaderStage ) {
  451. const bindings = this.bindings[ shaderStage ];
  452. let bindGroup = bindings[ groupName ];
  453. if ( bindGroup === undefined ) {
  454. if ( this.bindingsIndexes[ groupName ] === undefined ) {
  455. this.bindingsIndexes[ groupName ] = { binding: 0, group: Object.keys( this.bindingsIndexes ).length };
  456. }
  457. bindings[ groupName ] = bindGroup = [];
  458. }
  459. return bindGroup;
  460. }
  461. /**
  462. * Returns a list bindings of all shader stages separated by groups.
  463. *
  464. * @return {Array<BindGroup>} The list of bindings.
  465. */
  466. getBindings() {
  467. let bindingsGroups = this.bindGroups;
  468. if ( bindingsGroups === null ) {
  469. const groups = {};
  470. const bindings = this.bindings;
  471. for ( const shaderStage of shaderStages ) {
  472. for ( const groupName in bindings[ shaderStage ] ) {
  473. const uniforms = bindings[ shaderStage ][ groupName ];
  474. const groupUniforms = groups[ groupName ] || ( groups[ groupName ] = [] );
  475. groupUniforms.push( ...uniforms );
  476. }
  477. }
  478. bindingsGroups = [];
  479. for ( const groupName in groups ) {
  480. const group = groups[ groupName ];
  481. const bindingsGroup = this._getBindGroup( groupName, group );
  482. bindingsGroups.push( bindingsGroup );
  483. }
  484. this.bindGroups = bindingsGroups;
  485. }
  486. return bindingsGroups;
  487. }
  488. /**
  489. * Sorts the bind groups and updates {@link NodeBuilder#bindingsIndexes}.
  490. */
  491. sortBindingGroups() {
  492. const bindingsGroups = this.getBindings();
  493. bindingsGroups.sort( ( a, b ) => ( a.bindings[ 0 ].groupNode.order - b.bindings[ 0 ].groupNode.order ) );
  494. for ( let i = 0; i < bindingsGroups.length; i ++ ) {
  495. const bindingGroup = bindingsGroups[ i ];
  496. this.bindingsIndexes[ bindingGroup.name ].group = i;
  497. bindingGroup.index = i;
  498. }
  499. }
  500. /**
  501. * The builder maintains each node in a hash-based dictionary.
  502. * This method sets the given node (value) with the given hash (key) into this dictionary.
  503. *
  504. * @param {Node} node - The node to add.
  505. * @param {number} hash - The hash of the node.
  506. */
  507. setHashNode( node, hash ) {
  508. this.hashNodes[ hash ] = node;
  509. }
  510. /**
  511. * Adds a node to this builder.
  512. *
  513. * @param {Node} node - The node to add.
  514. */
  515. addNode( node ) {
  516. if ( this.nodes.includes( node ) === false ) {
  517. this.nodes.push( node );
  518. this.setHashNode( node, node.getHash( this ) );
  519. }
  520. }
  521. /**
  522. * It is used to add Nodes that will be used as FRAME and RENDER events,
  523. * and need to follow a certain sequence in the calls to work correctly.
  524. * This function should be called after 'setup()' in the 'build()' process to ensure that the child nodes are processed first.
  525. *
  526. * @param {Node} node - The node to add.
  527. */
  528. addSequentialNode( node ) {
  529. if ( this.sequentialNodes.includes( node ) === false ) {
  530. this.sequentialNodes.push( node );
  531. }
  532. }
  533. /**
  534. * Checks the update types of nodes
  535. */
  536. buildUpdateNodes() {
  537. for ( const node of this.nodes ) {
  538. const updateType = node.getUpdateType();
  539. if ( updateType !== NodeUpdateType.NONE ) {
  540. this.updateNodes.push( node.getSelf() );
  541. }
  542. }
  543. for ( const node of this.sequentialNodes ) {
  544. const updateBeforeType = node.getUpdateBeforeType();
  545. const updateAfterType = node.getUpdateAfterType();
  546. if ( updateBeforeType !== NodeUpdateType.NONE ) {
  547. this.updateBeforeNodes.push( node.getSelf() );
  548. }
  549. if ( updateAfterType !== NodeUpdateType.NONE ) {
  550. this.updateAfterNodes.push( node.getSelf() );
  551. }
  552. }
  553. }
  554. /**
  555. * A reference the current node which is the
  556. * last node in the chain of nodes.
  557. *
  558. * @type {Node}
  559. */
  560. get currentNode() {
  561. return this.chaining[ this.chaining.length - 1 ];
  562. }
  563. /**
  564. * Whether the given texture is filtered or not.
  565. *
  566. * @param {Texture} texture - The texture to check.
  567. * @return {boolean} Whether the given texture is filtered or not.
  568. */
  569. isFilteredTexture( texture ) {
  570. return ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter ||
  571. texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter );
  572. }
  573. /**
  574. * Adds the given node to the internal node chain.
  575. * This is used to check recursive calls in node-graph.
  576. *
  577. * @param {Node} node - The node to add.
  578. */
  579. addChain( node ) {
  580. /*
  581. if ( this.chaining.indexOf( node ) !== - 1 ) {
  582. console.warn( 'Recursive node: ', node );
  583. }
  584. */
  585. this.chaining.push( node );
  586. }
  587. /**
  588. * Removes the given node from the internal node chain.
  589. *
  590. * @param {Node} node - The node to remove.
  591. */
  592. removeChain( node ) {
  593. const lastChain = this.chaining.pop();
  594. if ( lastChain !== node ) {
  595. throw new Error( 'NodeBuilder: Invalid node chaining!' );
  596. }
  597. }
  598. /**
  599. * Returns the native shader method name for a given generic name. E.g.
  600. * the method name `textureDimensions` matches the WGSL name but must be
  601. * resolved to `textureSize` in GLSL.
  602. *
  603. * @abstract
  604. * @param {string} method - The method name to resolve.
  605. * @return {string} The resolved method name.
  606. */
  607. getMethod( method ) {
  608. return method;
  609. }
  610. /**
  611. * Returns a node for the given hash, see {@link NodeBuilder#setHashNode}.
  612. *
  613. * @param {number} hash - The hash of the node.
  614. * @return {Node} The found node.
  615. */
  616. getNodeFromHash( hash ) {
  617. return this.hashNodes[ hash ];
  618. }
  619. /**
  620. * Adds the Node to a target flow so that it can generate code in the 'generate' process.
  621. *
  622. * @param {('vertex'|'fragment'|'compute')} shaderStage - The shader stage.
  623. * @param {Node} node - The node to add.
  624. * @return {Node} The node.
  625. */
  626. addFlow( shaderStage, node ) {
  627. this.flowNodes[ shaderStage ].push( node );
  628. return node;
  629. }
  630. /**
  631. * Sets builder's context.
  632. *
  633. * @param {Object} context - The context to set.
  634. */
  635. setContext( context ) {
  636. this.context = context;
  637. }
  638. /**
  639. * Returns the builder's current context.
  640. *
  641. * @return {Object} The builder's current context.
  642. */
  643. getContext() {
  644. return this.context;
  645. }
  646. /**
  647. * Gets a context used in shader construction that can be shared across different materials.
  648. * This is necessary since the renderer cache can reuse shaders generated in one material and use them in another.
  649. *
  650. * @return {Object} The builder's current context without material.
  651. */
  652. getSharedContext() {
  653. const context = { ...this.context };
  654. delete context.material;
  655. return this.context;
  656. }
  657. /**
  658. * Sets builder's cache.
  659. *
  660. * @param {NodeCache} cache - The cache to set.
  661. */
  662. setCache( cache ) {
  663. this.cache = cache;
  664. }
  665. /**
  666. * Returns the builder's current cache.
  667. *
  668. * @return {NodeCache} The builder's current cache.
  669. */
  670. getCache() {
  671. return this.cache;
  672. }
  673. /**
  674. * Returns a cache for the given node.
  675. *
  676. * @param {Node} node - The node.
  677. * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not.
  678. * @return {NodeCache} The cache.
  679. */
  680. getCacheFromNode( node, parent = true ) {
  681. const data = this.getDataFromNode( node );
  682. if ( data.cache === undefined ) data.cache = new NodeCache( parent ? this.getCache() : null );
  683. return data.cache;
  684. }
  685. /**
  686. * Whether the requested feature is available or not.
  687. *
  688. * @abstract
  689. * @param {string} name - The requested feature.
  690. * @return {boolean} Whether the requested feature is supported or not.
  691. */
  692. isAvailable( /*name*/ ) {
  693. return false;
  694. }
  695. /**
  696. * Returns the vertexIndex input variable as a native shader string.
  697. *
  698. * @abstract
  699. * @return {string} The instanceIndex shader string.
  700. */
  701. getVertexIndex() {
  702. console.warn( 'Abstract function.' );
  703. }
  704. /**
  705. * Returns the instanceIndex input variable as a native shader string.
  706. *
  707. * @abstract
  708. * @return {string} The instanceIndex shader string.
  709. */
  710. getInstanceIndex() {
  711. console.warn( 'Abstract function.' );
  712. }
  713. /**
  714. * Returns the drawIndex input variable as a native shader string.
  715. * Only relevant for WebGL and its `WEBGL_multi_draw` extension.
  716. *
  717. * @abstract
  718. * @return {?string} The drawIndex shader string.
  719. */
  720. getDrawIndex() {
  721. console.warn( 'Abstract function.' );
  722. }
  723. /**
  724. * Returns the frontFacing input variable as a native shader string.
  725. *
  726. * @abstract
  727. * @return {string} The frontFacing shader string.
  728. */
  729. getFrontFacing() {
  730. console.warn( 'Abstract function.' );
  731. }
  732. /**
  733. * Returns the fragCoord input variable as a native shader string.
  734. *
  735. * @abstract
  736. * @return {string} The fragCoord shader string.
  737. */
  738. getFragCoord() {
  739. console.warn( 'Abstract function.' );
  740. }
  741. /**
  742. * Whether to flip texture data along its vertical axis or not. WebGL needs
  743. * this method evaluate to `true`, WebGPU to `false`.
  744. *
  745. * @abstract
  746. * @return {boolean} Whether to flip texture data along its vertical axis or not.
  747. */
  748. isFlipY() {
  749. return false;
  750. }
  751. /**
  752. * Calling this method increases the usage count for the given node by one.
  753. *
  754. * @param {Node} node - The node to increase the usage count for.
  755. * @return {number} The updated usage count.
  756. */
  757. increaseUsage( node ) {
  758. const nodeData = this.getDataFromNode( node );
  759. nodeData.usageCount = nodeData.usageCount === undefined ? 1 : nodeData.usageCount + 1;
  760. return nodeData.usageCount;
  761. }
  762. /**
  763. * Generates a texture sample shader string for the given texture data.
  764. *
  765. * @abstract
  766. * @param {Texture} texture - The texture.
  767. * @param {string} textureProperty - The texture property name.
  768. * @param {string} uvSnippet - Snippet defining the texture coordinates.
  769. * @return {string} The generated shader string.
  770. */
  771. generateTexture( /* texture, textureProperty, uvSnippet */ ) {
  772. console.warn( 'Abstract function.' );
  773. }
  774. /**
  775. * Generates a texture LOD shader string for the given texture data.
  776. *
  777. * @abstract
  778. * @param {Texture} texture - The texture.
  779. * @param {string} textureProperty - The texture property name.
  780. * @param {string} uvSnippet - Snippet defining the texture coordinates.
  781. * @param {?string} depthSnippet - Snippet defining the 0-based texture array index to sample.
  782. * @param {string} levelSnippet - Snippet defining the mip level.
  783. * @return {string} The generated shader string.
  784. */
  785. generateTextureLod( /* texture, textureProperty, uvSnippet, depthSnippet, levelSnippet */ ) {
  786. console.warn( 'Abstract function.' );
  787. }
  788. /**
  789. * Generates the array declaration string.
  790. *
  791. * @param {string} type - The type.
  792. * @param {?number} [count] - The count.
  793. * @return {string} The generated value as a shader string.
  794. */
  795. generateArrayDeclaration( type, count ) {
  796. return this.getType( type ) + '[ ' + count + ' ]';
  797. }
  798. /**
  799. * Generates the array shader string for the given type and value.
  800. *
  801. * @param {string} type - The type.
  802. * @param {?number} [count] - The count.
  803. * @param {?Array<Node>} [values=null] - The default values.
  804. * @return {string} The generated value as a shader string.
  805. */
  806. generateArray( type, count, values = null ) {
  807. let snippet = this.generateArrayDeclaration( type, count ) + '( ';
  808. for ( let i = 0; i < count; i ++ ) {
  809. const value = values ? values[ i ] : null;
  810. if ( value !== null ) {
  811. snippet += value.build( this, type );
  812. } else {
  813. snippet += this.generateConst( type );
  814. }
  815. if ( i < count - 1 ) snippet += ', ';
  816. }
  817. snippet += ' )';
  818. return snippet;
  819. }
  820. /**
  821. * Generates the struct shader string.
  822. *
  823. * @param {string} type - The type.
  824. * @param {Array<Object>} [membersLayout] - The count.
  825. * @param {?Array<Node>} [values=null] - The default values.
  826. * @return {string} The generated value as a shader string.
  827. */
  828. generateStruct( type, membersLayout, values = null ) {
  829. const snippets = [];
  830. for ( const member of membersLayout ) {
  831. const { name, type } = member;
  832. if ( values && values[ name ] && values[ name ].isNode ) {
  833. snippets.push( values[ name ].build( this, type ) );
  834. } else {
  835. snippets.push( this.generateConst( type ) );
  836. }
  837. }
  838. return type + '( ' + snippets.join( ', ' ) + ' )';
  839. }
  840. /**
  841. * Generates the shader string for the given type and value.
  842. *
  843. * @param {string} type - The type.
  844. * @param {?any} [value=null] - The value.
  845. * @return {string} The generated value as a shader string.
  846. */
  847. generateConst( type, value = null ) {
  848. if ( value === null ) {
  849. if ( type === 'float' || type === 'int' || type === 'uint' ) value = 0;
  850. else if ( type === 'bool' ) value = false;
  851. else if ( type === 'color' ) value = new Color();
  852. else if ( type === 'vec2' ) value = new Vector2();
  853. else if ( type === 'vec3' ) value = new Vector3();
  854. else if ( type === 'vec4' ) value = new Vector4();
  855. }
  856. if ( type === 'float' ) return toFloat( value );
  857. if ( type === 'int' ) return `${ Math.round( value ) }`;
  858. if ( type === 'uint' ) return value >= 0 ? `${ Math.round( value ) }u` : '0u';
  859. if ( type === 'bool' ) return value ? 'true' : 'false';
  860. if ( type === 'color' ) return `${ this.getType( 'vec3' ) }( ${ toFloat( value.r ) }, ${ toFloat( value.g ) }, ${ toFloat( value.b ) } )`;
  861. const typeLength = this.getTypeLength( type );
  862. const componentType = this.getComponentType( type );
  863. const generateConst = value => this.generateConst( componentType, value );
  864. if ( typeLength === 2 ) {
  865. return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) } )`;
  866. } else if ( typeLength === 3 ) {
  867. return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) } )`;
  868. } else if ( typeLength === 4 && type !== 'mat2' ) {
  869. return `${ this.getType( type ) }( ${ generateConst( value.x ) }, ${ generateConst( value.y ) }, ${ generateConst( value.z ) }, ${ generateConst( value.w ) } )`;
  870. } else if ( typeLength >= 4 && value && ( value.isMatrix2 || value.isMatrix3 || value.isMatrix4 ) ) {
  871. return `${ this.getType( type ) }( ${ value.elements.map( generateConst ).join( ', ' ) } )`;
  872. } else if ( typeLength > 4 ) {
  873. return `${ this.getType( type ) }()`;
  874. }
  875. throw new Error( `NodeBuilder: Type '${type}' not found in generate constant attempt.` );
  876. }
  877. /**
  878. * It might be necessary to convert certain data types to different ones
  879. * so this method can be used to hide the conversion.
  880. *
  881. * @param {string} type - The type.
  882. * @return {string} The updated type.
  883. */
  884. getType( type ) {
  885. if ( type === 'color' ) return 'vec3';
  886. return type;
  887. }
  888. /**
  889. * Whether the given attribute name is defined in the geometry or not.
  890. *
  891. * @param {string} name - The attribute name.
  892. * @return {boolean} Whether the given attribute name is defined in the geometry.
  893. */
  894. hasGeometryAttribute( name ) {
  895. return this.geometry && this.geometry.getAttribute( name ) !== undefined;
  896. }
  897. /**
  898. * Returns a node attribute for the given name and type.
  899. *
  900. * @param {string} name - The attribute's name.
  901. * @param {string} type - The attribute's type.
  902. * @return {NodeAttribute} The node attribute.
  903. */
  904. getAttribute( name, type ) {
  905. const attributes = this.attributes;
  906. // find attribute
  907. for ( const attribute of attributes ) {
  908. if ( attribute.name === name ) {
  909. return attribute;
  910. }
  911. }
  912. // create a new if no exist
  913. const attribute = new NodeAttribute( name, type );
  914. attributes.push( attribute );
  915. return attribute;
  916. }
  917. /**
  918. * Returns for the given node and shader stage the property name for the shader.
  919. *
  920. * @param {Node} node - The node.
  921. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  922. * @return {string} The property name.
  923. */
  924. getPropertyName( node/*, shaderStage*/ ) {
  925. return node.name;
  926. }
  927. /**
  928. * Whether the given type is a vector type or not.
  929. *
  930. * @param {string} type - The type to check.
  931. * @return {boolean} Whether the given type is a vector type or not.
  932. */
  933. isVector( type ) {
  934. return /vec\d/.test( type );
  935. }
  936. /**
  937. * Whether the given type is a matrix type or not.
  938. *
  939. * @param {string} type - The type to check.
  940. * @return {boolean} Whether the given type is a matrix type or not.
  941. */
  942. isMatrix( type ) {
  943. return /mat\d/.test( type );
  944. }
  945. /**
  946. * Whether the given type is a reference type or not.
  947. *
  948. * @param {string} type - The type to check.
  949. * @return {boolean} Whether the given type is a reference type or not.
  950. */
  951. isReference( type ) {
  952. return type === 'void' || type === 'property' || type === 'sampler' || type === 'samplerComparison' || type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'depthTexture' || type === 'texture3D';
  953. }
  954. /**
  955. * Checks if the given texture requires a manual conversion to the working color space.
  956. *
  957. * @abstract
  958. * @param {Texture} texture - The texture to check.
  959. * @return {boolean} Whether the given texture requires a conversion to working color space or not.
  960. */
  961. needsToWorkingColorSpace( /*texture*/ ) {
  962. return false;
  963. }
  964. /**
  965. * Returns the component type of a given texture.
  966. *
  967. * @param {Texture} texture - The texture.
  968. * @return {string} The component type.
  969. */
  970. getComponentTypeFromTexture( texture ) {
  971. const type = texture.type;
  972. if ( texture.isDataTexture ) {
  973. if ( type === IntType ) return 'int';
  974. if ( type === UnsignedIntType ) return 'uint';
  975. }
  976. return 'float';
  977. }
  978. /**
  979. * Returns the element type for a given type.
  980. *
  981. * @param {string} type - The type.
  982. * @return {string} The element type.
  983. */
  984. getElementType( type ) {
  985. if ( type === 'mat2' ) return 'vec2';
  986. if ( type === 'mat3' ) return 'vec3';
  987. if ( type === 'mat4' ) return 'vec4';
  988. return this.getComponentType( type );
  989. }
  990. /**
  991. * Returns the component type for a given type.
  992. *
  993. * @param {string} type - The type.
  994. * @return {string} The component type.
  995. */
  996. getComponentType( type ) {
  997. type = this.getVectorType( type );
  998. if ( type === 'float' || type === 'bool' || type === 'int' || type === 'uint' ) return type;
  999. const componentType = /(b|i|u|)(vec|mat)([2-4])/.exec( type );
  1000. if ( componentType === null ) return null;
  1001. if ( componentType[ 1 ] === 'b' ) return 'bool';
  1002. if ( componentType[ 1 ] === 'i' ) return 'int';
  1003. if ( componentType[ 1 ] === 'u' ) return 'uint';
  1004. return 'float';
  1005. }
  1006. /**
  1007. * Returns the vector type for a given type.
  1008. *
  1009. * @param {string} type - The type.
  1010. * @return {string} The vector type.
  1011. */
  1012. getVectorType( type ) {
  1013. if ( type === 'color' ) return 'vec3';
  1014. if ( type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D' ) return 'vec4';
  1015. return type;
  1016. }
  1017. /**
  1018. * Returns the data type for the given the length and component type.
  1019. *
  1020. * @param {number} length - The length.
  1021. * @param {string} [componentType='float'] - The component type.
  1022. * @return {string} The type.
  1023. */
  1024. getTypeFromLength( length, componentType = 'float' ) {
  1025. if ( length === 1 ) return componentType;
  1026. let baseType = getTypeFromLength( length );
  1027. const prefix = componentType === 'float' ? '' : componentType[ 0 ];
  1028. // fix edge case for mat2x2 being same size as vec4
  1029. if ( /mat2/.test( componentType ) === true ) {
  1030. baseType = baseType.replace( 'vec', 'mat' );
  1031. }
  1032. return prefix + baseType;
  1033. }
  1034. /**
  1035. * Returns the type for a given typed array.
  1036. *
  1037. * @param {TypedArray} array - The typed array.
  1038. * @return {string} The type.
  1039. */
  1040. getTypeFromArray( array ) {
  1041. return typeFromArray.get( array.constructor );
  1042. }
  1043. /**
  1044. * Returns the type for a given buffer attribute.
  1045. *
  1046. * @param {BufferAttribute} attribute - The buffer attribute.
  1047. * @return {string} The type.
  1048. */
  1049. getTypeFromAttribute( attribute ) {
  1050. let dataAttribute = attribute;
  1051. if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data;
  1052. const array = dataAttribute.array;
  1053. const itemSize = attribute.itemSize;
  1054. const normalized = attribute.normalized;
  1055. let arrayType;
  1056. if ( ! ( attribute instanceof Float16BufferAttribute ) && normalized !== true ) {
  1057. arrayType = this.getTypeFromArray( array );
  1058. }
  1059. return this.getTypeFromLength( itemSize, arrayType );
  1060. }
  1061. /**
  1062. * Returns the length for the given data type.
  1063. *
  1064. * @param {string} type - The data type.
  1065. * @return {number} The length.
  1066. */
  1067. getTypeLength( type ) {
  1068. const vecType = this.getVectorType( type );
  1069. const vecNum = /vec([2-4])/.exec( vecType );
  1070. if ( vecNum !== null ) return Number( vecNum[ 1 ] );
  1071. if ( vecType === 'float' || vecType === 'bool' || vecType === 'int' || vecType === 'uint' ) return 1;
  1072. if ( /mat2/.test( type ) === true ) return 4;
  1073. if ( /mat3/.test( type ) === true ) return 9;
  1074. if ( /mat4/.test( type ) === true ) return 16;
  1075. return 0;
  1076. }
  1077. /**
  1078. * Returns the vector type for a given matrix type.
  1079. *
  1080. * @param {string} type - The matrix type.
  1081. * @return {string} The vector type.
  1082. */
  1083. getVectorFromMatrix( type ) {
  1084. return type.replace( 'mat', 'vec' );
  1085. }
  1086. /**
  1087. * For a given type this method changes the component type to the
  1088. * given value. E.g. `vec4` should be changed to the new component type
  1089. * `uint` which results in `uvec4`.
  1090. *
  1091. * @param {string} type - The type.
  1092. * @param {string} newComponentType - The new component type.
  1093. * @return {string} The new type.
  1094. */
  1095. changeComponentType( type, newComponentType ) {
  1096. return this.getTypeFromLength( this.getTypeLength( type ), newComponentType );
  1097. }
  1098. /**
  1099. * Returns the integer type pendant for the given type.
  1100. *
  1101. * @param {string} type - The type.
  1102. * @return {string} The integer type.
  1103. */
  1104. getIntegerType( type ) {
  1105. const componentType = this.getComponentType( type );
  1106. if ( componentType === 'int' || componentType === 'uint' ) return type;
  1107. return this.changeComponentType( type, 'int' );
  1108. }
  1109. /**
  1110. * Adds a stack node to the internal stack.
  1111. *
  1112. * @return {StackNode} The added stack node.
  1113. */
  1114. addStack() {
  1115. this.stack = stack( this.stack );
  1116. this.stacks.push( getCurrentStack() || this.stack );
  1117. setCurrentStack( this.stack );
  1118. return this.stack;
  1119. }
  1120. /**
  1121. * Removes the last stack node from the internal stack.
  1122. *
  1123. * @return {StackNode} The removed stack node.
  1124. */
  1125. removeStack() {
  1126. const lastStack = this.stack;
  1127. this.stack = lastStack.parent;
  1128. setCurrentStack( this.stacks.pop() );
  1129. return lastStack;
  1130. }
  1131. /**
  1132. * The builder maintains (cached) data for each node during the building process. This method
  1133. * can be used to get these data for a specific shader stage and cache.
  1134. *
  1135. * @param {Node} node - The node to get the data for.
  1136. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
  1137. * @param {?NodeCache} cache - An optional cache.
  1138. * @return {Object} The node data.
  1139. */
  1140. getDataFromNode( node, shaderStage = this.shaderStage, cache = null ) {
  1141. cache = cache === null ? ( node.isGlobal( this ) ? this.globalCache : this.cache ) : cache;
  1142. let nodeData = cache.getData( node );
  1143. if ( nodeData === undefined ) {
  1144. nodeData = {};
  1145. cache.setData( node, nodeData );
  1146. }
  1147. if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {};
  1148. return nodeData[ shaderStage ];
  1149. }
  1150. /**
  1151. * Returns the properties for the given node and shader stage.
  1152. *
  1153. * @param {Node} node - The node to get the properties for.
  1154. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage='any'] - The shader stage.
  1155. * @return {Object} The node properties.
  1156. */
  1157. getNodeProperties( node, shaderStage = 'any' ) {
  1158. const nodeData = this.getDataFromNode( node, shaderStage );
  1159. return nodeData.properties || ( nodeData.properties = { outputNode: null } );
  1160. }
  1161. /**
  1162. * Returns an instance of {@link NodeAttribute} for the given buffer attribute node.
  1163. *
  1164. * @param {BufferAttributeNode} node - The buffer attribute node.
  1165. * @param {string} type - The node type.
  1166. * @return {NodeAttribute} The node attribute.
  1167. */
  1168. getBufferAttributeFromNode( node, type ) {
  1169. const nodeData = this.getDataFromNode( node );
  1170. let bufferAttribute = nodeData.bufferAttribute;
  1171. if ( bufferAttribute === undefined ) {
  1172. const index = this.uniforms.index ++;
  1173. bufferAttribute = new NodeAttribute( 'nodeAttribute' + index, type, node );
  1174. this.bufferAttributes.push( bufferAttribute );
  1175. nodeData.bufferAttribute = bufferAttribute;
  1176. }
  1177. return bufferAttribute;
  1178. }
  1179. /**
  1180. * Returns an instance of {@link StructType} for the given output struct node.
  1181. *
  1182. * @param {OutputStructNode} node - The output struct node.
  1183. * @param {Array<Object>} membersLayout - The output struct types.
  1184. * @param {?string} [name=null] - The name of the struct.
  1185. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
  1186. * @return {StructType} The struct type attribute.
  1187. */
  1188. getStructTypeFromNode( node, membersLayout, name = null, shaderStage = this.shaderStage ) {
  1189. const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache );
  1190. let structType = nodeData.structType;
  1191. if ( structType === undefined ) {
  1192. const index = this.structs.index ++;
  1193. if ( name === null ) name = 'StructType' + index;
  1194. structType = new StructType( name, membersLayout );
  1195. this.structs[ shaderStage ].push( structType );
  1196. nodeData.structType = structType;
  1197. }
  1198. return structType;
  1199. }
  1200. /**
  1201. * Returns an instance of {@link StructType} for the given output struct node.
  1202. *
  1203. * @param {OutputStructNode} node - The output struct node.
  1204. * @param {Array<Object>} membersLayout - The output struct types.
  1205. * @return {StructType} The struct type attribute.
  1206. */
  1207. getOutputStructTypeFromNode( node, membersLayout ) {
  1208. const structType = this.getStructTypeFromNode( node, membersLayout, 'OutputType', 'fragment' );
  1209. structType.output = true;
  1210. return structType;
  1211. }
  1212. /**
  1213. * Returns an instance of {@link NodeUniform} for the given uniform node.
  1214. *
  1215. * @param {UniformNode} node - The uniform node.
  1216. * @param {string} type - The uniform type.
  1217. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
  1218. * @param {?string} name - The name of the uniform.
  1219. * @return {NodeUniform} The node uniform.
  1220. */
  1221. getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) {
  1222. const nodeData = this.getDataFromNode( node, shaderStage, this.globalCache );
  1223. let nodeUniform = nodeData.uniform;
  1224. if ( nodeUniform === undefined ) {
  1225. const index = this.uniforms.index ++;
  1226. nodeUniform = new NodeUniform( name || ( 'nodeUniform' + index ), type, node );
  1227. this.uniforms[ shaderStage ].push( nodeUniform );
  1228. nodeData.uniform = nodeUniform;
  1229. }
  1230. return nodeUniform;
  1231. }
  1232. /**
  1233. * Returns the array length.
  1234. *
  1235. * @param {Node} node - The node.
  1236. * @return {?number} The array length.
  1237. */
  1238. getArrayCount( node ) {
  1239. let count = null;
  1240. if ( node.isArrayNode ) count = node.count;
  1241. else if ( node.isVarNode && node.node.isArrayNode ) count = node.node.count;
  1242. return count;
  1243. }
  1244. /**
  1245. * Returns an instance of {@link NodeVar} for the given variable node.
  1246. *
  1247. * @param {VarNode} node - The variable node.
  1248. * @param {?string} name - The variable's name.
  1249. * @param {string} [type=node.getNodeType( this )] - The variable's type.
  1250. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
  1251. * @param {boolean} [readOnly=false] - Whether the variable is read-only or not.
  1252. *
  1253. * @return {NodeVar} The node variable.
  1254. */
  1255. getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) {
  1256. const nodeData = this.getDataFromNode( node, shaderStage );
  1257. let nodeVar = nodeData.variable;
  1258. if ( nodeVar === undefined ) {
  1259. const idNS = readOnly ? '_const' : '_var';
  1260. const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] );
  1261. const id = this.vars[ idNS ] || ( this.vars[ idNS ] = 0 );
  1262. if ( name === null ) {
  1263. name = ( readOnly ? 'nodeConst' : 'nodeVar' ) + id;
  1264. this.vars[ idNS ] ++;
  1265. }
  1266. //
  1267. const count = this.getArrayCount( node );
  1268. nodeVar = new NodeVar( name, type, readOnly, count );
  1269. if ( ! readOnly ) {
  1270. vars.push( nodeVar );
  1271. }
  1272. nodeData.variable = nodeVar;
  1273. }
  1274. return nodeVar;
  1275. }
  1276. /**
  1277. * Returns whether a Node or its flow is deterministic, useful for use in `const`.
  1278. *
  1279. * @param {Node} node - The varying node.
  1280. * @return {boolean} Returns true if deterministic.
  1281. */
  1282. isDeterministic( node ) {
  1283. if ( node.isMathNode ) {
  1284. return this.isDeterministic( node.aNode ) &&
  1285. ( node.bNode ? this.isDeterministic( node.bNode ) : true ) &&
  1286. ( node.cNode ? this.isDeterministic( node.cNode ) : true );
  1287. } else if ( node.isOperatorNode ) {
  1288. return this.isDeterministic( node.aNode ) &&
  1289. ( node.bNode ? this.isDeterministic( node.bNode ) : true );
  1290. } else if ( node.isArrayNode ) {
  1291. if ( node.values !== null ) {
  1292. for ( const n of node.values ) {
  1293. if ( ! this.isDeterministic( n ) ) {
  1294. return false;
  1295. }
  1296. }
  1297. }
  1298. return true;
  1299. } else if ( node.isConstNode ) {
  1300. return true;
  1301. }
  1302. return false;
  1303. }
  1304. /**
  1305. * Returns an instance of {@link NodeVarying} for the given varying node.
  1306. *
  1307. * @param {(VaryingNode|PropertyNode)} node - The varying node.
  1308. * @param {?string} name - The varying's name.
  1309. * @param {string} [type=node.getNodeType( this )] - The varying's type.
  1310. * @return {NodeVar} The node varying.
  1311. */
  1312. getVaryingFromNode( node, name = null, type = node.getNodeType( this ) ) {
  1313. const nodeData = this.getDataFromNode( node, 'any' );
  1314. let nodeVarying = nodeData.varying;
  1315. if ( nodeVarying === undefined ) {
  1316. const varyings = this.varyings;
  1317. const index = varyings.length;
  1318. if ( name === null ) name = 'nodeVarying' + index;
  1319. nodeVarying = new NodeVarying( name, type );
  1320. varyings.push( nodeVarying );
  1321. nodeData.varying = nodeVarying;
  1322. }
  1323. return nodeVarying;
  1324. }
  1325. /**
  1326. * Returns an instance of {@link NodeCode} for the given code node.
  1327. *
  1328. * @param {CodeNode} node - The code node.
  1329. * @param {string} type - The node type.
  1330. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage.
  1331. * @return {NodeCode} The node code.
  1332. */
  1333. getCodeFromNode( node, type, shaderStage = this.shaderStage ) {
  1334. const nodeData = this.getDataFromNode( node );
  1335. let nodeCode = nodeData.code;
  1336. if ( nodeCode === undefined ) {
  1337. const codes = this.codes[ shaderStage ] || ( this.codes[ shaderStage ] = [] );
  1338. const index = codes.length;
  1339. nodeCode = new NodeCode( 'nodeCode' + index, type );
  1340. codes.push( nodeCode );
  1341. nodeData.code = nodeCode;
  1342. }
  1343. return nodeCode;
  1344. }
  1345. /**
  1346. * Adds a code flow based on the code-block hierarchy.
  1347. * This is used so that code-blocks like If,Else create their variables locally if the Node
  1348. * is only used inside one of these conditionals in the current shader stage.
  1349. *
  1350. * @param {Node} node - The node to add.
  1351. * @param {Node} nodeBlock - Node-based code-block. Usually 'ConditionalNode'.
  1352. */
  1353. addFlowCodeHierarchy( node, nodeBlock ) {
  1354. const { flowCodes, flowCodeBlock } = this.getDataFromNode( node );
  1355. let needsFlowCode = true;
  1356. let nodeBlockHierarchy = nodeBlock;
  1357. while ( nodeBlockHierarchy ) {
  1358. if ( flowCodeBlock.get( nodeBlockHierarchy ) === true ) {
  1359. needsFlowCode = false;
  1360. break;
  1361. }
  1362. nodeBlockHierarchy = this.getDataFromNode( nodeBlockHierarchy ).parentNodeBlock;
  1363. }
  1364. if ( needsFlowCode ) {
  1365. for ( const flowCode of flowCodes ) {
  1366. this.addLineFlowCode( flowCode );
  1367. }
  1368. }
  1369. }
  1370. /**
  1371. * Add a inline-code to the current flow code-block.
  1372. *
  1373. * @param {Node} node - The node to add.
  1374. * @param {string} code - The code to add.
  1375. * @param {Node} nodeBlock - Current ConditionalNode
  1376. */
  1377. addLineFlowCodeBlock( node, code, nodeBlock ) {
  1378. const nodeData = this.getDataFromNode( node );
  1379. const flowCodes = nodeData.flowCodes || ( nodeData.flowCodes = [] );
  1380. const codeBlock = nodeData.flowCodeBlock || ( nodeData.flowCodeBlock = new WeakMap() );
  1381. flowCodes.push( code );
  1382. codeBlock.set( nodeBlock, true );
  1383. }
  1384. /**
  1385. * Add a inline-code to the current flow.
  1386. *
  1387. * @param {string} code - The code to add.
  1388. * @param {?Node} [node= null] - Optional Node, can help the system understand if the Node is part of a code-block.
  1389. * @return {NodeBuilder} A reference to this node builder.
  1390. */
  1391. addLineFlowCode( code, node = null ) {
  1392. if ( code === '' ) return this;
  1393. if ( node !== null && this.context.nodeBlock ) {
  1394. this.addLineFlowCodeBlock( node, code, this.context.nodeBlock );
  1395. }
  1396. code = this.tab + code;
  1397. if ( ! /;\s*$/.test( code ) ) {
  1398. code = code + ';\n';
  1399. }
  1400. this.flow.code += code;
  1401. return this;
  1402. }
  1403. /**
  1404. * Adds a code to the current code flow.
  1405. *
  1406. * @param {string} code - Shader code.
  1407. * @return {NodeBuilder} A reference to this node builder.
  1408. */
  1409. addFlowCode( code ) {
  1410. this.flow.code += code;
  1411. return this;
  1412. }
  1413. /**
  1414. * Add tab in the code that will be generated so that other snippets respect the current tabulation.
  1415. * Typically used in codes with If,Else.
  1416. *
  1417. * @return {NodeBuilder} A reference to this node builder.
  1418. */
  1419. addFlowTab() {
  1420. this.tab += '\t';
  1421. return this;
  1422. }
  1423. /**
  1424. * Removes a tab.
  1425. *
  1426. * @return {NodeBuilder} A reference to this node builder.
  1427. */
  1428. removeFlowTab() {
  1429. this.tab = this.tab.slice( 0, - 1 );
  1430. return this;
  1431. }
  1432. /**
  1433. * Gets the current flow data based on a Node.
  1434. *
  1435. * @param {Node} node - Node that the flow was started.
  1436. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1437. * @return {Object} The flow data.
  1438. */
  1439. getFlowData( node/*, shaderStage*/ ) {
  1440. return this.flowsData.get( node );
  1441. }
  1442. /**
  1443. * Executes the node flow based on a root node to generate the final shader code.
  1444. *
  1445. * @param {Node} node - The node to execute.
  1446. * @return {Object} The code flow.
  1447. */
  1448. flowNode( node ) {
  1449. const output = node.getNodeType( this );
  1450. const flowData = this.flowChildNode( node, output );
  1451. this.flowsData.set( node, flowData );
  1452. return flowData;
  1453. }
  1454. /**
  1455. * Includes a node in the current function node.
  1456. *
  1457. * @param {Node} node - The node to include.
  1458. * @returns {void}
  1459. */
  1460. addInclude( node ) {
  1461. if ( this.currentFunctionNode !== null ) {
  1462. this.currentFunctionNode.includes.push( node );
  1463. }
  1464. }
  1465. /**
  1466. * Returns the native shader operator name for a given generic name.
  1467. * It is a similar type of method like {@link NodeBuilder#getMethod}.
  1468. *
  1469. * @param {ShaderNodeInternal} shaderNode - The shader node to build the function node with.
  1470. * @return {FunctionNode} The build function node.
  1471. */
  1472. buildFunctionNode( shaderNode ) {
  1473. const fn = new FunctionNode();
  1474. const previous = this.currentFunctionNode;
  1475. this.currentFunctionNode = fn;
  1476. fn.code = this.buildFunctionCode( shaderNode );
  1477. this.currentFunctionNode = previous;
  1478. return fn;
  1479. }
  1480. /**
  1481. * Generates a code flow based on a TSL function: Fn().
  1482. *
  1483. * @param {ShaderNodeInternal} shaderNode - A function code will be generated based on the input.
  1484. * @return {Object}
  1485. */
  1486. flowShaderNode( shaderNode ) {
  1487. const layout = shaderNode.layout;
  1488. const inputs = {
  1489. [ Symbol.iterator ]() {
  1490. let index = 0;
  1491. const values = Object.values( this );
  1492. return {
  1493. next: () => ( {
  1494. value: values[ index ],
  1495. done: index ++ >= values.length
  1496. } )
  1497. };
  1498. }
  1499. };
  1500. for ( const input of layout.inputs ) {
  1501. inputs[ input.name ] = new ParameterNode( input.type, input.name );
  1502. }
  1503. //
  1504. shaderNode.layout = null;
  1505. const callNode = shaderNode.call( inputs );
  1506. const flowData = this.flowStagesNode( callNode, layout.type );
  1507. shaderNode.layout = layout;
  1508. return flowData;
  1509. }
  1510. /**
  1511. * Runs the node flow through all the steps of creation, 'setup', 'analyze', 'generate'.
  1512. *
  1513. * @param {Node} node - The node to execute.
  1514. * @param {?string} output - Expected output type. For example 'vec3'.
  1515. * @return {Object}
  1516. */
  1517. flowStagesNode( node, output = null ) {
  1518. const previousFlow = this.flow;
  1519. const previousVars = this.vars;
  1520. const previousCache = this.cache;
  1521. const previousBuildStage = this.buildStage;
  1522. const previousStack = this.stack;
  1523. const flow = {
  1524. code: ''
  1525. };
  1526. this.flow = flow;
  1527. this.vars = {};
  1528. this.cache = new NodeCache();
  1529. this.stack = stack();
  1530. for ( const buildStage of defaultBuildStages ) {
  1531. this.setBuildStage( buildStage );
  1532. flow.result = node.build( this, output );
  1533. }
  1534. flow.vars = this.getVars( this.shaderStage );
  1535. this.flow = previousFlow;
  1536. this.vars = previousVars;
  1537. this.cache = previousCache;
  1538. this.stack = previousStack;
  1539. this.setBuildStage( previousBuildStage );
  1540. return flow;
  1541. }
  1542. /**
  1543. * Returns the native shader operator name for a given generic name.
  1544. * It is a similar type of method like {@link NodeBuilder#getMethod}.
  1545. *
  1546. * @abstract
  1547. * @param {string} op - The operator name to resolve.
  1548. * @return {?string} The resolved operator name.
  1549. */
  1550. getFunctionOperator( /* op */ ) {
  1551. return null;
  1552. }
  1553. /**
  1554. * Builds the given shader node.
  1555. *
  1556. * @abstract
  1557. * @param {ShaderNodeInternal} shaderNode - The shader node.
  1558. * @return {string} The function code.
  1559. */
  1560. buildFunctionCode( /* shaderNode */ ) {
  1561. console.warn( 'Abstract function.' );
  1562. }
  1563. /**
  1564. * Generates a code flow based on a child Node.
  1565. *
  1566. * @param {Node} node - The node to execute.
  1567. * @param {?string} output - Expected output type. For example 'vec3'.
  1568. * @return {Object} The code flow.
  1569. */
  1570. flowChildNode( node, output = null ) {
  1571. const previousFlow = this.flow;
  1572. const flow = {
  1573. code: ''
  1574. };
  1575. this.flow = flow;
  1576. flow.result = node.build( this, output );
  1577. this.flow = previousFlow;
  1578. return flow;
  1579. }
  1580. /**
  1581. * Executes a flow of code in a different stage.
  1582. *
  1583. * Some nodes like `varying()` have the ability to compute code in vertex-stage and
  1584. * return the value in fragment-stage even if it is being executed in an input fragment.
  1585. *
  1586. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1587. * @param {Node} node - The node to execute.
  1588. * @param {?string} output - Expected output type. For example 'vec3'.
  1589. * @param {?string} propertyName - The property name to assign the result.
  1590. * @return {Object}
  1591. */
  1592. flowNodeFromShaderStage( shaderStage, node, output = null, propertyName = null ) {
  1593. const previousShaderStage = this.shaderStage;
  1594. this.setShaderStage( shaderStage );
  1595. const flowData = this.flowChildNode( node, output );
  1596. if ( propertyName !== null ) {
  1597. flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`;
  1598. }
  1599. this.flowCode[ shaderStage ] = this.flowCode[ shaderStage ] + flowData.code;
  1600. this.setShaderStage( previousShaderStage );
  1601. return flowData;
  1602. }
  1603. /**
  1604. * Returns an array holding all node attributes of this node builder.
  1605. *
  1606. * @return {Array<NodeAttribute>} The node attributes of this builder.
  1607. */
  1608. getAttributesArray() {
  1609. return this.attributes.concat( this.bufferAttributes );
  1610. }
  1611. /**
  1612. * Returns the attribute definitions as a shader string for the given shader stage.
  1613. *
  1614. * @abstract
  1615. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1616. * @return {string} The attribute code section.
  1617. */
  1618. getAttributes( /*shaderStage*/ ) {
  1619. console.warn( 'Abstract function.' );
  1620. }
  1621. /**
  1622. * Returns the varying definitions as a shader string for the given shader stage.
  1623. *
  1624. * @abstract
  1625. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1626. * @return {string} The varying code section.
  1627. */
  1628. getVaryings( /*shaderStage*/ ) {
  1629. console.warn( 'Abstract function.' );
  1630. }
  1631. /**
  1632. * Returns a single variable definition as a shader string for the given variable type and name.
  1633. *
  1634. * @param {string} type - The variable's type.
  1635. * @param {string} name - The variable's name.
  1636. * @param {?number} [count=null] - The array length.
  1637. * @return {string} The shader string.
  1638. */
  1639. getVar( type, name, count = null ) {
  1640. return `${ count !== null ? this.generateArrayDeclaration( type, count ) : this.getType( type ) } ${ name }`;
  1641. }
  1642. /**
  1643. * Returns the variable definitions as a shader string for the given shader stage.
  1644. *
  1645. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1646. * @return {string} The variable code section.
  1647. */
  1648. getVars( shaderStage ) {
  1649. let snippet = '';
  1650. const vars = this.vars[ shaderStage ];
  1651. if ( vars !== undefined ) {
  1652. for ( const variable of vars ) {
  1653. snippet += `${ this.getVar( variable.type, variable.name ) }; `;
  1654. }
  1655. }
  1656. return snippet;
  1657. }
  1658. /**
  1659. * Returns the uniform definitions as a shader string for the given shader stage.
  1660. *
  1661. * @abstract
  1662. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1663. * @return {string} The uniform code section.
  1664. */
  1665. getUniforms( /*shaderStage*/ ) {
  1666. console.warn( 'Abstract function.' );
  1667. }
  1668. /**
  1669. * Returns the native code definitions as a shader string for the given shader stage.
  1670. *
  1671. * @param {('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage.
  1672. * @return {string} The native code section.
  1673. */
  1674. getCodes( shaderStage ) {
  1675. const codes = this.codes[ shaderStage ];
  1676. let code = '';
  1677. if ( codes !== undefined ) {
  1678. for ( const nodeCode of codes ) {
  1679. code += nodeCode.code + '\n';
  1680. }
  1681. }
  1682. return code;
  1683. }
  1684. /**
  1685. * Returns the hash of this node builder.
  1686. *
  1687. * @return {string} The hash.
  1688. */
  1689. getHash() {
  1690. return this.vertexShader + this.fragmentShader + this.computeShader;
  1691. }
  1692. /**
  1693. * Sets the current shader stage.
  1694. *
  1695. * @param {?('vertex'|'fragment'|'compute'|'any')} shaderStage - The shader stage to set.
  1696. */
  1697. setShaderStage( shaderStage ) {
  1698. this.shaderStage = shaderStage;
  1699. }
  1700. /**
  1701. * Returns the current shader stage.
  1702. *
  1703. * @return {?('vertex'|'fragment'|'compute'|'any')} The current shader stage.
  1704. */
  1705. getShaderStage() {
  1706. return this.shaderStage;
  1707. }
  1708. /**
  1709. * Sets the current build stage.
  1710. *
  1711. * @param {?('setup'|'analyze'|'generate')} buildStage - The build stage to set.
  1712. */
  1713. setBuildStage( buildStage ) {
  1714. this.buildStage = buildStage;
  1715. }
  1716. /**
  1717. * Returns the current build stage.
  1718. *
  1719. * @return {?('setup'|'analyze'|'generate')} The current build stage.
  1720. */
  1721. getBuildStage() {
  1722. return this.buildStage;
  1723. }
  1724. /**
  1725. * Controls the code build of the shader stages.
  1726. *
  1727. * @abstract
  1728. */
  1729. buildCode() {
  1730. console.warn( 'Abstract function.' );
  1731. }
  1732. /**
  1733. * Central build method which controls the build for the given object.
  1734. *
  1735. * @return {NodeBuilder} A reference to this node builder.
  1736. */
  1737. build() {
  1738. const { object, material, renderer } = this;
  1739. if ( material !== null ) {
  1740. let nodeMaterial = renderer.library.fromMaterial( material );
  1741. if ( nodeMaterial === null ) {
  1742. console.error( `NodeMaterial: Material "${ material.type }" is not compatible.` );
  1743. nodeMaterial = new NodeMaterial();
  1744. }
  1745. nodeMaterial.build( this );
  1746. } else {
  1747. this.addFlow( 'compute', object );
  1748. }
  1749. // setup() -> stage 1: create possible new nodes and returns an output reference node
  1750. // analyze() -> stage 2: analyze nodes to possible optimization and validation
  1751. // generate() -> stage 3: generate shader
  1752. for ( const buildStage of defaultBuildStages ) {
  1753. this.setBuildStage( buildStage );
  1754. if ( this.context.vertex && this.context.vertex.isNode ) {
  1755. this.flowNodeFromShaderStage( 'vertex', this.context.vertex );
  1756. }
  1757. for ( const shaderStage of shaderStages ) {
  1758. this.setShaderStage( shaderStage );
  1759. const flowNodes = this.flowNodes[ shaderStage ];
  1760. for ( const node of flowNodes ) {
  1761. if ( buildStage === 'generate' ) {
  1762. this.flowNode( node );
  1763. } else {
  1764. node.build( this );
  1765. }
  1766. }
  1767. }
  1768. }
  1769. this.setBuildStage( null );
  1770. this.setShaderStage( null );
  1771. // stage 4: build code for a specific output
  1772. this.buildCode();
  1773. this.buildUpdateNodes();
  1774. return this;
  1775. }
  1776. /**
  1777. * Returns a uniform representation which is later used for UBO generation and rendering.
  1778. *
  1779. * @param {NodeUniform} uniformNode - The uniform node.
  1780. * @param {string} type - The requested type.
  1781. * @return {Uniform} The uniform.
  1782. */
  1783. getNodeUniform( uniformNode, type ) {
  1784. if ( type === 'float' || type === 'int' || type === 'uint' ) return new NumberNodeUniform( uniformNode );
  1785. if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return new Vector2NodeUniform( uniformNode );
  1786. if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return new Vector3NodeUniform( uniformNode );
  1787. if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return new Vector4NodeUniform( uniformNode );
  1788. if ( type === 'color' ) return new ColorNodeUniform( uniformNode );
  1789. if ( type === 'mat2' ) return new Matrix2NodeUniform( uniformNode );
  1790. if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode );
  1791. if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode );
  1792. throw new Error( `Uniform "${type}" not declared.` );
  1793. }
  1794. /**
  1795. * Formats the given shader snippet from a given type into another one. E.g.
  1796. * this method might be used to convert a simple float string `"1.0"` into a
  1797. * `vec3` representation: `"vec3<f32>( 1.0 )"`.
  1798. *
  1799. * @param {string} snippet - The shader snippet.
  1800. * @param {string} fromType - The source type.
  1801. * @param {string} toType - The target type.
  1802. * @return {string} The updated shader string.
  1803. */
  1804. format( snippet, fromType, toType ) {
  1805. fromType = this.getVectorType( fromType );
  1806. toType = this.getVectorType( toType );
  1807. if ( fromType === toType || toType === null || this.isReference( toType ) ) {
  1808. return snippet;
  1809. }
  1810. const fromTypeLength = this.getTypeLength( fromType );
  1811. const toTypeLength = this.getTypeLength( toType );
  1812. if ( fromTypeLength === 16 && toTypeLength === 9 ) {
  1813. return `${ this.getType( toType ) }(${ snippet }[0].xyz, ${ snippet }[1].xyz, ${ snippet }[2].xyz)`;
  1814. }
  1815. if ( fromTypeLength === 9 && toTypeLength === 4 ) {
  1816. return `${ this.getType( toType ) }(${ snippet }[0].xy, ${ snippet }[1].xy)`;
  1817. }
  1818. if ( fromTypeLength > 4 ) { // fromType is matrix-like
  1819. // @TODO: ignore for now
  1820. return snippet;
  1821. }
  1822. if ( toTypeLength > 4 || toTypeLength === 0 ) { // toType is matrix-like or unknown
  1823. // @TODO: ignore for now
  1824. return snippet;
  1825. }
  1826. if ( fromTypeLength === toTypeLength ) {
  1827. return `${ this.getType( toType ) }( ${ snippet } )`;
  1828. }
  1829. if ( fromTypeLength > toTypeLength ) {
  1830. return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength, this.getComponentType( fromType ) ), toType );
  1831. }
  1832. if ( toTypeLength === 4 && fromTypeLength > 1 ) { // toType is vec4-like
  1833. return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec3' ) }, 1.0 )`;
  1834. }
  1835. if ( fromTypeLength === 2 ) { // fromType is vec2-like and toType is vec3-like
  1836. return `${ this.getType( toType ) }( ${ this.format( snippet, fromType, 'vec2' ) }, 0.0 )`;
  1837. }
  1838. if ( fromTypeLength === 1 && toTypeLength > 1 && fromType !== this.getComponentType( toType ) ) { // fromType is float-like
  1839. // convert a number value to vector type, e.g:
  1840. // vec3( 1u ) -> vec3( float( 1u ) )
  1841. snippet = `${ this.getType( this.getComponentType( toType ) ) }( ${ snippet } )`;
  1842. }
  1843. return `${ this.getType( toType ) }( ${ snippet } )`; // fromType is float-like
  1844. }
  1845. /**
  1846. * Returns a signature with the engine's current revision.
  1847. *
  1848. * @return {string} The signature.
  1849. */
  1850. getSignature() {
  1851. return `// Three.js r${ REVISION } - Node System\n`;
  1852. }
  1853. // Deprecated
  1854. /**
  1855. * @function
  1856. * @deprecated since r168. Use `new NodeMaterial()` instead, with targeted node material name.
  1857. *
  1858. * @param {string} [type='NodeMaterial'] - The node material type.
  1859. * @throws {Error}
  1860. */
  1861. createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168
  1862. throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` );
  1863. }
  1864. }
  1865. export default NodeBuilder;
粤ICP备19079148号