Skip to content

⬅️ Back to Table of Contents

📄 BufferAttributeNode.js

📊 Analysis Summary

Metric Count
🔧 Functions 11
🧱 Classes 1
📦 Imports 8
📊 Variables & Constants 6

📚 Table of Contents

🛠️ File Location:

📂 src/nodes/accessors/BufferAttributeNode.js

📦 Imports

Name Source
InputNode ../core/InputNode.js
nodeObject ../tsl/TSLCore.js
addMethodChaining ../tsl/TSLCore.js
varying ../core/VaryingNode.js
InterleavedBufferAttribute ../../core/InterleavedBufferAttribute.js
InterleavedBuffer ../../core/InterleavedBuffer.js
StaticDrawUsage ../../constants.js
DynamicDrawUsage ../../constants.js

Variables & Constants

Name Type Kind Value Exported
array any let/var this.value
stride any let/var this.bufferStride \|\| itemSize
offset number let/var this.bufferOffset
buffer any let/var array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, st...
bufferAttribute InterleavedBufferAttribute let/var new InterleavedBufferAttribute( buffer, itemSize, offset )
output any let/var null

Functions

BufferAttributeNode.getHash(builder: NodeBuilder): string

JSDoc:

/**
     * This method is overwritten since the attribute data might be shared
     * and thus the hash should be shared as well.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The hash.
     */

Parameters:

  • builder NodeBuilder

Returns: string

Calls:

  • builder.globalCache.getData
  • builder.globalCache.setData
Code
getHash( builder ) {

        if ( this.bufferStride === 0 && this.bufferOffset === 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;

    }

BufferAttributeNode.getNodeType(builder: NodeBuilder): string

JSDoc:

/**
     * This method is overwritten since the node type is inferred from
     * the buffer attribute.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The node type.
     */

Parameters:

  • builder NodeBuilder

Returns: string

Calls:

  • builder.getTypeFromAttribute
Code
getNodeType( builder ) {

        if ( this.bufferType === null ) {

            this.bufferType = builder.getTypeFromAttribute( this.attribute );

        }

        return this.bufferType;

    }

BufferAttributeNode.setup(builder: NodeBuilder): void

JSDoc:

/**
     * Depending on which value was passed to the node, `setup()` behaves
     * differently. If no instance of `BufferAttribute` was passed, the method
     * creates an internal attribute and configures it respectively.
     *
     * @param {NodeBuilder} builder - The current node builder.
     */

Parameters:

  • builder NodeBuilder

Returns: void

Calls:

  • this.getNodeType
  • builder.getTypeLength
  • buffer.setUsage
Code
setup( builder ) {

        if ( this.attribute !== null ) return;

        const type = this.getNodeType( builder );
        const array = this.value;
        const itemSize = builder.getTypeLength( type );
        const stride = this.bufferStride || itemSize;
        const offset = this.bufferOffset;

        const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride );
        const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );

        buffer.setUsage( this.usage );

        this.attribute = bufferAttribute;
        this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute

    }

BufferAttributeNode.generate(builder: NodeBuilder): string

JSDoc:

/**
     * Generates the code snippet of the buffer attribute node.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The generated code snippet.
     */

Parameters:

  • builder NodeBuilder

Returns: string

Calls:

  • this.getNodeType
  • builder.getBufferAttributeFromNode
  • builder.getPropertyName
  • varying (from ../core/VaryingNode.js)
  • nodeVarying.build
Code
generate( builder ) {

        const nodeType = this.getNodeType( builder );

        const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType );
        const propertyName = builder.getPropertyName( nodeAttribute );

        let output = null;

        if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {

            this.name = propertyName;

            output = propertyName;

        } else {

            const nodeVarying = varying( this );

            output = nodeVarying.build( builder, nodeType );

        }

        return output;

    }

BufferAttributeNode.getInputType(): string

JSDoc:

/**
     * Overwrites the default implementation to return a fixed value `'bufferAttribute'`.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The input type.
     */

Returns: string

Code
getInputType( /*builder*/ ) {

        return 'bufferAttribute';

    }

BufferAttributeNode.setUsage(value: number): BufferAttributeNode

