TextureNode.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. import UniformNode, { uniform } from '../core/UniformNode.js';
  2. import { uv } from './UV.js';
  3. import { textureSize } from './TextureSizeNode.js';
  4. import { colorSpaceToWorking } from '../display/ColorSpaceNode.js';
  5. import { expression } from '../code/ExpressionNode.js';
  6. import { maxMipLevel } from '../utils/MaxMipLevelNode.js';
  7. import { nodeProxy, vec3, nodeObject, int } from '../tsl/TSLBase.js';
  8. import { NodeUpdateType } from '../core/constants.js';
  9. import { IntType, NearestFilter, UnsignedIntType } from '../../constants.js';
  10. import { Texture } from '../../textures/Texture.js';
  11. import { warn } from '../../utils.js';
  12. const EmptyTexture = /*@__PURE__*/ new Texture();
  13. /**
  14. * This type of uniform node represents a 2D texture.
  15. *
  16. * @augments UniformNode
  17. */
  18. class TextureNode extends UniformNode {
  19. static get type() {
  20. return 'TextureNode';
  21. }
  22. /**
  23. * Constructs a new texture node.
  24. *
  25. * @param {Texture} [value=EmptyTexture] - The texture.
  26. * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node.
  27. * @param {?Node<int>} [levelNode=null] - The level node.
  28. * @param {?Node<float>} [biasNode=null] - The bias node.
  29. */
  30. constructor( value = EmptyTexture, uvNode = null, levelNode = null, biasNode = null ) {
  31. super( value );
  32. /**
  33. * This flag can be used for type testing.
  34. *
  35. * @type {boolean}
  36. * @readonly
  37. * @default true
  38. */
  39. this.isTextureNode = true;
  40. /**
  41. * Represents the texture coordinates.
  42. *
  43. * @type {?Node<vec2|vec3>}
  44. * @default null
  45. */
  46. this.uvNode = uvNode;
  47. /**
  48. * Represents the mip level that should be selected.
  49. *
  50. * @type {?Node<int>}
  51. * @default null
  52. */
  53. this.levelNode = levelNode;
  54. /**
  55. * Represents the bias to be applied during level-of-detail computation.
  56. *
  57. * @type {?Node<float>}
  58. * @default null
  59. */
  60. this.biasNode = biasNode;
  61. /**
  62. * Represents a reference value a texture sample is compared to.
  63. *
  64. * @type {?Node<float>}
  65. * @default null
  66. */
  67. this.compareNode = null;
  68. /**
  69. * When using texture arrays, the depth node defines the layer to select.
  70. *
  71. * @type {?Node<int>}
  72. * @default null
  73. */
  74. this.depthNode = null;
  75. /**
  76. * When defined, a texture is sampled using explicit gradients.
  77. *
  78. * @type {?Array<Node<vec2>>}
  79. * @default null
  80. */
  81. this.gradNode = null;
  82. /**
  83. * Represents the optional texel offset applied to the unnormalized texture
  84. * coordinate before sampling the texture.
  85. *
  86. * @type {?Node<ivec2|ivec3>}
  87. * @default null
  88. */
  89. this.offsetNode = null;
  90. /**
  91. * Whether texture values should be sampled or fetched.
  92. *
  93. * @type {boolean}
  94. * @default true
  95. */
  96. this.sampler = true;
  97. /**
  98. * Whether the uv transformation matrix should be
  99. * automatically updated or not. Use `setUpdateMatrix()`
  100. * if you want to change the value of the property.
  101. *
  102. * @type {boolean}
  103. * @default false
  104. */
  105. this.updateMatrix = false;
  106. /**
  107. * By default the `update()` method is not executed. `setUpdateMatrix()`
  108. * sets the value to `frame` when the uv transformation matrix should
  109. * automatically be updated.
  110. *
  111. * @type {string}
  112. * @default 'none'
  113. */
  114. this.updateType = NodeUpdateType.NONE;
  115. /**
  116. * The reference node.
  117. *
  118. * @type {?Node}
  119. * @default null
  120. */
  121. this.referenceNode = null;
  122. /**
  123. * The texture value is stored in a private property.
  124. *
  125. * @private
  126. * @type {Texture}
  127. */
  128. this._value = value;
  129. /**
  130. * The uniform node that represents the uv transformation matrix.
  131. *
  132. * @private
  133. * @type {?UniformNode<mat3>}
  134. */
  135. this._matrixUniform = null;
  136. this.setUpdateMatrix( uvNode === null );
  137. }
  138. set value( value ) {
  139. if ( this.referenceNode ) {
  140. this.referenceNode.value = value;
  141. } else {
  142. this._value = value;
  143. }
  144. }
  145. /**
  146. * The texture value.
  147. *
  148. * @type {Texture}
  149. */
  150. get value() {
  151. return this.referenceNode ? this.referenceNode.value : this._value;
  152. }
  153. /**
  154. * Overwritten since the uniform hash is defined by the texture's UUID.
  155. *
  156. * @param {NodeBuilder} builder - The current node builder.
  157. * @return {string} The uniform hash.
  158. */
  159. getUniformHash( /*builder*/ ) {
  160. return this.value.uuid;
  161. }
  162. /**
  163. * Overwritten since the node type is inferred from the texture type.
  164. *
  165. * @param {NodeBuilder} builder - The current node builder.
  166. * @return {string} The node type.
  167. */
  168. getNodeType( /*builder*/ ) {
  169. if ( this.value.isDepthTexture === true ) return 'float';
  170. if ( this.value.type === UnsignedIntType ) {
  171. return 'uvec4';
  172. } else if ( this.value.type === IntType ) {
  173. return 'ivec4';
  174. }
  175. return 'vec4';
  176. }
  177. /**
  178. * Overwrites the default implementation to return a fixed value `'texture'`.
  179. *
  180. * @param {NodeBuilder} builder - The current node builder.
  181. * @return {string} The input type.
  182. */
  183. getInputType( /*builder*/ ) {
  184. return 'texture';
  185. }
  186. /**
  187. * Returns a default uvs based on the current texture's channel.
  188. *
  189. * @return {AttributeNode<vec2>} The default uvs.
  190. */
  191. getDefaultUV() {
  192. return uv( this.value.channel );
  193. }
  194. /**
  195. * Overwritten to always return the texture reference of the node.
  196. *
  197. * @param {any} state - This method can be invocated in different contexts so `state` can refer to any object type.
  198. * @return {Texture} The texture reference.
  199. */
  200. updateReference( /*state*/ ) {
  201. return this.value;
  202. }
  203. /**
  204. * Transforms the given uv node with the texture transformation matrix.
  205. *
  206. * @param {Node} uvNode - The uv node to transform.
  207. * @return {Node} The transformed uv node.
  208. */
  209. getTransformedUV( uvNode ) {
  210. if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix );
  211. return this._matrixUniform.mul( vec3( uvNode, 1 ) ).xy;
  212. }
  213. /**
  214. * Defines whether the uv transformation matrix should automatically be updated or not.
  215. *
  216. * @param {boolean} value - The update toggle.
  217. * @return {TextureNode} A reference to this node.
  218. */
  219. setUpdateMatrix( value ) {
  220. this.updateMatrix = value;
  221. this.updateType = value ? NodeUpdateType.OBJECT : NodeUpdateType.NONE;
  222. return this;
  223. }
  224. /**
  225. * Setups the uv node. Depending on the backend as well as texture's image and type, it might be necessary
  226. * to modify the uv node for correct sampling.
  227. *
  228. * @param {NodeBuilder} builder - The current node builder.
  229. * @param {Node} uvNode - The uv node to setup.
  230. * @return {Node} The updated uv node.
  231. */
  232. setupUV( builder, uvNode ) {
  233. const texture = this.value;
  234. if ( builder.isFlipY() && ( ( texture.image instanceof ImageBitmap && texture.flipY === true ) || texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) {
  235. if ( this.sampler ) {
  236. uvNode = uvNode.flipY();
  237. } else {
  238. uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) );
  239. }
  240. }
  241. return uvNode;
  242. }
  243. /**
  244. * Setups texture node by preparing the internal nodes for code generation.
  245. *
  246. * @param {NodeBuilder} builder - The current node builder.
  247. */
  248. setup( builder ) {
  249. const properties = builder.getNodeProperties( this );
  250. properties.referenceNode = this.referenceNode;
  251. //
  252. const texture = this.value;
  253. if ( ! texture || texture.isTexture !== true ) {
  254. throw new Error( 'THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().' );
  255. }
  256. //
  257. let uvNode = this.uvNode;
  258. if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) {
  259. uvNode = builder.context.getUV( this, builder );
  260. }
  261. if ( ! uvNode ) uvNode = this.getDefaultUV();
  262. if ( this.updateMatrix === true ) {
  263. uvNode = this.getTransformedUV( uvNode );
  264. }
  265. uvNode = this.setupUV( builder, uvNode );
  266. //
  267. let levelNode = this.levelNode;
  268. if ( levelNode === null && builder.context.getTextureLevel ) {
  269. levelNode = builder.context.getTextureLevel( this );
  270. }
  271. //
  272. properties.uvNode = uvNode;
  273. properties.levelNode = levelNode;
  274. properties.biasNode = this.biasNode;
  275. properties.compareNode = this.compareNode;
  276. properties.gradNode = this.gradNode;
  277. properties.depthNode = this.depthNode;
  278. properties.offsetNode = this.offsetNode;
  279. }
  280. /**
  281. * Generates the uv code snippet.
  282. *
  283. * @param {NodeBuilder} builder - The current node builder.
  284. * @param {Node} uvNode - The uv node to generate code for.
  285. * @return {string} The generated code snippet.
  286. */
  287. generateUV( builder, uvNode ) {
  288. return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' );
  289. }
  290. /**
  291. * Generates the offset code snippet.
  292. *
  293. * @param {NodeBuilder} builder - The current node builder.
  294. * @param {Node} offsetNode - The offset node to generate code for.
  295. * @return {string} The generated code snippet.
  296. */
  297. generateOffset( builder, offsetNode ) {
  298. return offsetNode.build( builder, 'ivec2' );
  299. }
  300. /**
  301. * Generates the snippet for the texture sampling.
  302. *
  303. * @param {NodeBuilder} builder - The current node builder.
  304. * @param {string} textureProperty - The texture property.
  305. * @param {string} uvSnippet - The uv snippet.
  306. * @param {?string} levelSnippet - The level snippet.
  307. * @param {?string} biasSnippet - The bias snippet.
  308. * @param {?string} depthSnippet - The depth snippet.
  309. * @param {?string} compareSnippet - The compare snippet.
  310. * @param {?Array<string>} gradSnippet - The grad snippet.
  311. * @param {?string} offsetSnippet - The offset snippet.
  312. * @return {string} The generated code snippet.
  313. */
  314. generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet ) {
  315. const texture = this.value;
  316. let snippet;
  317. if ( biasSnippet ) {
  318. snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet );
  319. } else if ( gradSnippet ) {
  320. snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet );
  321. } else if ( compareSnippet ) {
  322. snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet );
  323. } else if ( this.sampler === false ) {
  324. snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet );
  325. } else if ( levelSnippet ) {
  326. snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet );
  327. } else {
  328. snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet );
  329. }
  330. return snippet;
  331. }
  332. /**
  333. * Generates the code snippet of the texture node.
  334. *
  335. * @param {NodeBuilder} builder - The current node builder.
  336. * @param {string} output - The current output.
  337. * @return {string} The generated code snippet.
  338. */
  339. generate( builder, output ) {
  340. const texture = this.value;
  341. const properties = builder.getNodeProperties( this );
  342. const textureProperty = super.generate( builder, 'property' );
  343. if ( /^sampler/.test( output ) ) {
  344. return textureProperty + '_sampler';
  345. } else if ( builder.isReference( output ) ) {
  346. return textureProperty;
  347. } else {
  348. const nodeData = builder.getDataFromNode( this );
  349. let propertyName = nodeData.propertyName;
  350. if ( propertyName === undefined ) {
  351. const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode, offsetNode } = properties;
  352. const uvSnippet = this.generateUV( builder, uvNode );
  353. const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null;
  354. const biasSnippet = biasNode ? biasNode.build( builder, 'float' ) : null;
  355. const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null;
  356. const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null;
  357. const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null;
  358. const offsetSnippet = offsetNode ? this.generateOffset( builder, offsetNode ) : null;
  359. const nodeVar = builder.getVarFromNode( this );
  360. propertyName = builder.getPropertyName( nodeVar );
  361. const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet );
  362. builder.addLineFlowCode( `${propertyName} = ${snippet}`, this );
  363. nodeData.snippet = snippet;
  364. nodeData.propertyName = propertyName;
  365. }
  366. let snippet = propertyName;
  367. const nodeType = this.getNodeType( builder );
  368. if ( builder.needsToWorkingColorSpace( texture ) ) {
  369. snippet = colorSpaceToWorking( expression( snippet, nodeType ), texture.colorSpace ).setup( builder ).build( builder, nodeType );
  370. }
  371. return builder.format( snippet, nodeType, output );
  372. }
  373. }
  374. /**
  375. * Sets the sampler value.
  376. *
  377. * @param {boolean} value - The sampler value to set.
  378. * @return {TextureNode} A reference to this texture node.
  379. */
  380. setSampler( value ) {
  381. this.sampler = value;
  382. return this;
  383. }
  384. /**
  385. * Returns the sampler value.
  386. *
  387. * @return {boolean} The sampler value.
  388. */
  389. getSampler() {
  390. return this.sampler;
  391. }
  392. // @TODO: Move to TSL
  393. /**
  394. * @function
  395. * @deprecated since r172. Use {@link TextureNode#sample} instead.
  396. *
  397. * @param {Node} uvNode - The uv node.
  398. * @return {TextureNode} A texture node representing the texture sample.
  399. */
  400. uv( uvNode ) { // @deprecated, r172
  401. warn( 'TextureNode: .uv() has been renamed. Use .sample() instead.' );
  402. return this.sample( uvNode );
  403. }
  404. /**
  405. * Samples the texture with the given uv node.
  406. *
  407. * @param {Node} uvNode - The uv node.
  408. * @return {TextureNode} A texture node representing the texture sample.
  409. */
  410. sample( uvNode ) {
  411. const textureNode = this.clone();
  412. textureNode.uvNode = nodeObject( uvNode );
  413. textureNode.referenceNode = this.getBase();
  414. return nodeObject( textureNode );
  415. }
  416. /**
  417. * TSL function for creating a texture node that fetches/loads texels without interpolation.
  418. *
  419. * @param {Node<uvec2>} uvNode - The uv node.
  420. * @returns {TextureNode} A texture node representing the texture load.
  421. */
  422. load( uvNode ) {
  423. return this.sample( uvNode ).setSampler( false );
  424. }
  425. /**
  426. * Samples a blurred version of the texture by defining an internal bias.
  427. *
  428. * @param {Node<float>} amountNode - How blurred the texture should be.
  429. * @return {TextureNode} A texture node representing the texture sample.
  430. */
  431. blur( amountNode ) {
  432. const textureNode = this.clone();
  433. textureNode.biasNode = nodeObject( amountNode ).mul( maxMipLevel( textureNode ) );
  434. textureNode.referenceNode = this.getBase();
  435. const map = textureNode.value;
  436. if ( textureNode.generateMipmaps === false && ( map && map.generateMipmaps === false || map.minFilter === NearestFilter || map.magFilter === NearestFilter ) ) {
  437. warn( 'TSL: texture().blur() requires mipmaps and sampling. Use .generateMipmaps=true and .minFilter/.magFilter=THREE.LinearFilter in the Texture.' );
  438. textureNode.biasNode = null;
  439. }
  440. return nodeObject( textureNode );
  441. }
  442. /**
  443. * Samples a specific mip of the texture.
  444. *
  445. * @param {Node<int>} levelNode - The mip level to sample.
  446. * @return {TextureNode} A texture node representing the texture sample.
  447. */
  448. level( levelNode ) {
  449. const textureNode = this.clone();
  450. textureNode.levelNode = nodeObject( levelNode );
  451. textureNode.referenceNode = this.getBase();
  452. return nodeObject( textureNode );
  453. }
  454. /**
  455. * Returns the texture size of the requested level.
  456. *
  457. * @param {Node<int>} levelNode - The level to compute the size for.
  458. * @return {TextureSizeNode} The texture size.
  459. */
  460. size( levelNode ) {
  461. return textureSize( this, levelNode );
  462. }
  463. /**
  464. * Samples the texture with the given bias.
  465. *
  466. * @param {Node<float>} biasNode - The bias node.
  467. * @return {TextureNode} A texture node representing the texture sample.
  468. */
  469. bias( biasNode ) {
  470. const textureNode = this.clone();
  471. textureNode.biasNode = nodeObject( biasNode );
  472. textureNode.referenceNode = this.getBase();
  473. return nodeObject( textureNode );
  474. }
  475. /**
  476. * Returns the base texture of this node.
  477. * @return {TextureNode} The base texture node.
  478. */
  479. getBase() {
  480. return this.referenceNode ? this.referenceNode.getBase() : this;
  481. }
  482. /**
  483. * Samples the texture by executing a compare operation.
  484. *
  485. * @param {Node<float>} compareNode - The node that defines the compare value.
  486. * @return {TextureNode} A texture node representing the texture sample.
  487. */
  488. compare( compareNode ) {
  489. const textureNode = this.clone();
  490. textureNode.compareNode = nodeObject( compareNode );
  491. textureNode.referenceNode = this.getBase();
  492. return nodeObject( textureNode );
  493. }
  494. /**
  495. * Samples the texture using an explicit gradient.
  496. *
  497. * @param {Node<vec2>} gradNodeX - The gradX node.
  498. * @param {Node<vec2>} gradNodeY - The gradY node.
  499. * @return {TextureNode} A texture node representing the texture sample.
  500. */
  501. grad( gradNodeX, gradNodeY ) {
  502. const textureNode = this.clone();
  503. textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ];
  504. textureNode.referenceNode = this.getBase();
  505. return nodeObject( textureNode );
  506. }
  507. /**
  508. * Samples the texture by defining a depth node.
  509. *
  510. * @param {Node<int>} depthNode - The depth node.
  511. * @return {TextureNode} A texture node representing the texture sample.
  512. */
  513. depth( depthNode ) {
  514. const textureNode = this.clone();
  515. textureNode.depthNode = nodeObject( depthNode );
  516. textureNode.referenceNode = this.getBase();
  517. return nodeObject( textureNode );
  518. }
  519. /**
  520. * Samples the texture by defining an offset node.
  521. *
  522. * @param {Node<ivec2>} offsetNode - The offset node.
  523. * @return {TextureNode} A texture node representing the texture sample.
  524. */
  525. offset( offsetNode ) {
  526. const textureNode = this.clone();
  527. textureNode.offsetNode = nodeObject( offsetNode );
  528. textureNode.referenceNode = this.getBase();
  529. return nodeObject( textureNode );
  530. }
  531. // --
  532. serialize( data ) {
  533. super.serialize( data );
  534. data.value = this.value.toJSON( data.meta ).uuid;
  535. data.sampler = this.sampler;
  536. data.updateMatrix = this.updateMatrix;
  537. data.updateType = this.updateType;
  538. }
  539. deserialize( data ) {
  540. super.deserialize( data );
  541. this.value = data.meta.textures[ data.value ];
  542. this.sampler = data.sampler;
  543. this.updateMatrix = data.updateMatrix;
  544. this.updateType = data.updateType;
  545. }
  546. /**
  547. * The update is used to implement the update of the uv transformation matrix.
  548. */
  549. update() {
  550. const texture = this.value;
  551. const matrixUniform = this._matrixUniform;
  552. if ( matrixUniform !== null ) matrixUniform.value = texture.matrix;
  553. if ( texture.matrixAutoUpdate === true ) {
  554. texture.updateMatrix();
  555. }
  556. }
  557. /**
  558. * Clones the texture node.
  559. *
  560. * @return {TextureNode} The cloned texture node.
  561. */
  562. clone() {
  563. const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode );
  564. newNode.sampler = this.sampler;
  565. newNode.depthNode = this.depthNode;
  566. newNode.compareNode = this.compareNode;
  567. newNode.gradNode = this.gradNode;
  568. newNode.offsetNode = this.offsetNode;
  569. return newNode;
  570. }
  571. }
  572. export default TextureNode;
  573. /**
  574. * TSL function for creating a texture node.
  575. *
  576. * @tsl
  577. * @function
  578. * @param {?Texture} value - The texture.
  579. * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node.
  580. * @param {?Node<int>} [levelNode=null] - The level node.
  581. * @param {?Node<float>} [biasNode=null] - The bias node.
  582. * @returns {TextureNode}
  583. */
  584. const textureBase = /*@__PURE__*/ nodeProxy( TextureNode ).setParameterLength( 1, 4 ).setName( 'texture' );
  585. /**
  586. * TSL function for creating a texture node or sample a texture node already existing.
  587. *
  588. * @tsl
  589. * @function
  590. * @param {?(Texture|TextureNode)} [value=EmptyTexture] - The texture.
  591. * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node.
  592. * @param {?Node<int>} [levelNode=null] - The level node.
  593. * @param {?Node<float>} [biasNode=null] - The bias node.
  594. * @returns {TextureNode}
  595. */
  596. export const texture = ( value = EmptyTexture, uvNode = null, levelNode = null, biasNode = null ) => {
  597. let textureNode;
  598. if ( value && value.isTextureNode === true ) {
  599. textureNode = nodeObject( value.clone() );
  600. textureNode.referenceNode = value.getBase(); // Ensure the reference is set to the original node
  601. if ( uvNode !== null ) textureNode.uvNode = nodeObject( uvNode );
  602. if ( levelNode !== null ) textureNode.levelNode = nodeObject( levelNode );
  603. if ( biasNode !== null ) textureNode.biasNode = nodeObject( biasNode );
  604. } else {
  605. textureNode = textureBase( value, uvNode, levelNode, biasNode );
  606. }
  607. return textureNode;
  608. };
  609. /**
  610. * TSL function for creating a uniform texture node.
  611. *
  612. * @tsl
  613. * @function
  614. * @param {?Texture} value - The texture.
  615. * @returns {TextureNode}
  616. */
  617. export const uniformTexture = ( value = EmptyTexture ) => texture( value );
  618. /**
  619. * TSL function for creating a texture node that fetches/loads texels without interpolation.
  620. *
  621. * @tsl
  622. * @function
  623. * @param {?(Texture|TextureNode)} [value=EmptyTexture] - The texture.
  624. * @param {?Node<vec2|vec3>} [uvNode=null] - The uv node.
  625. * @param {?Node<int>} [levelNode=null] - The level node.
  626. * @param {?Node<float>} [biasNode=null] - The bias node.
  627. * @returns {TextureNode}
  628. */
  629. export const textureLoad = ( ...params ) => texture( ...params ).setSampler( false );
  630. //export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level );
  631. /**
  632. * Converts a texture or texture node to a sampler.
  633. *
  634. * @tsl
  635. * @function
  636. * @param {TextureNode|Texture} value - The texture or texture node to convert.
  637. * @returns {Node}
  638. */
  639. export const sampler = ( value ) => ( value.isNode === true ? value : texture( value ) ).convert( 'sampler' );
  640. /**
  641. * Converts a texture or texture node to a sampler comparison.
  642. *
  643. * @tsl
  644. * @function
  645. * @param {TextureNode|Texture} value - The texture or texture node to convert.
  646. * @returns {Node}
  647. */
  648. export const samplerComparison = ( value ) => ( value.isNode === true ? value : texture( value ) ).convert( 'samplerComparison' );
粤ICP备19079148号