📄 InstanceNode.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 2 |
🧱 Classes | 1 |
📦 Imports | 16 |
📊 Variables & Constants | 6 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 src/nodes/accessors/InstanceNode.js
📦 Imports¶
Name | Source |
---|---|
Node |
../core/Node.js |
varyingProperty |
../core/PropertyNode.js |
instancedBufferAttribute |
./BufferAttributeNode.js |
instancedDynamicBufferAttribute |
./BufferAttributeNode.js |
normalLocal |
./Normal.js |
transformNormal |
./Normal.js |
positionLocal |
./Position.js |
nodeProxy |
../tsl/TSLBase.js |
vec3 |
../tsl/TSLBase.js |
mat4 |
../tsl/TSLBase.js |
NodeUpdateType |
../core/constants.js |
buffer |
../accessors/BufferNode.js |
instanceIndex |
../core/IndexNode.js |
InstancedInterleavedBuffer |
../../core/InstancedInterleavedBuffer.js |
InstancedBufferAttribute |
../../core/InstancedBufferAttribute.js |
DynamicDrawUsage |
../../constants.js |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
buffer |
InstancedInterleavedBuffer |
let/var | new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 ) |
✗ |
bufferFn |
(array: any, type?: string, stride?: ... |
let/var | instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute :... |
✗ |
instanceBuffers |
BufferAttributeNode[] |
let/var | [ // F.Signature -> bufferAttribute( array, type, stride, offset ) bufferFn( ... |
✗ |
buffer |
InstancedBufferAttribute |
let/var | new InstancedBufferAttribute( instanceColor.array, 3 ) |
✗ |
bufferFn |
(array: any, type?: string, stride?: ... |
let/var | instanceColor.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : ... |
✗ |
instancePosition |
any |
let/var | instanceMatrixNode.mul( positionLocal ).xyz |
✗ |
Functions¶
InstanceNode.setup(builder: NodeBuilder): void
¶
JSDoc:
/**
* Setups the internal buffers and nodes and assigns the transformed vertex data
* to predefined node variables for accumulation. That follows the same patterns
* like with morph and skinning nodes.
*
* @param {NodeBuilder} builder - The current node builder.
*/
Parameters:
builder
NodeBuilder
Returns: void
Calls:
buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element
bufferFn
mat4 (from ../tsl/TSLBase.js)
vec3 (from ../tsl/TSLBase.js)
instanceMatrixNode.mul
positionLocal.assign
builder.hasGeometryAttribute
transformNormal (from ./Normal.js)
normalLocal.assign
varyingProperty( 'vec3', 'vInstanceColor' ).assign
Internal Comments:
// Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute.
// F.Signature -> bufferAttribute( array, type, stride, offset ) (x2)
// POSITION (x2)
// NORMAL
// ASSIGNS (x4)
// COLOR
Code
setup( builder ) {
const { count, instanceMatrix, instanceColor } = this;
let { instanceMatrixNode, instanceColorNode } = this;
if ( instanceMatrixNode === null ) {
// Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute.
if ( count <= 1000 ) {
instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
} else {
const buffer = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
this.buffer = buffer;
const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
const instanceBuffers = [
// F.Signature -> bufferAttribute( array, type, stride, offset )
bufferFn( buffer, 'vec4', 16, 0 ),
bufferFn( buffer, 'vec4', 16, 4 ),
bufferFn( buffer, 'vec4', 16, 8 ),
bufferFn( buffer, 'vec4', 16, 12 )
];
instanceMatrixNode = mat4( ...instanceBuffers );
}
this.instanceMatrixNode = instanceMatrixNode;
}
if ( instanceColor && instanceColorNode === null ) {
const buffer = new InstancedBufferAttribute( instanceColor.array, 3 );
const bufferFn = instanceColor.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
this.bufferColor = buffer;
instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) );
this.instanceColorNode = instanceColorNode;
}
// POSITION
const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
positionLocal.assign( instancePosition );
// NORMAL
if ( builder.hasGeometryAttribute( 'normal' ) ) {
const instanceNormal = transformNormal( normalLocal, instanceMatrixNode );
// ASSIGNS
normalLocal.assign( instanceNormal );
}
// COLOR
if ( this.instanceColorNode !== null ) {
varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode );
}
}
InstanceNode.update(): void
¶
JSDoc:
/**
* Checks if the internal buffers required an update.
*
* @param {NodeFrame} frame - The current node frame.
*/
Returns: void
Code
update( /*frame*/ ) {
if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) {
this.buffer.version = this.instanceMatrix.version;
}
if ( this.instanceColor && this.instanceColor.usage !== DynamicDrawUsage && this.bufferColor !== null && this.instanceColor.version !== this.bufferColor.version ) {
this.bufferColor.version = this.instanceColor.version;
}
}
Classes¶
InstanceNode
¶
Class Code
class InstanceNode extends Node {
static get type() {
return 'InstanceNode';
}
/**
* Constructs a new instance node.
*
* @param {number} count - The number of instances.
* @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations.
* @param {?InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors.
*/
constructor( count, instanceMatrix, instanceColor = null ) {
super( 'void' );
/**
* The number of instances.
*
* @type {number}
*/
this.count = count;
/**
* Instanced buffer attribute representing the transformation of instances.
*
* @type {InstancedBufferAttribute}
*/
this.instanceMatrix = instanceMatrix;
/**
* Instanced buffer attribute representing the color of instances.
*
* @type {InstancedBufferAttribute}
*/
this.instanceColor = instanceColor;
/**
* The node that represents the instance matrix data.
*
* @type {?Node}
*/
this.instanceMatrixNode = null;
/**
* The node that represents the instance color data.
*
* @type {?Node}
* @default null
*/
this.instanceColorNode = null;
/**
* The update type is set to `frame` since an update
* of instanced buffer data must be checked per frame.
*
* @type {string}
* @default 'frame'
*/
this.updateType = NodeUpdateType.FRAME;
/**
* A reference to a buffer that is used by `instanceMatrixNode`.
*
* @type {?InstancedInterleavedBuffer}
*/
this.buffer = null;
/**
* A reference to a buffer that is used by `instanceColorNode`.
*
* @type {?InstancedBufferAttribute}
*/
this.bufferColor = null;
}
/**
* Setups the internal buffers and nodes and assigns the transformed vertex data
* to predefined node variables for accumulation. That follows the same patterns
* like with morph and skinning nodes.
*
* @param {NodeBuilder} builder - The current node builder.
*/
setup( builder ) {
const { count, instanceMatrix, instanceColor } = this;
let { instanceMatrixNode, instanceColorNode } = this;
if ( instanceMatrixNode === null ) {
// Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute.
if ( count <= 1000 ) {
instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
} else {
const buffer = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
this.buffer = buffer;
const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
const instanceBuffers = [
// F.Signature -> bufferAttribute( array, type, stride, offset )
bufferFn( buffer, 'vec4', 16, 0 ),
bufferFn( buffer, 'vec4', 16, 4 ),
bufferFn( buffer, 'vec4', 16, 8 ),
bufferFn( buffer, 'vec4', 16, 12 )
];
instanceMatrixNode = mat4( ...instanceBuffers );
}
this.instanceMatrixNode = instanceMatrixNode;
}
if ( instanceColor && instanceColorNode === null ) {
const buffer = new InstancedBufferAttribute( instanceColor.array, 3 );
const bufferFn = instanceColor.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
this.bufferColor = buffer;
instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) );
this.instanceColorNode = instanceColorNode;
}
// POSITION
const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
positionLocal.assign( instancePosition );
// NORMAL
if ( builder.hasGeometryAttribute( 'normal' ) ) {
const instanceNormal = transformNormal( normalLocal, instanceMatrixNode );
// ASSIGNS
normalLocal.assign( instanceNormal );
}
// COLOR
if ( this.instanceColorNode !== null ) {
varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode );
}
}
/**
* Checks if the internal buffers required an update.
*
* @param {NodeFrame} frame - The current node frame.
*/
update( /*frame*/ ) {
if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) {
this.buffer.version = this.instanceMatrix.version;
}
if ( this.instanceColor && this.instanceColor.usage !== DynamicDrawUsage && this.bufferColor !== null && this.instanceColor.version !== this.bufferColor.version ) {
this.bufferColor.version = this.instanceColor.version;
}
}
}
Methods¶
setup(builder: NodeBuilder): void
¶
Code
setup( builder ) {
const { count, instanceMatrix, instanceColor } = this;
let { instanceMatrixNode, instanceColorNode } = this;
if ( instanceMatrixNode === null ) {
// Both WebGPU and WebGL backends have UBO max limited to 64kb. Matrix count number bigger than 1000 ( 16 * 4 * 1000 = 64kb ) will fallback to attribute.
if ( count <= 1000 ) {
instanceMatrixNode = buffer( instanceMatrix.array, 'mat4', Math.max( count, 1 ) ).element( instanceIndex );
} else {
const buffer = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
this.buffer = buffer;
const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
const instanceBuffers = [
// F.Signature -> bufferAttribute( array, type, stride, offset )
bufferFn( buffer, 'vec4', 16, 0 ),
bufferFn( buffer, 'vec4', 16, 4 ),
bufferFn( buffer, 'vec4', 16, 8 ),
bufferFn( buffer, 'vec4', 16, 12 )
];
instanceMatrixNode = mat4( ...instanceBuffers );
}
this.instanceMatrixNode = instanceMatrixNode;
}
if ( instanceColor && instanceColorNode === null ) {
const buffer = new InstancedBufferAttribute( instanceColor.array, 3 );
const bufferFn = instanceColor.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
this.bufferColor = buffer;
instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) );
this.instanceColorNode = instanceColorNode;
}
// POSITION
const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
positionLocal.assign( instancePosition );
// NORMAL
if ( builder.hasGeometryAttribute( 'normal' ) ) {
const instanceNormal = transformNormal( normalLocal, instanceMatrixNode );
// ASSIGNS
normalLocal.assign( instanceNormal );
}
// COLOR
if ( this.instanceColorNode !== null ) {
varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode );
}
}
update(): void
¶
Code
update( /*frame*/ ) {
if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) {
this.buffer.version = this.instanceMatrix.version;
}
if ( this.instanceColor && this.instanceColor.usage !== DynamicDrawUsage && this.bufferColor !== null && this.instanceColor.version !== this.bufferColor.version ) {
this.bufferColor.version = this.instanceColor.version;
}
}