Skip to content

Commit 473ac04

Browse files
authored
TSL: Add support for mat3 and mat4 using bufferAttribute (#32204)
* add support for `mat3` and `mat4` * cleanup
1 parent fde4b93 commit 473ac04

File tree

2 files changed

+102
-24
lines changed

2 files changed

+102
-24
lines changed

src/nodes/accessors/BufferAttributeNode.js

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,43 @@
11
import InputNode from '../core/InputNode.js';
2-
import { nodeObject, addMethodChaining } from '../tsl/TSLCore.js';
2+
import { addMethodChaining, mat3, mat4 } from '../tsl/TSLCore.js';
33
import { varying } from '../core/VaryingNode.js';
44

55
import { InterleavedBufferAttribute } from '../../core/InterleavedBufferAttribute.js';
66
import { InterleavedBuffer } from '../../core/InterleavedBuffer.js';
77
import { StaticDrawUsage, DynamicDrawUsage } from '../../constants.js';
88

9+
/**
10+
* Internal buffer attribute library.
11+
*
12+
* @private
13+
* @type {WeakMap<TypedArray, InterleavedBuffer>}
14+
*/
15+
const _bufferLib = new WeakMap();
16+
17+
/**
18+
* Internal method for retrieving or creating interleaved buffers.
19+
*
20+
* @private
21+
* @param {TypedArray} value - The attribute data.
22+
* @param {number} itemSize - The attribute item size.
23+
* @returns {InterleavedBuffer} The interleaved buffer.
24+
*/
25+
function _getBufferAttribute( value, itemSize ) {
26+
27+
let buffer = _bufferLib.get( value );
28+
29+
if ( buffer === undefined ) {
30+
31+
buffer = new InterleavedBuffer( value, itemSize );
32+
33+
_bufferLib.set( value, buffer );
34+
35+
}
36+
37+
return buffer;
38+
39+
}
40+
941
/**
1042
* In earlier `three.js` versions it was only possible to define attribute data
1143
* on geometry level. With `BufferAttributeNode`, it is also possible to do this
@@ -114,7 +146,7 @@ class BufferAttributeNode extends InputNode {
114146
*/
115147
this.global = true;
116148

117-
if ( value && value.isBufferAttribute === true ) {
149+
if ( value && value.isBufferAttribute === true && value.itemSize <= 4 ) {
118150

119151
this.attribute = value;
120152
this.usage = value.usage;
@@ -185,13 +217,30 @@ class BufferAttributeNode extends InputNode {
185217

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

220+
//
221+
188222
const type = this.getNodeType( builder );
189-
const array = this.value;
190223
const itemSize = builder.getTypeLength( type );
224+
const value = this.value;
191225
const stride = this.bufferStride || itemSize;
192226
const offset = this.bufferOffset;
193227

194-
const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride );
228+
let buffer;
229+
230+
if ( value.isInterleavedBuffer === true ) {
231+
232+
buffer = value;
233+
234+
} else if ( value.isBufferAttribute === true ) {
235+
236+
buffer = _getBufferAttribute( value.array, stride );
237+
238+
} else {
239+
240+
buffer = _getBufferAttribute( value, stride );
241+
242+
}
243+
195244
const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );
196245

197246
buffer.setUsage( this.usage );
@@ -284,6 +333,43 @@ class BufferAttributeNode extends InputNode {
284333

285334
export default BufferAttributeNode;
286335

336+
/**
337+
* Internal method for creating buffer attribute nodes.
338+
*
339+
* @private
340+
* @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data.
341+
* @param {?string} [type=null] - The buffer type (e.g. `'vec3'`).
342+
* @param {number} [stride=0] - The buffer stride.
343+
* @param {number} [offset=0] - The buffer offset.
344+
* @param {number} [usage=StaticDrawUsage] - The buffer usage.
345+
* @param {boolean} [instanced=false] - Whether the buffer is instanced.
346+
* @returns {BufferAttributeNode|Node} The buffer attribute node.
347+
*/
348+
function createBufferAttribute( array, type = null, stride = 0, offset = 0, usage = StaticDrawUsage, instanced = false ) {
349+
350+
if ( type === 'mat3' || ( type === null && array.itemSize === 9 ) ) {
351+
352+
return mat3(
353+
new BufferAttributeNode( array, 'vec3', 9, 0 ).setUsage( usage ).setInstanced( instanced ),
354+
new BufferAttributeNode( array, 'vec3', 9, 3 ).setUsage( usage ).setInstanced( instanced ),
355+
new BufferAttributeNode( array, 'vec3', 9, 6 ).setUsage( usage ).setInstanced( instanced )
356+
);
357+
358+
} else if ( type === 'mat4' || ( type === null && array.itemSize === 16 ) ) {
359+
360+
return mat4(
361+
new BufferAttributeNode( array, 'vec4', 16, 0 ).setUsage( usage ).setInstanced( instanced ),
362+
new BufferAttributeNode( array, 'vec4', 16, 4 ).setUsage( usage ).setInstanced( instanced ),
363+
new BufferAttributeNode( array, 'vec4', 16, 8 ).setUsage( usage ).setInstanced( instanced ),
364+
new BufferAttributeNode( array, 'vec4', 16, 12 ).setUsage( usage ).setInstanced( instanced )
365+
);
366+
367+
}
368+
369+
return new BufferAttributeNode( array, type, stride, offset );
370+
371+
}
372+
287373
/**
288374
* TSL function for creating a buffer attribute node.
289375
*
@@ -293,9 +379,9 @@ export default BufferAttributeNode;
293379
* @param {?string} [type=null] - The buffer type (e.g. `'vec3'`).
294380
* @param {number} [stride=0] - The buffer stride.
295381
* @param {number} [offset=0] - The buffer offset.
296-
* @returns {BufferAttributeNode}
382+
* @returns {BufferAttributeNode|Node}
297383
*/
298-
export const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) );
384+
export const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => createBufferAttribute( array, type, stride, offset );
299385

300386
/**
301387
* TSL function for creating a buffer attribute node but with dynamic draw usage.
@@ -307,9 +393,9 @@ export const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) =>
307393
* @param {?string} [type=null] - The buffer type (e.g. `'vec3'`).
308394
* @param {number} [stride=0] - The buffer stride.
309395
* @param {number} [offset=0] - The buffer offset.
310-
* @returns {BufferAttributeNode}
396+
* @returns {BufferAttributeNode|Node}
311397
*/
312-
export const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage );
398+
export const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => createBufferAttribute( array, type, stride, offset, DynamicDrawUsage );
313399

