|
6 | 6 | FileLoader, |
7 | 7 | Loader, |
8 | 8 | LinearSRGBColorSpace, |
9 | | - SRGBColorSpace |
| 9 | + SRGBColorSpace, |
| 10 | + InterleavedBuffer, |
| 11 | + InterleavedBufferAttribute |
10 | 12 | } from 'three'; |
11 | 13 |
|
12 | 14 | const _taskCache = new WeakMap(); |
@@ -273,16 +275,25 @@ class DRACOLoader extends Loader { |
273 | 275 |
|
274 | 276 | for ( let i = 0; i < geometryData.attributes.length; i ++ ) { |
275 | 277 |
|
276 | | - const result = geometryData.attributes[ i ]; |
277 | | - const name = result.name; |
278 | | - const array = result.array; |
279 | | - const itemSize = result.itemSize; |
| 278 | + const { name, array, itemSize, stride, vertexColorSpace } = geometryData.attributes[ i ]; |
280 | 279 |
|
281 | | - const attribute = new BufferAttribute( array, itemSize ); |
| 280 | + let attribute; |
| 281 | + |
| 282 | + if ( itemSize === stride ) { |
| 283 | + |
| 284 | + attribute = new BufferAttribute( array, itemSize ); |
| 285 | + |
| 286 | + } else { |
| 287 | + |
| 288 | + const buffer = new InterleavedBuffer( array, stride ); |
| 289 | + |
| 290 | + attribute = new InterleavedBufferAttribute( buffer, itemSize, 0 ); |
| 291 | + |
| 292 | + } |
282 | 293 |
|
283 | 294 | if ( name === 'color' ) { |
284 | 295 |
|
285 | | - this._assignVertexColorSpace( attribute, result.vertexColorSpace ); |
| 296 | + this._assignVertexColorSpace( attribute, vertexColorSpace ); |
286 | 297 |
|
287 | 298 | attribute.normalized = ( array instanceof Float32Array ) === false; |
288 | 299 |
|
@@ -646,30 +657,70 @@ function DRACOWorker() { |
646 | 657 |
|
647 | 658 | } |
648 | 659 |
|
649 | | - function decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) { |
| 660 | + function decodeAttribute( draco, decoder, dracoGeometry, attributeName, TypedArray, attribute ) { |
650 | 661 |
|
651 | | - const numComponents = attribute.num_components(); |
652 | | - const numPoints = dracoGeometry.num_points(); |
653 | | - const numValues = numPoints * numComponents; |
654 | | - const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; |
655 | | - const dataType = getDracoDataType( draco, attributeType ); |
| 662 | + const count = dracoGeometry.num_points(); |
| 663 | + const itemSize = attribute.num_components(); |
| 664 | + const dracoDataType = getDracoDataType( draco, TypedArray ); |
| 665 | + |
| 666 | + // Reference: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#data-alignment |
| 667 | + const srcByteStride = itemSize * TypedArray.BYTES_PER_ELEMENT; |
| 668 | + const dstByteStride = Math.ceil( srcByteStride / 4 ) * 4; |
| 669 | + |
| 670 | + const dstStride = dstByteStride / TypedArray.BYTES_PER_ELEMENT |
| 671 | + |
| 672 | + const srcByteLength = count * srcByteStride; |
| 673 | + const dstByteLength = count * dstByteStride; |
| 674 | + |
| 675 | + const ptr = draco._malloc( srcByteLength ); |
| 676 | + decoder.GetAttributeDataArrayForAllPoints( dracoGeometry, attribute, dracoDataType, srcByteLength, ptr ); |
| 677 | + |
| 678 | + const srcArray = new TypedArray( draco.HEAPF32.buffer, ptr, srcByteLength / TypedArray.BYTES_PER_ELEMENT ); |
| 679 | + let dstArray; |
| 680 | + |
| 681 | + if ( srcByteStride === dstByteStride ) { |
| 682 | + |
| 683 | + // THREE.BufferAttribute |
| 684 | + |
| 685 | + dstArray = srcArray.slice(); |
| 686 | + |
| 687 | + } else { |
| 688 | + |
| 689 | + // THREE.InterleavedBufferAttribute |
| 690 | + |
| 691 | + dstArray = new TypedArray( dstByteLength / TypedArray.BYTES_PER_ELEMENT ); |
| 692 | + |
| 693 | + let dstOffset = 0 |
| 694 | + |
| 695 | + for ( let i = 0, il = srcArray.length; i < il; i++ ) { |
| 696 | + |
| 697 | + for ( let j = 0; j < itemSize; j++ ) { |
| 698 | + |
| 699 | + dstArray[ dstOffset + j ] = srcArray[ i * itemSize + j ] |
| 700 | + |
| 701 | + } |
| 702 | + |
| 703 | + dstOffset += dstStride; |
| 704 | + |
| 705 | + } |
| 706 | + |
| 707 | + } |
656 | 708 |
|
657 | | - const ptr = draco._malloc( byteLength ); |
658 | | - decoder.GetAttributeDataArrayForAllPoints( dracoGeometry, attribute, dataType, byteLength, ptr ); |
659 | | - const array = new attributeType( draco.HEAPF32.buffer, ptr, numValues ).slice(); |
660 | 709 | draco._free( ptr ); |
661 | 710 |
|
662 | 711 | return { |
663 | 712 | name: attributeName, |
664 | | - array: array, |
665 | | - itemSize: numComponents |
| 713 | + count: count, |
| 714 | + itemSize: itemSize, |
| 715 | + array: dstArray, |
| 716 | + stride: dstStride |
666 | 717 | }; |
667 | 718 |
|
668 | 719 | } |
669 | 720 |
|
670 | | - function getDracoDataType( draco, attributeType ) { |
| 721 | + function getDracoDataType( draco, TypedArray ) { |
671 | 722 |
|
672 | | - switch ( attributeType ) { |
| 723 | + switch ( TypedArray ) { |
673 | 724 |
|
674 | 725 | case Float32Array: return draco.DT_FLOAT32; |
675 | 726 | case Int8Array: return draco.DT_INT8; |
|
0 commit comments