Browse Source

GLTFLoader: Update MeshoptDecoder support to support WebWorkers (#24460)

MeshoptDecoder can decode at ~1 GB/sec (with filters) on modern desktop
CPUs, which mostly means we don't need to offload the processing to
other threads... except when we're dealing with scenes with ~800 MB of
geometry, at which point we might be stalling the main thread for
700-900ms.

To solve this, meshoptimizer is implementing support for WebWorkers:
https://github.com/zeux/meshoptimizer/pull/454

The decoder gains a new function, decodeGltfBufferAsync, which works
regardless of whether WebWorkers are enabled; when decoder.useWorkers is
called with the desired worker count, it switches to asynchronous
decoding which almost entirely eliminates main thread overhead, with the
exception of copying the input buffer.

This change is structured to still work with the old versions of the
library, the library will be updated separately. Note that when
decodeGltfBufferAsync is used, `ready` promise doesn't need to be used.
Arseny Kapoulkine 3 years ago
parent
commit
223c5721f2
1 changed files with 22 additions and 5 deletions
  1. 22 5
      examples/jsm/loaders/GLTFLoader.js

+ 22 - 5
examples/jsm/loaders/GLTFLoader.js

@@ -1341,7 +1341,7 @@ class GLTFMeshoptCompression {
 
 			}
 
-			return Promise.all( [ buffer, decoder.ready ] ).then( function ( res ) {
+			return buffer.then( function ( res ) {
 
 				const byteOffset = extensionDef.byteOffset || 0;
 				const byteLength = extensionDef.byteLength || 0;
@@ -1349,11 +1349,28 @@ class GLTFMeshoptCompression {
 				const count = extensionDef.count;
 				const stride = extensionDef.byteStride;
 
-				const result = new ArrayBuffer( count * stride );
-				const source = new Uint8Array( res[ 0 ], byteOffset, byteLength );
+				const source = new Uint8Array( res, byteOffset, byteLength );
 
-				decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
-				return result;
+				if ( decoder.decodeGltfBufferAsync ) {
+
+					return decoder.decodeGltfBufferAsync( count, stride, source, extensionDef.mode, extensionDef.filter ).then( function ( res ) {
+
+						return res.buffer;
+
+					} );
+
+				} else {
+
+					// Support for MeshoptDecoder 0.18 or earlier, without decodeGltfBufferAsync
+					return decoder.ready.then( function () {
+
+						const result = new ArrayBuffer( count * stride );
+						decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
+						return result;
+
+					} );
+
+				}
 
 			} );