11import InputNode from '../core/InputNode.js' ;
2- import { nodeObject , addMethodChaining } from '../tsl/TSLCore.js' ;
2+ import { addMethodChaining , mat3 , mat4 } from '../tsl/TSLCore.js' ;
33import { varying } from '../core/VaryingNode.js' ;
44
55import { InterleavedBufferAttribute } from '../../core/InterleavedBufferAttribute.js' ;
66import { InterleavedBuffer } from '../../core/InterleavedBuffer.js' ;
77import { 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
285334export 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
340426addMethodChaining ( 'toAttribute' , ( bufferNode ) => bufferAttribute ( bufferNode . value ) ) ;
0 commit comments