Repository navigation
feat: Decode EXT_meshopt_compression and KHR_meshopt_compression glTF buffer views - #9738
Conversation
… buffer views Adds meshoptInitialize, which takes the meshoptimizer decoder object or the URL of its module. The module is imported on first use, decoding runs on the main thread unless numWorkers is set, and the decoder is not bundled with the engine. Compressed buffer views are decoded where the parser builds buffer views, after any user bufferView hook. Fallback buffers are no longer read as the GLB binary chunk or downloaded when a decoder is available, and a compressed file without a decoder or a fallback now fails with a message naming meshoptInitialize instead of a RangeError. The meshoptimizer 1.3 decoder and encoder are vendored in examples/assets/wasm/meshopt; the tests encode their fixtures with the encoder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Build size reportThis PR changes the size of the minified bundles.
|
WebGPU has no three component 8-bit vertex format, so the engine pads byte normals to four components and getNormals returns four values per vertex there. The KHR filter test now compares the xyz of each normal whatever the component count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@slimbuck This mirrors the |
mvaligursky
left a comment
There was a problem hiding this comment.
Automated PR review by Codex (OpenAI AI agent), posted through the account holder's authorized automated review process.
Reviewed the full diff at 880262c, including extension fallback rules, buffer-view hooks, decoder initialization, worker dispatch, and error handling. Two P2 decoder-loading issues are detailed inline: relative URL resolution and recovery after a failed module download. Both were reproduced in Chrome with successful control cases.
Validation: 4,188 unit tests passing (33 pending); 4,177 real Metal WebGPU tests passing (39 pending); declaration build, consumer type tests, affected-file lint, and diff checks passed. Supplemental browser tests successfully loaded EXT v0 and KHR v1/filter fixtures through the full parser with two decoder workers on both WebGL2 and WebGPU, with exact decoded vertex positions. No additional actionable issues found in the compression or parser integration paths reviewed.
A relative decoder URL now resolves against document.baseURI, so <base href> is honored, and against the worker location in a worker, where the old code had no base at all and threw. Node still resolves against the working directory. Browsers keep a failed module import for its URL, so a retry after a failed download never sent a new request. Each retry now imports the URL with a distinct fragment, which forces a fresh request without changing the request sent to the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mvaligursky
left a comment
There was a problem hiding this comment.
Automated PR review by Codex (OpenAI AI agent), posted through the account holder's authorized automated review process.
Re-reviewed bcaacb6 and the replies to the previous review. Both previous P2 findings are addressed; no new actionable issues found in the follow-up.
Re-ran the original Chrome reproductions: relative decoder URLs now load correctly with a document <base href> and inside a real module worker. After an initial HTTP 503, the next decode successfully imports the decoder using the retry fragment, without requiring reinitialization or a caller-supplied URL change.
Validation: 4,191 unit tests passing (33 pending); 4,180 real Metal WebGPU tests passing (39 pending); declaration build, consumer type tests, changed-file lint, and diff checks passed. Full-parser browser checks with two decoder workers still load EXT v0 and KHR v1/filter fixtures correctly on both WebGL2 and WebGPU, with exact vertex positions.
|
Great, our fork gets smaller by the hour ;). I actually forgot this wasn't a part of normal playcanvas, sorry |
Adds support for glTF files compressed with
EXT_meshopt_compressionandKHR_meshopt_compression. gltfpack (-c,-cc,-cz) and glTF-Transform both produce these files. Today they fail withRangeError: Invalid typed array length.Usage
The decoder is meshoptimizer's
meshopt_decoder.mjs(about 7.7 KB gzipped, with both WASM builds embedded). It is not bundled with the engine, in the same way the Draco decoder isn't. Pass either the decoder object or the URL of its module:Decoding runs on the main thread.
numWorkershands it to the decoder's own workers for very large assets.Changes
meshoptInitialize(new public API) stores the decoder or URL. A URL is resolved against the page, as ESM scripts are, and imported on first use. If the import fails, a later load retries it.bufferView.processAsynchook, so apps that decode meshopt through that hook today keep working.EXT_andKHR_share one code path; the decoder handles the KHR v1 bitstream and theCOLORfilter.uriis no longer read as the GLB binary chunk. That aliasing is what causes the currentRangeError.uriis not downloaded when a decoder is set. Without a decoder it still loads, so optional-extension files work as before.glTF buffer view N is meshopt compressed, call meshoptInitialize to load it.examples/assets/wasm/meshopt, next to Draco and Basis. The tests use the encoder to build their fixtures.Tests
Seven new
GlbParsertests, with fixtures encoded at test time:meshoptInitializeerror (fails on main)The full suite, the type build and type tests, and the docs build pass locally. I also loaded a real glTF-Transform file (4 meshes, 11,944 triangles, quantized with
KHR_mesh_quantization) headlessly and in the examples app on WebGL2. It decoded in about 80 ms and rendered correctly.Not covered: the
numWorkerspath, because the decoder's workers need a browserWorker. There is no example yet, as it needs a compressed model with a known license.🤖 Generated with Claude Code