| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- import { nodeObject } from '../tsl/TSLBase.js';
- import { NodeUpdateType } from '../core/constants.js';
- import { getValueType } from '../core/NodeUtils.js';
- import ArrayElementNode from '../utils/ArrayElementNode.js';
- import BufferNode from './BufferNode.js';
- /**
- * Represents the element access on uniform array nodes.
- *
- * @augments ArrayElementNode
- */
- class UniformArrayElementNode extends ArrayElementNode {
- static get type() {
- return 'UniformArrayElementNode';
- }
- /**
- * Constructs a new buffer node.
- *
- * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access.
- * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array.
- */
- constructor( uniformArrayNode, indexNode ) {
- super( uniformArrayNode, indexNode );
- /**
- * This flag can be used for type testing.
- *
- * @type {boolean}
- * @readonly
- * @default true
- */
- this.isArrayBufferElementNode = true;
- }
- generate( builder ) {
- const snippet = super.generate( builder );
- const type = this.getNodeType();
- const paddedType = this.node.getPaddedType();
- return builder.format( snippet, paddedType, type );
- }
- }
- /**
- * Similar to {@link BufferNode} this module represents array-like data as
- * uniform buffers. Unlike {@link BufferNode}, it can handle more common
- * data types in the array (e.g `three.js` primitives) and automatically
- * manage buffer padding. It should be the first choice when working with
- * uniforms buffers.
- * ```js
- * const tintColors = uniformArray( [
- * new Color( 1, 0, 0 ),
- * new Color( 0, 1, 0 ),
- * new Color( 0, 0, 1 )
- * ], 'color' );
- *
- * const redColor = tintColors.element( 0 );
- *
- * @augments BufferNode
- */
- class UniformArrayNode extends BufferNode {
- static get type() {
- return 'UniformArrayNode';
- }
- /**
- * Constructs a new uniform array node.
- *
- * @param {Array<any>} value - Array holding the buffer data.
- * @param {?string} [elementType=null] - The data type of a buffer element.
- */
- constructor( value, elementType = null ) {
- super( null );
- /**
- * Array holding the buffer data. Unlike {@link BufferNode}, the array can
- * hold number primitives as well as three.js objects like vectors, matrices
- * or colors.
- *
- * @type {Array<any>}
- */
- this.array = value;
- /**
- * The data type of an array element.
- *
- * @type {string}
- */
- this.elementType = elementType === null ? getValueType( value[ 0 ] ) : elementType;
- /**
- * The padded type. Uniform buffers must conform to a certain buffer layout
- * so a separate type is computed to ensure correct buffer size.
- *
- * @type {string}
- */
- this.paddedType = this.getPaddedType();
- /**
- * Overwritten since uniform array nodes are updated per render.
- *
- * @type {string}
- * @default 'render'
- */
- this.updateType = NodeUpdateType.RENDER;
- /**
- * This flag can be used for type testing.
- *
- * @type {boolean}
- * @readonly
- * @default true
- */
- this.isArrayBufferNode = true;
- }
- /**
- * This method is overwritten since the node type is inferred from the
- * {@link UniformArrayNode#paddedType}.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {string} The node type.
- */
- getNodeType( /*builder*/ ) {
- return this.paddedType;
- }
- /**
- * The data type of the array elements.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {string} The element type.
- */
- getElementType() {
- return this.elementType;
- }
- /**
- * Returns the padded type based on the element type.
- *
- * @return {string} The padded type.
- */
- getPaddedType() {
- const elementType = this.elementType;
- let paddedType = 'vec4';
- if ( elementType === 'mat2' ) {
- paddedType = 'mat2';
- } else if ( /mat/.test( elementType ) === true ) {
- paddedType = 'mat4';
- } else if ( elementType.charAt( 0 ) === 'i' ) {
- paddedType = 'ivec4';
- } else if ( elementType.charAt( 0 ) === 'u' ) {
- paddedType = 'uvec4';
- }
- return paddedType;
- }
- /**
- * The update makes sure to correctly transfer the data from the (complex) objects
- * in the array to the internal, correctly padded value buffer.
- *
- * @param {NodeFrame} frame - A reference to the current node frame.
- */
- update( /*frame*/ ) {
- const { array, value } = this;
- const elementType = this.elementType;
- if ( elementType === 'float' || elementType === 'int' || elementType === 'uint' ) {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 4;
- value[ index ] = array[ i ];
- }
- } else if ( elementType === 'color' ) {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 4;
- const vector = array[ i ];
- value[ index ] = vector.r;
- value[ index + 1 ] = vector.g;
- value[ index + 2 ] = vector.b || 0;
- //value[ index + 3 ] = vector.a || 0;
- }
- } else if ( elementType === 'mat2' ) {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 4;
- const matrix = array[ i ];
- value[ index ] = matrix.elements[ 0 ];
- value[ index + 1 ] = matrix.elements[ 1 ];
- value[ index + 2 ] = matrix.elements[ 2 ];
- value[ index + 3 ] = matrix.elements[ 3 ];
- }
- } else if ( elementType === 'mat3' ) {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 16;
- const matrix = array[ i ];
- value[ index ] = matrix.elements[ 0 ];
- value[ index + 1 ] = matrix.elements[ 1 ];
- value[ index + 2 ] = matrix.elements[ 2 ];
- value[ index + 4 ] = matrix.elements[ 3 ];
- value[ index + 5 ] = matrix.elements[ 4 ];
- value[ index + 6 ] = matrix.elements[ 5 ];
- value[ index + 8 ] = matrix.elements[ 6 ];
- value[ index + 9 ] = matrix.elements[ 7 ];
- value[ index + 10 ] = matrix.elements[ 8 ];
- value[ index + 15 ] = 1;
- }
- } else if ( elementType === 'mat4' ) {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 16;
- const matrix = array[ i ];
- for ( let i = 0; i < matrix.elements.length; i ++ ) {
- value[ index + i ] = matrix.elements[ i ];
- }
- }
- } else {
- for ( let i = 0; i < array.length; i ++ ) {
- const index = i * 4;
- const vector = array[ i ];
- value[ index ] = vector.x;
- value[ index + 1 ] = vector.y;
- value[ index + 2 ] = vector.z || 0;
- value[ index + 3 ] = vector.w || 0;
- }
- }
- }
- /**
- * Implement the value buffer creation based on the array data.
- *
- * @param {NodeBuilder} builder - A reference to the current node builder.
- * @return {null}
- */
- setup( builder ) {
- const length = this.array.length;
- const elementType = this.elementType;
- let arrayType = Float32Array;
- const paddedType = this.paddedType;
- const paddedElementLength = builder.getTypeLength( paddedType );
- if ( elementType.charAt( 0 ) === 'i' ) arrayType = Int32Array;
- if ( elementType.charAt( 0 ) === 'u' ) arrayType = Uint32Array;
- this.value = new arrayType( length * paddedElementLength );
- this.bufferCount = length;
- this.bufferType = paddedType;
- return super.setup( builder );
- }
- /**
- * Overwrites the default `element()` method to provide element access
- * based on {@link UniformArrayNode}.
- *
- * @param {IndexNode} indexNode - The index node.
- * @return {UniformArrayElementNode}
- */
- element( indexNode ) {
- return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) );
- }
- }
- export default UniformArrayNode;
- /**
- * TSL function for creating an uniform array node.
- *
- * @tsl
- * @function
- * @param {Array<any>} values - Array-like data.
- * @param {?string} [nodeType] - The data type of the array elements.
- * @returns {UniformArrayNode}
- */
- export const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) );
|