UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

324 lines (298 loc) 9.1 kB
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); };