314400
/**
315401
* TSL function for creating a buffer attribute node but with enabled instancing
@@ -320,9 +406,9 @@ export const dynamicBufferAttribute = ( array, type = null, stride = 0, offset =
320406
* @param {?string} [type=null] - The buffer type (e.g. `'vec3'`).
321407
* @param {number} [stride=0] - The buffer stride.
322408
* @param {number} [offset=0] - The buffer offset.
323-
* @returns {BufferAttributeNode}
409+
* @returns {BufferAttributeNode|Node}
324410
*/
325-
export const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true );
411+
export const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => createBufferAttribute( array, type, stride, offset, StaticDrawUsage, true );
326412

327413
/**
328414
* TSL function for creating a buffer attribute node but with dynamic draw usage and enabled instancing
@@ -333,8 +419,8 @@ export const instancedBufferAttribute = ( array, type = null, stride = 0, offset
333419
* @param {?string} [type=null] - The buffer type (e.g. `'vec3'`).
334420
* @param {number} [stride=0] - The buffer stride.
335421
* @param {number} [offset=0] - The buffer offset.
336-
* @returns {BufferAttributeNode}
422+
* @returns {BufferAttributeNode|Node}
337423
*/
338-
export const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true );
424+
export const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => createBufferAttribute( array, type, stride, offset, DynamicDrawUsage, true );
339425

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

src/nodes/accessors/InstanceNode.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { varyingProperty } from '../core/PropertyNode.js';
33
import { instancedBufferAttribute, instancedDynamicBufferAttribute } from './BufferAttributeNode.js';
44
import { normalLocal, transformNormal } from './Normal.js';
55
import { positionLocal } from './Position.js';
6-
import { nodeProxy, vec3, mat4 } from '../tsl/TSLBase.js';
6+
import { nodeProxy, vec3 } from '../tsl/TSLBase.js';
77
import { NodeUpdateType } from '../core/constants.js';
88
import { buffer } from '../accessors/BufferNode.js';
99
import { instanceIndex } from '../core/IndexNode.js';
@@ -127,19 +127,11 @@ class InstanceNode extends Node {
127127

128128
const buffer = new InstancedInterleavedBuffer( instanceMatrix.array, 16, 1 );
129129

130-
this.buffer = buffer;
131-
132-
const bufferFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
130+
const instancedBufferAttributeFn = instanceMatrix.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
133131

134-
const instanceBuffers = [
135-
// F.Signature -> bufferAttribute( array, type, stride, offset )
136-
bufferFn( buffer, 'vec4', 16, 0 ),
137-
bufferFn( buffer, 'vec4', 16, 4 ),
138-
bufferFn( buffer, 'vec4', 16, 8 ),
139-
bufferFn( buffer, 'vec4', 16, 12 )
140-
];
132+
instanceMatrixNode = instancedBufferAttributeFn( buffer, 'mat4' );
141133

142-
instanceMatrixNode = mat4( ...instanceBuffers );
134+
this.buffer = buffer;
143135

144136
}
145137

0 commit comments

Comments
 (0)