Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node: Document more modules. #30123

Merged
merged 3 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions examples/webgpu_compute_sort_bitonic.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<script type="module">

import * as THREE from 'three';
import { storageObject, If, vec3, not, uniform, uv, uint, float, Fn, vec2, abs, int, invocationLocalIndex, workgroupArray, uvec2, floor, instanceIndex, workgroupBarrier, atomicAdd, atomicStore, workgroupId } from 'three/tsl';
import { storage, If, vec3, not, uniform, uv, uint, float, Fn, vec2, abs, int, invocationLocalIndex, workgroupArray, uvec2, floor, instanceIndex, workgroupBarrier, atomicAdd, atomicStore, workgroupId } from 'three/tsl';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaning up some deprecation warnings.


import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

Expand Down Expand Up @@ -141,17 +141,17 @@

const nextAlgoBuffer = new THREE.StorageInstancedBufferAttribute( new Uint32Array( 1 ).fill( forceGlobalSwap ? StepType.FLIP_GLOBAL : StepType.FLIP_LOCAL ), 1 );

const nextAlgoStorage = storageObject( nextAlgoBuffer, 'uint', nextAlgoBuffer.count ).label( 'NextAlgo' );
const nextAlgoStorage = storage( nextAlgoBuffer, 'uint', nextAlgoBuffer.count ).setPBO( true ).label( 'NextAlgo' );

const nextBlockHeightBuffer = new THREE.StorageInstancedBufferAttribute( new Uint32Array( 1 ).fill( 2 ), 1 );
const nextBlockHeightStorage = storageObject( nextBlockHeightBuffer, 'uint', nextBlockHeightBuffer.count ).label( 'NextBlockHeight' );
const nextBlockHeightRead = storageObject( nextBlockHeightBuffer, 'uint', nextBlockHeightBuffer.count ).label( 'NextBlockHeight' ).toReadOnly();
const nextBlockHeightStorage = storage( nextBlockHeightBuffer, 'uint', nextBlockHeightBuffer.count ).setPBO( true ).label( 'NextBlockHeight' );
const nextBlockHeightRead = storage( nextBlockHeightBuffer, 'uint', nextBlockHeightBuffer.count ).setPBO( true ).label( 'NextBlockHeight' ).toReadOnly();

const highestBlockHeightBuffer = new THREE.StorageInstancedBufferAttribute( new Uint32Array( 1 ).fill( 2 ), 1 );
const highestBlockHeightStorage = storageObject( highestBlockHeightBuffer, 'uint', highestBlockHeightBuffer.count ).label( 'HighestBlockHeight' );
const highestBlockHeightStorage = storage( highestBlockHeightBuffer, 'uint', highestBlockHeightBuffer.count ).setPBO( true ).label( 'HighestBlockHeight' );

const counterBuffer = new THREE.StorageBufferAttribute( 1, 1 );
const counterStorage = storageObject( counterBuffer, 'uint', counterBuffer.count ).toAtomic().label( 'Counter' );
const counterStorage = storage( counterBuffer, 'uint', counterBuffer.count ).setPBO( true ).toAtomic().label( 'Counter' );

