UniformArrayNode.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. import { nodeObject } from '../tsl/TSLBase.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { getValueType } from '../core/NodeUtils.js';
  4. import ArrayElementNode from '../utils/ArrayElementNode.js';
  5. import BufferNode from './BufferNode.js';
  6. /**
  7. * Represents the element access on uniform array nodes.
  8. *
  9. * @augments ArrayElementNode
  10. */
  11. class UniformArrayElementNode extends ArrayElementNode {
  12. static get type() {
  13. return 'UniformArrayElementNode';
  14. }
  15. /**
  16. * Constructs a new buffer node.
  17. *
  18. * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access.
  19. * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array.
  20. */
  21. constructor( uniformArrayNode, indexNode ) {
  22. super( uniformArrayNode, indexNode );
  23. /**
  24. * This flag can be used for type testing.
  25. *
  26. * @type {boolean}
  27. * @readonly
  28. * @default true
  29. */
  30. this.isArrayBufferElementNode = true;
  31. }
  32. generate( builder ) {
  33. const snippet = super.generate( builder );
  34. const type = this.getNodeType();
  35. const paddedType = this.node.getPaddedType();
  36. return builder.format( snippet, paddedType, type );
  37. }
  38. }
  39. /**
  40. * Similar to {@link BufferNode} this module represents array-like data as
  41. * uniform buffers. Unlike {@link BufferNode}, it can handle more common
  42. * data types in the array (e.g `three.js` primitives) and automatically
  43. * manage buffer padding. It should be the first choice when working with
  44. * uniforms buffers.
  45. * ```js
  46. * const tintColors = uniformArray( [
  47. * new Color( 1, 0, 0 ),
  48. * new Color( 0, 1, 0 ),
  49. * new Color( 0, 0, 1 )
  50. * ], 'color' );
  51. *
  52. * const redColor = tintColors.element( 0 );
  53. *
  54. * @augments BufferNode
  55. */
  56. class UniformArrayNode extends BufferNode {
  57. static get type() {
  58. return 'UniformArrayNode';
  59. }
  60. /**
  61. * Constructs a new uniform array node.
  62. *
  63. * @param {Array<any>} value - Array holding the buffer data.
  64. * @param {?string} [elementType=null] - The data type of a buffer element.
  65. */
  66. constructor( value, elementType = null ) {
  67. super( null );
  68. /**
  69. * Array holding the buffer data. Unlike {@link BufferNode}, the array can
  70. * hold number primitives as well as three.js objects like vectors, matrices
  71. * or colors.
  72. *
  73. * @type {Array<any>}
  74. */
  75. this.array = value;
  76. /**
  77. * The data type of an array element.
  78. *
  79. * @type {string}
  80. */
  81. this.elementType = elementType === null ? getValueType( value[ 0 ] ) : elementType;
  82. /**
  83. * The padded type. Uniform buffers must conform to a certain buffer layout
  84. * so a separate type is computed to ensure correct buffer size.
  85. *
  86. * @type {string}
  87. */
  88. this.paddedType = this.getPaddedType();
  89. /**
  90. * Overwritten since uniform array nodes are updated per render.
  91. *
  92. * @type {string}
  93. * @default 'render'
  94. */
  95. this.updateType = NodeUpdateType.RENDER;
  96. /**
  97. * This flag can be used for type testing.
  98. *
  99. * @type {boolean}
  100. * @readonly
  101. * @default true
  102. */
  103. this.isArrayBufferNode = true;
  104. }
  105. /**
  106. * This method is overwritten since the node type is inferred from the
  107. * {@link UniformArrayNode#paddedType}.
  108. *
  109. * @param {NodeBuilder} builder - The current node builder.
  110. * @return {string} The node type.
  111. */
  112. getNodeType( /*builder*/ ) {
  113. return this.paddedType;
  114. }
  115. /**
  116. * The data type of the array elements.
  117. *
  118. * @param {NodeBuilder} builder - The current node builder.
  119. * @return {string} The element type.
  120. */
  121. getElementType() {
  122. return this.elementType;
  123. }
  124. /**
  125. * Returns the padded type based on the element type.
  126. *
  127. * @return {string} The padded type.
  128. */
  129. getPaddedType() {
  130. const elementType = this.elementType;
  131. let paddedType = 'vec4';
  132. if ( elementType === 'mat2' ) {
  133. paddedType = 'mat2';
  134. } else if ( /mat/.test( elementType ) === true ) {
  135. paddedType = 'mat4';
  136. } else if ( elementType.charAt( 0 ) === 'i' ) {
  137. paddedType = 'ivec4';
  138. } else if ( elementType.charAt( 0 ) === 'u' ) {
  139. paddedType = 'uvec4';
  140. }
  141. return paddedType;
  142. }
  143. /**
  144. * The update makes sure to correctly transfer the data from the (complex) objects
  145. * in the array to the internal, correctly padded value buffer.
  146. *
  147. * @param {NodeFrame} frame - A reference to the current node frame.
  148. */
  149. update( /*frame*/ ) {
  150. const { array, value } = this;
  151. const elementType = this.elementType;
  152. if ( elementType === 'float' || elementType === 'int' || elementType === 'uint' ) {
  153. for ( let i = 0; i < array.length; i ++ ) {
  154. const index = i * 4;
  155. value[ index ] = array[ i ];
  156. }
  157. } else if ( elementType === 'color' ) {
  158. for ( let i = 0; i < array.length; i ++ ) {
  159. const index = i * 4;
  160. const vector = array[ i ];
  161. value[ index ] = vector.r;
  162. value[ index + 1 ] = vector.g;
  163. value[ index + 2 ] = vector.b || 0;
  164. //value[ index + 3 ] = vector.a || 0;
  165. }
  166. } else if ( elementType === 'mat2' ) {
  167. for ( let i = 0; i < array.length; i ++ ) {
  168. const index = i * 4;
  169. const matrix = array[ i ];
  170. value[ index ] = matrix.elements[ 0 ];
  171. value[ index + 1 ] = matrix.elements[ 1 ];
  172. value[ index + 2 ] = matrix.elements[ 2 ];
  173. value[ index + 3 ] = matrix.elements[ 3 ];
  174. }
  175. } else if ( elementType === 'mat3' ) {
  176. for ( let i = 0; i < array.length; i ++ ) {
  177. const index = i * 16;
  178. const matrix = array[ i ];
  179. value[ index ] = matrix.elements[ 0 ];
  180. value[ index + 1 ] = matrix.elements[ 1 ];
  181. value[ index + 2 ] = matrix.elements[ 2 ];
  182. value[ index + 4 ] = matrix.elements[ 3 ];
  183. value[ index + 5 ] = matrix.elements[ 4 ];
  184. value[ index + 6 ] = matrix.elements[ 5 ];
  185. value[ index + 8 ] = matrix.elements[ 6 ];
  186. value[ index + 9 ] = matrix.elements[ 7 ];
  187. value[ index + 10 ] = matrix.elements[ 8 ];
  188. value[ index + 15 ] = 1;
  189. }
  190. } else if ( elementType === 'mat4' ) {
  191. for ( let i = 0; i < array.length; i ++ ) {
  192. const index = i * 16;
  193. const matrix = array[ i ];
  194. for ( let i = 0; i < matrix.elements.length; i ++ ) {
  195. value[ index + i ] = matrix.elements[ i ];
  196. }
  197. }
  198. } else {
  199. for ( let i = 0; i < array.length; i ++ ) {
  200. const index = i * 4;
  201. const vector = array[ i ];
  202. value[ index ] = vector.x;
  203. value[ index + 1 ] = vector.y;
  204. value[ index + 2 ] = vector.z || 0;
  205. value[ index + 3 ] = vector.w || 0;
  206. }
  207. }
  208. }
  209. /**
  210. * Implement the value buffer creation based on the array data.
  211. *
  212. * @param {NodeBuilder} builder - A reference to the current node builder.
  213. * @return {null}
  214. */
  215. setup( builder ) {
  216. const length = this.array.length;
  217. const elementType = this.elementType;
  218. let arrayType = Float32Array;
  219. const paddedType = this.paddedType;
  220. const paddedElementLength = builder.getTypeLength( paddedType );
  221. if ( elementType.charAt( 0 ) === 'i' ) arrayType = Int32Array;
  222. if ( elementType.charAt( 0 ) === 'u' ) arrayType = Uint32Array;
  223. this.value = new arrayType( length * paddedElementLength );
  224. this.bufferCount = length;
  225. this.bufferType = paddedType;
  226. return super.setup( builder );
  227. }
  228. /**
  229. * Overwrites the default `element()` method to provide element access
  230. * based on {@link UniformArrayNode}.
  231. *
  232. * @param {IndexNode} indexNode - The index node.
  233. * @return {UniformArrayElementNode}
  234. */
  235. element( indexNode ) {
  236. return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) );
  237. }
  238. }
  239. export default UniformArrayNode;
  240. /**
  241. * TSL function for creating an uniform array node.
  242. *
  243. * @tsl
  244. * @function
  245. * @param {Array<any>} values - Array-like data.
  246. * @param {?string} [nodeType] - The data type of the array elements.
  247. * @returns {UniformArrayNode}
  248. */
  249. export const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) );
粤ICP备19079148号