KHRONOS_EXTENSIONS and DRACO compression using React

Hello,

I want to compress a GLB file with DRACO compression in React App using KHRONOS_EXTENSIONS
The following error message appears and I don’t know how to fix that. Thanks in advance.


My code is

import "./styles.css";
import { Document, NodeIO } from "@gltf-transform/core";
import { KHRONOS_EXTENSIONS } from "@gltf-transform/extensions";

import draco3d from "draco3dgltf";

export default function App() {
  const handleCompression = () => {
    const url = "./model.glb";

    const compression = async (url) => {
      console.log(url);

      // Configure I/O.
      const io = new NodeIO()
        .registerExtensions(KHRONOS_EXTENSIONS)
        .registerDependencies({
          "draco3d.decoder": await draco3d.createDecoderModule(), // Optional.
          "draco3d.encoder": await draco3d.createEncoderModule() // Optional.
        });
      console.log("after io");
      // Read and decode.
      //const document = await io.read('compressed.glb');

      const document = await io.read(url);
      console.log(document);

      // Write to byte array (Uint8Array).
      const glb = await io.writeBinary(document);
      console.log(glb);

      // Write and encode.
      // document
      //   .createExtension(KHRDracoMeshCompression)
      //   .setRequired(true)
      //   .setEncoderOptions({
      //     method: KHRDracoMeshCompression.EncoderMethod.EDGEBREAKER,
      //     encodeSpeed: 5,
      //     decodeSpeed: 5,
      //   });
      // await io.write("model.glb", document);
    };

    compression(url);
  };

  return (
    <>
      <h1>Press button to compress</h1>

      <button type="submit" onClick={handleCompression}>
        Compress
      </button>
    </>
  );
}

https://codesandbox.io/s/condescending-shadow-bnl51v?file=/src/App.js

gltf-transform is also a commandline tool. im guessing npxy @gltf-transform/cli optimize file.glb compressing a glb in a react app, hard to imagine what you’re trying to do unless this is a server component running under a node backend like next.

if you’re using react you can also just open your shell and type: npx gltfjsx yourmodel.glb --transform

Thank you for your answer. I want to use react app to run code to compress .glb file, not manually compress it using shell

in that case i think it has to be a server component, or a rest service. it has to run under node. @donmccurdy made that tool, he knows for sure.

Thank you so much. I will try to move it to server side to see if it is working.

1 Like

@Ling @drcmda nearly all of glTF Transform’s features do work in a web browser. The main exception is texture compression, which requires Node.js. I’m keeping an eye on ways to fix that, too: WebAssembly build by RReverser · Pull Request #3522 · lovell/sharp · GitHub.

The problem you will have with this code, though, is that the draco3dgltf package is built for Node.js. I wish they’d ship a browser build to npm, but for now you’ll need to grab the Draco dependency the old fashioned way:

1 Like

Hello Don McCurdy,

Thank you so much for your answer. I will follow the instructions and let you know if it is working.

i think with modern day react this is all possible now via rsc. i have yet to try but it should just work. the old limitations should apply no more, everything that runs under node should be available.

@drcmda What is rsc? I think the problem is how they’re compiling and packaging the Draco WASM decoder, last I checked it’s still a nightmare to build WASM for multiple runtimes and publish to npm… :sweat_smile:

In any case – I wouldn’t necessarily want to process a user’s 3D files on my server if i can do so on their browser. Huge difference in performance and security implications, if you’re just giving them back the output to download.

This is how https://gltf.report/ works – it’s statically hosted. Draco, Meshopt, and anything you put in the script tab will just run in the browser.

@donmccurdy Thanks a lot.

I moved above code to server side, there is no bug now, but gave the same size glb file, it seems that Draco compression did not work. I don’t know what happened in above code.

I tried to download the extension files and use them in React, it did not work.

The Draco compression of this website https://gltf.report/ is what I want to do. But I tested https://gltf.report/ to compress my glb file, the website also gave me the same size glb file after I clicked export button.
gltfreport

Could you share the model, or a screenshot of the “metadata” tab from glTF Report?

Draco compresses only mesh geometry – if your model is large for other reasons (textures, animation, morph targets) then you’ll have to optimize it in other ways.

Sure, please see the attached model and metadata. This is the model that I converted from dxf to glb, there is no textures, animation…, just vertex. I just want to convert dxf to glb then use draco compression to reduce the size then upload to S3. Everything is going well except for draco compression :joy:. Except for gltf-transform/extensions, what else technique can do draco compression? Thank you so much.

model123.glb (2.8 MB)

Hm, something weird going on here.

I’m noticing that the file’s UVs have type “VEC3”, which isn’t valid – this should be a “VEC2” attribute. In three.js that’s geometry.attributes.uv.itemSize. It’s possible that’s the cause, but on the CLI (running a more recent glTF Transform version) this does compress anyway, from 3MB to 94.45 KB.

Except for gltf-transform/extensions, what else technique can do draco compression?

I’m not aware of another in-browser implementation of Draco compression for glTF sorry!

1 Like

Found the issue – Draco requires indexed geometry. The CLI indexes automatically when required, but the glTF Report site (and the code above) do not. I’ll push out a fix soon but in the meantime you can work around the issue like this:

import { weld } from '@gltf-transform/functions';

await document.transform(weld({tolerance: 0}));

That script can be run either in your code, or in the glTF Report ‘script’ tab, before exporting with Draco compression.


The UVs probably should still be VEC2 and not VEC3, but that seems unrelated to the compression question here.

1 Like

Thank you so much. I will work around according to your answer.

It works!!! :grinning: :grinning: :grinning:

After I added this code

import { weld } from '@gltf-transform/functions';

await document.transform(weld({tolerance: 0}));

I really appreciate all your help. It took me almost 3 days and nights, I tried lots of other methods and other techniques, but none of them works. Thank you soooooo much.

Thanks again for UVs problem. I will try to fix that.

1 Like

a server component. React Labs: What We've Been Working On – March 2023 – React these blur the lines between client and server, they’re not part of the bundle and can execute tasks that traditionally run on the client, but they can also run on the server and handle rest requests or do anything that a traditional node service did in the past. if i had to set up an application that transforms glb’s i guess i would use rsc, it would be able to run these async gltf-transform functions right in the render function.

1 Like