Skip to content

Commit

Permalink
Node: Document more modules. (#30123)
Browse files Browse the repository at this point in the history
* Node: Document more modules.

* Node: Document more modules.

* Exampels: Clean up.
  • Loading branch information
Mugen87 authored Dec 14, 2024
1 parent ef5be21 commit 0f523ac
Show file tree
Hide file tree
Showing 13 changed files with 1,102 additions and 38 deletions.
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';

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

0 comments on commit 0f523ac

Please sign in to comment.