const array = new Uint32Array( Array.from( { length: size }, ( _, i ) => {

Expand Down Expand Up @@ -179,11 +179,11 @@
randomizeDataArray();

const currentElementsBuffer = new THREE.StorageInstancedBufferAttribute( array, 1 );
const currentElementsStorage = storageObject( currentElementsBuffer, 'uint', size ).label( 'Elements' );
const currentElementsStorage = storage( currentElementsBuffer, 'uint', size ).setPBO( true ).label( 'Elements' );
const tempBuffer = new THREE.StorageInstancedBufferAttribute( array, 1 );
const tempStorage = storageObject( tempBuffer, 'uint', size ).label( 'Temp' );
const tempStorage = storage( tempBuffer, 'uint', size ).setPBO( true ).label( 'Temp' );
const randomizedElementsBuffer = new THREE.StorageInstancedBufferAttribute( size, 1 );
const randomizedElementsStorage = storageObject( randomizedElementsBuffer, 'uint', size ).label( 'RandomizedElements' );
const randomizedElementsStorage = storage( randomizedElementsBuffer, 'uint', size ).setPBO( true ).label( 'RandomizedElements' );

const getFlipIndices = ( index, blockHeight ) => {

Expand Down
19 changes: 18 additions & 1 deletion src/nodes/accessors/Arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import StorageBufferAttribute from '../../renderers/common/StorageBufferAttribut
import { storage } from './StorageBufferNode.js';
import { getLengthFromType } from '../core/NodeUtils.js';

/** @module Arrays **/

/**
* TSL function for creating a storage buffer node with a configured `StorageBufferAttribute`.
*
* @function
* @param {Number} count - The data count.
* @param {String} [type='float'] - The data type.
* @returns {StorageBufferNode}
*/
export const attributeArray = ( count, type = 'float' ) => {

const itemSize = getLengthFromType( type );
Expand All @@ -14,7 +24,14 @@ export const attributeArray = ( count, type = 'float' ) => {

};


/**
* TSL function for creating a storage buffer node with a configured `StorageInstancedBufferAttribute`.
*
* @function
* @param {Number} count - The data count.
* @param {String} [type='float'] - The data type.
* @returns {StorageBufferNode}
*/
export const instancedArray = ( count, type = 'float' ) => {

const itemSize = getLengthFromType( type );
Expand Down
183 changes: 178 additions & 5 deletions src/nodes/accessors/BufferAttributeNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ import { InterleavedBufferAttribute } from '../../core/InterleavedBufferAttribut
import { InterleavedBuffer } from '../../core/InterleavedBuffer.js';
import { StaticDrawUsage, DynamicDrawUsage } from '../../constants.js';

/** @module BufferAttributeNode **/

/**
* In earlier `three.js` versions it was only possible to define attribute data
* on geometry level. With `BufferAttributeNode`, it is also possible to do this
* on the node level.
* ```js
* const geometry = new THREE.PlaneGeometry();
* const positionAttribute = geometry.getAttribute( 'position' );
*
* const colors = [];
* for ( let i = 0; i < position.count; i ++ ) {
* colors.push( 1, 0, 0 );
* }
*
* material.colorNode = bufferAttribute( new THREE.Float32BufferAttribute( colors, 3 ) );
* ```
* This new approach is especially interesting when geometry data are generated via
* compute shaders. The below line converts a storage buffer into an attribute.
* ```js
* material.positionNode = positionBuffer.toAttribute();
* ```
* @augments InputNode
*/
class BufferAttributeNode extends InputNode {

static get type() {
Expand All @@ -14,21 +38,82 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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 ) {
Expand All @@ -41,6 +126,13 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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 ) {
Expand All @@ -65,6 +157,13 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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 ) {
Expand All @@ -77,6 +176,13 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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;
Expand All @@ -97,6 +203,12 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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 );
Expand Down Expand Up @@ -124,12 +236,24 @@ class BufferAttributeNode extends InputNode {

}

/**
* 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;
Expand All @@ -144,6 +268,12 @@ class BufferAttributeNode extends InputNode {

}

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

this.instanced = value;
Expand All @@ -156,10 +286,53 @@ class BufferAttributeNode extends InputNode {

export default BufferAttributeNode;

export const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) );
export const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage );

export const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true );
export const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true );
/**
* TSL function for creating a buffer attribute node.
*
* @function
* @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data.
* @param {String?} [type=null] - The buffer type (e.g. `'vec3'`).
* @param {Number} [stride=0] - The buffer stride.
* @param {Number} [offset=0] - The buffer offset.
* @returns {BufferAttributeNode}
*/
export const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) );

/**
* TSL function for creating a buffer attribute node but with dynamic draw usage.
* Use this function if attribute data are updated per frame.
*
* @function
* @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data.
* @param {String?} [type=null] - The buffer type (e.g. `'vec3'`).
* @param {Number} [stride=0] - The buffer stride.
* @param {Number} [offset=0] - The buffer offset.
* @returns {BufferAttributeNode}
*/
export const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage );

/**
* TSL function for creating a buffer attribute node but with enabled instancing
*
* @function
* @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data.
* @param {String?} [type=null] - The buffer type (e.g. `'vec3'`).
* @param {Number} [stride=0] - The buffer stride.
* @param {Number} [offset=0] - The buffer offset.
* @returns {BufferAttributeNode}
*/
export const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true );

/**
* TSL function for creating a buffer attribute node but with dynamic draw usage and enabled instancing
*
* @function
* @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data.
* @param {String?} [type=null] - The buffer type (e.g. `'vec3'`).
* @param {Number} [stride=0] - The buffer stride.
* @param {Number} [offset=0] - The buffer offset.
* @returns {BufferAttributeNode}
*/
export const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true );

addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) );
Loading
Loading