JSDoc:

/**
     * Sets the `usage` property to the given value.
     *
     * @param {number} value - The usage to set.
     * @return {BufferAttributeNode} A reference to this node.
     */

Parameters:

  • value number

Returns: BufferAttributeNode

Code
setUsage( value ) {

        this.usage = value;

        if ( this.attribute && this.attribute.isBufferAttribute === true ) {

            this.attribute.usage = value;

        }

        return this;

    }

BufferAttributeNode.setInstanced(value: boolean): BufferAttributeNode

JSDoc:

/**
     * Sets the `instanced` property to the given value.
     *
     * @param {boolean} value - The value to set.
     * @return {BufferAttributeNode} A reference to this node.
     */

Parameters:

  • value boolean

Returns: BufferAttributeNode

Code
setInstanced( value ) {

        this.instanced = value;

        return this;

    }

bufferAttribute(array: any, type: string, stride: number, offset: number): BufferAttributeNode

Parameters:

  • array any
  • type string
  • stride number
  • offset number

Returns: BufferAttributeNode

Calls:

  • nodeObject (from ../tsl/TSLCore.js)
Code
( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) )

dynamicBufferAttribute(array: any, type: string, stride: number, offset: number): BufferAttributeNode

Parameters:

  • array any
  • type string
  • stride number
  • offset number

Returns: BufferAttributeNode

Calls:

  • bufferAttribute( array, type, stride, offset ).setUsage
Code
( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage )

instancedBufferAttribute(array: any, type: string, stride: number, offset: number): BufferAttributeNode

Parameters:

  • array any
  • type string
  • stride number
  • offset number

Returns: BufferAttributeNode

Calls:

  • bufferAttribute( array, type, stride, offset ).setInstanced
Code
( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true )

instancedDynamicBufferAttribute(array: any, type: string, stride: number, offset: number): BufferAttributeNode

Parameters:

  • array any
  • type string
  • stride number
  • offset number

Returns: BufferAttributeNode

Calls:

  • dynamicBufferAttribute( array, type, stride, offset ).setInstanced
Code
( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true )

Classes

BufferAttributeNode

Class Code
class BufferAttributeNode extends InputNode {

    static get type() {

        return 'BufferAttributeNode';

    }

