Quellcode durchsuchen

GLTFLoader: Fix incorrect accessor count caching

When two accessors with a different count but the same component type
share a buffer view, there are two cases in GLTF loader:

- If accessor stride is "natural" (equal to item size in bytes), a
TypedArray slice is created with the count matching accessor count

- If accessor stride is "unnatural", an InterleavedBuffer is created for
the entire buffer view; accessor count is ignored as a result.

Incorrect count is problematic because various algorithms such as
bounding box calculation would try to process elements that may not
exist in the buffer. Note that this situation arises for any unnatural
stride, whether the rest of the stride is used by another interleaved
accessor or not.

A solution is to make sure that the InterleavedBufferAttribute.count
(which is derived from InterleavedBuffer.array.length) is always
correct, by creating a TypedArray from a "slice" of the buffer view.

In an actual interleaving situation this maintains the effectiveness of
the cache - multiple accessors sharing the same interleaved data that
are used in the same mesh primitive will get the same slice (since the
byte offsets will be almost the same, and floor(byteoffset / stride)
will match). Thus this change should only fix existing cases where
.count is broken and not make anything worse.

Fixed #16802.
Arseny Kapoulkine vor 6 Jahren
Ursprung
Commit
c1af2b385b
1 geänderte Dateien mit 6 neuen und 4 gelöschten Zeilen
  1. 6 4
      examples/js/loaders/GLTFLoader.js

+ 6 - 4
examples/js/loaders/GLTFLoader.js

@@ -1875,13 +1875,15 @@ THREE.GLTFLoader = ( function () {
 			// The buffer is not interleaved if the stride is the item size in bytes.
 			if ( byteStride && byteStride !== itemBytes ) {
 
-				var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType;
+				// Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
+				// This makes sure that IBA.count reflects accessor.count properly
+				var ibSlice = Math.floor( byteOffset / byteStride );
+				var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count;
 				var ib = parser.cache.get( ibCacheKey );
 
 				if ( ! ib ) {
 
-					// Use the full buffer if it's interleaved.
-					array = new TypedArray( bufferView );
+					array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes );
 
 					// Integer parameters to IB/IBA are in array elements, not bytes.
 					ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes );
@@ -1890,7 +1892,7 @@ THREE.GLTFLoader = ( function () {
 
 				}
 
-				bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, byteOffset / elementBytes, normalized );
+				bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, (byteOffset % byteStride) / elementBytes, normalized );
 
 			} else {