| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- import BufferNode from './BufferNode.js';
- import { bufferAttribute } from './BufferAttributeNode.js';
- import { nodeObject, varying } from '../tsl/TSLBase.js';
- import { storageElement } from '../utils/StorageArrayElementNode.js';
- import { NodeAccess } from '../core/constants.js';
- import { getTypeFromLength } from '../core/NodeUtils.js';
- /**
- * This node is used in context of compute shaders and allows to define a
- * storage buffer for data. A typical workflow is to create instances of
- * this node with the convenience functions `attributeArray()` or `instancedArray()`,
- * setup up a compute shader that writes into the buffers and then convert
- * the storage buffers to attribute nodes for rendering.
- *
- * ```js
- * const positionBuffer = instancedArray( particleCount, 'vec3' ); // the storage buffer node
- *
- * const computeInit = Fn( () => { // the compute shader
- *
- * const position = positionBuffer.element( instanceIndex );
- *
- * // compute position data
- *
- * position.x = 1;
- * position.y = 1;
- * position.z = 1;
- *
- * } )().compute( particleCount );
- *
- * const particleMaterial = new THREE.SpriteNodeMaterial();
- * particleMaterial.positionNode = positionBuffer.toAttribute();
- *
- * renderer.computeAsync( computeInit );
- *
- * ```
- *
- * @augments BufferNode
- */
- class StorageBufferNode extends BufferNode {
- static get type() {
- return 'StorageBufferNode';
- }
- /**
- * Constructs a new storage buffer node.
- *
- * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data.
- * @param {(String|Struct)?} [bufferType=null] - The buffer type (e.g. `'vec3'`).
- * @param {Number} [bufferCount=0] - The buffer count.
- */
- constructor( value, bufferType = null, bufferCount = 0 ) {
- let nodeType, structTypeNode = null;
- if ( bufferType && bufferType.isStruct ) {
- nodeType = 'struct';
- structTypeNode = bufferType.layout;
- } else if ( bufferType === null && ( value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute ) ) {
- nodeType = getTypeFromLength( value.itemSize );
- bufferCount = value.count;
- } else {
- nodeType = bufferType;
- }
- super( value, nodeType, bufferCount );
- /**
- * This flag can be used for type testing.
- *
- * @type {Boolean}
- * @readonly
- * @default true
- */
- this.isStorageBufferNode = true;
- /**
- * The buffer struct type.
- *
- * @type {structTypeNode?}
- * @default null
- */
- this.structTypeNode = structTypeNode;
- /**
- * The access type of the texture node.
- *
- * @type {String}
- * @default 'readWrite'
- */
- this.access = NodeAccess.READ_WRITE;
- /**
- * Whether the node is atomic or not.
- *
- * @type {Boolean}
- * @default false
- */
- this.isAtomic = false;
- /**
- * Whether the node represents a PBO or not.
- * Only relevant for WebGL.
- *
- * @type {Boolean}
- * @default false
- */
- this.isPBO = false;
- /**
- * A reference to the internal buffer attribute node.
- *
- * @type {BufferAttributeNode?}
- * @default null
- */
- this._attribute = null;
- /**
- * A reference to the internal varying node.
- *
- * @type {VaryingNode?}
- * @default null
- */
- this._varying = null;
- /**
- * `StorageBufferNode` sets this property to `true` by default.
- *
- * @type {Boolean}
- * @default true
- */
- this.global = true;
- if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) {
- // TODO: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer
- if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true;
- else value.isStorageBufferAttribute = true;
- }
- }
- /**
- * This method is overwritten since the buffer data might be shared
- * and thus the hash should be shared as well.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {String} The hash.
- */
- getHash( builder ) {
- if ( this.bufferCount === 0 ) {
- let bufferData = builder.globalCache.getData( this.value );
- if ( bufferData === undefined ) {
- bufferData = {
- node: this
- };
- builder.globalCache.setData( this.value, bufferData );
- }
- return bufferData.node.uuid;
- }
- return this.uuid;
- }
- /**
- * Overwrites the default implementation to return a fixed value `'indirectStorageBuffer'` or `'storageBuffer'`.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {String} The input type.
- */
- getInputType( /*builder*/ ) {
- return this.value.isIndirectStorageBufferAttribute ? 'indirectStorageBuffer' : 'storageBuffer';
- }
- /**
- * Enables element access with the given index node.
- *
- * @param {IndexNode} indexNode - The index node.
- * @return {StorageArrayElementNode} A node representing the element access.
- */
- element( indexNode ) {
- return storageElement( this, indexNode );
- }
- /**
- * Defines whether this node is a PBO or not. Only relevant for WebGL.
- *
- * @param {Boolean} value - The value so set.
- * @return {StorageBufferNode} A reference to this node.
- */
- setPBO( value ) {
- this.isPBO = value;
- return this;
- }
- /**
- * Returns the `isPBO` value.
- *
- * @return {Boolean} Whether the node represents a PBO or not.
- */
- getPBO() {
- return this.isPBO;
- }
- /**
- * Defines the node access.
- *
- * @param {String} value - The node access.
- * @return {StorageBufferNode} A reference to this node.
- */
- setAccess( value ) {
- this.access = value;
- return this;
- }
- /**
- * Convenience method for configuring a read-only node access.
- *
- * @return {StorageBufferNode} A reference to this node.
- */
- toReadOnly() {
- return this.setAccess( NodeAccess.READ_ONLY );
- }
- /**
- * Defines whether the node is atomic or not.
- *
- * @param {Boolean} value - The atomic flag.
- * @return {StorageBufferNode} A reference to this node.
- */
- setAtomic( value ) {
- this.isAtomic = value;
- return this;
- }
- /**
- * Convenience method for making this node atomic.
- *
- * @return {StorageBufferNode} A reference to this node.
- */
- toAtomic() {
- return this.setAtomic( true );
- }
- /**
- * Returns attribute data for this storage buffer node.
- *
- * @return {{attribute: BufferAttributeNode, varying: VaryingNode}} The attribute data.
- */
- getAttributeData() {
- if ( this._attribute === null ) {
- this._attribute = bufferAttribute( this.value );
- this._varying = varying( this._attribute );
- }
- return {
- attribute: this._attribute,
- varying: this._varying
- };
- }
- /**
- * This method is overwritten since the node type from the availability of storage buffers
- * and the attribute data.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {String} The node type.
- */
- getNodeType( builder ) {
- if ( this.structTypeNode !== null ) {
- return this.structTypeNode.getNodeType( builder );
- }
- if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) {
- return super.getNodeType( builder );
- }
- const { attribute } = this.getAttributeData();
- return attribute.getNodeType( builder );
- }
- /**
- * Generates the code snippet of the storage buffer node.
- *
- * @param {NodeBuilder} builder - The current node builder.
- * @return {String} The generated code snippet.
- */
- generate( builder ) {
- if ( this.structTypeNode !== null ) this.structTypeNode.build( builder );
- if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) {
- return super.generate( builder );
- }
- const { attribute, varying } = this.getAttributeData();
- const output = varying.build( builder );
- builder.registerTransform( output, attribute );
- return output;
- }
- }
- export default StorageBufferNode;
- /**
- * TSL function for creating a storage buffer node.
- *
- * @tsl
- * @function
- * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data.
- * @param {(String|Struct)?} [type=null] - The buffer type (e.g. `'vec3'`).
- * @param {Number} [count=0] - The buffer count.
- * @returns {StorageBufferNode}
- */
- export const storage = ( value, type = null, count = 0 ) => nodeObject( new StorageBufferNode( value, type, count ) );
- /**
- * @tsl
- * @function
- * @deprecated since r171. Use `storage().setPBO( true )` instead.
- *
- * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data.
- * @param {String?} type - The buffer type (e.g. `'vec3'`).
- * @param {Number} count - The buffer count.
- * @returns {StorageBufferNode}
- */
- export const storageObject = ( value, type, count ) => { // @deprecated, r171
- console.warn( 'THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' );
- return storage( value, type, count ).setPBO( true );
- };
|