    /**
     * Constructs a new buffer attribute node.
     *
     * @param {BufferAttribute|InterleavedBuffer|TypedArray} value - The attribute data.
     * @param {?string} [bufferType=null] - The buffer type (e.g. `'vec3'`).
     * @param {number} [bufferStride=0] - The buffer stride.
     * @param {number} [bufferOffset=0] - The buffer offset.
     */
    constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) {

        super( value, bufferType );

        /**
         * This flag can be used for type testing.
         *
         * @type {boolean}
         * @readonly
         * @default true
         */
        this.isBufferNode = true;

        /**
         * The buffer type (e.g. `'vec3'`).
         *
         * @type {?string}
         * @default null
         */
        this.bufferType = bufferType;

        /**
         * The buffer stride.
         *
         * @type {number}
         * @default 0
         */
        this.bufferStride = bufferStride;

        /**
         * The buffer offset.
         *
         * @type {number}
         * @default 0
         */
        this.bufferOffset = bufferOffset;

        /**
         * The usage property. Set this to `THREE.DynamicDrawUsage` via `.setUsage()`,
         * if you are planning to update the attribute data per frame.
         *
         * @type {number}
         * @default StaticDrawUsage
         */
        this.usage = StaticDrawUsage;

        /**
         * Whether the attribute is instanced or not.
         *
         * @type {boolean}
         * @default false
         */
        this.instanced = false;

        /**
         * A reference to the buffer attribute.
         *
         * @type {?BufferAttribute}
         * @default null
         */
        this.attribute = null;

        /**
         * `BufferAttributeNode` sets this property to `true` by default.
         *
         * @type {boolean}
         * @default true
         */
        this.global = true;

        if ( value && value.isBufferAttribute === true ) {

            this.attribute = value;
            this.usage = value.usage;
            this.instanced = value.isInstancedBufferAttribute;

        }

    }

    /**
     * This method is overwritten since the attribute 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.bufferStride === 0 && this.bufferOffset === 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;

    }

    /**
     * This method is overwritten since the node type is inferred from
     * the buffer attribute.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The node type.
     */
    getNodeType( builder ) {

        if ( this.bufferType === null ) {

            this.bufferType = builder.getTypeFromAttribute( this.attribute );

        }

        return this.bufferType;

    }

    /**
     * Depending on which value was passed to the node, `setup()` behaves
     * differently. If no instance of `BufferAttribute` was passed, the method
     * creates an internal attribute and configures it respectively.
     *
     * @param {NodeBuilder} builder - The current node builder.
     */
    setup( builder ) {

        if ( this.attribute !== null ) return;

        const type = this.getNodeType( builder );
        const array = this.value;
        const itemSize = builder.getTypeLength( type );
        const stride = this.bufferStride || itemSize;
        const offset = this.bufferOffset;

        const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride );
        const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );

        buffer.setUsage( this.usage );

        this.attribute = bufferAttribute;
        this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute

    }

    /**
     * Generates the code snippet of the buffer attribute node.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The generated code snippet.
     */
    generate( builder ) {

        const nodeType = this.getNodeType( builder );

        const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType );
        const propertyName = builder.getPropertyName( nodeAttribute );

        let output = null;

        if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {

            this.name = propertyName;

            output = propertyName;

        } else {

            const nodeVarying = varying( this );

            output = nodeVarying.build( builder, nodeType );

        }

        return output;

    }

    /**
     * Overwrites the default implementation to return a fixed value `'bufferAttribute'`.
     *
     * @param {NodeBuilder} builder - The current node builder.
     * @return {string} The input type.
     */
    getInputType( /*builder*/ ) {

        return 'bufferAttribute';

    }

    /**
     * Sets the `usage` property to the given value.
     *
     * @param {number} value - The usage to set.
     * @return {BufferAttributeNode} A reference to this node.
     */
    setUsage( value ) {

        this.usage = value;

        if ( this.attribute && this.attribute.isBufferAttribute === true ) {

            this.attribute.usage = value;

        }

        return this;

    }

    /**
     * Sets the `instanced` property to the given value.
     *
     * @param {boolean} value - The value to set.
     * @return {BufferAttributeNode} A reference to this node.
     */
    setInstanced( value ) {

        this.instanced = value;

        return this;

    }

}

Methods

getHash(builder: NodeBuilder): string
Code
getHash( builder ) {

        if ( this.bufferStride === 0 && this.bufferOffset === 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;

    }
getNodeType(builder: NodeBuilder): string
Code
getNodeType( builder ) {

        if ( this.bufferType === null ) {

            this.bufferType = builder.getTypeFromAttribute( this.attribute );

        }

        return this.bufferType;

    }
setup(builder: NodeBuilder): void
Code
setup( builder ) {

        if ( this.attribute !== null ) return;

        const type = this.getNodeType( builder );
        const array = this.value;
        const itemSize = builder.getTypeLength( type );
        const stride = this.bufferStride || itemSize;
        const offset = this.bufferOffset;

        const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride );
        const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );

        buffer.setUsage( this.usage );

        this.attribute = bufferAttribute;
        this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute

    }
generate(builder: NodeBuilder): string
Code
generate( builder ) {

        const nodeType = this.getNodeType( builder );

        const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType );
        const propertyName = builder.getPropertyName( nodeAttribute );

        let output = null;

        if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {

            this.name = propertyName;

            output = propertyName;

        } else {

            const nodeVarying = varying( this );

            output = nodeVarying.build( builder, nodeType );

        }

        return output;

    }
getInputType(): string
Code
getInputType( /*builder*/ ) {

        return 'bufferAttribute';

    }
setUsage(value: number): BufferAttributeNode
Code
setUsage( value ) {

        this.usage = value;

        if ( this.attribute && this.attribute.isBufferAttribute === true ) {

            this.attribute.usage = value;

        }

        return this;

    }
setInstanced(value: boolean): BufferAttributeNode
Code
setInstanced( value ) {

        this.instanced = value;

        return this;

    }