Unable to load meshopt compressed .glb file in react native

I am unable to load the meshopt compressed file in react native can anyone help me in this. I have tried “MeshoptDecoder” from both “three-stdlib” and “three/examples/jsm/libs/meshopt_decoder.module.js” package but nothing working out, the error says: Error: THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files
Here is my code:

import React, { useRef, useState, useCallback } from "react";
import { GLTFLoader } from "three-stdlib";
import { DRACOLoader } from "three-stdlib";
import { MeshoptDecoder } from "three-stdlib";
import { Graphics_Key } from "@/constants/constants";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { glb_Loading_Time_Metrics } from "@/services/apiServices";

const useMeshLoader = () => {
  const [meshes, setMeshes] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [isAssetReplacing, setIsAssetReplacing] = useState(false);
  const loader = useRef(new GLTFLoader()).current;
  const dracoLoader = useRef(new DRACOLoader()).current;

  dracoLoader.setDecoderPath(
    "https://www.gstatic.com/draco/versioned/decoders/1.5.7/"
  );
  loader.setDRACOLoader(dracoLoader);

  loader.setMeshoptDecoder(MeshoptDecoder);

  const prevAssetObject = useRef({});
  const loadQueue = useRef(Promise.resolve());

  const LoadMeshes = useCallback(
    (assetsObject) => {
      const loadEverything = async () => {
        if (assetsObject) {
          const promiseArray = [];
          const keyToLoad = [];
          const avatarMetrics = {} as any;
          for (let key of Object.keys(assetsObject)) {
            if (
              assetsObject[key] &&
              (!meshes ||
                prevAssetObject.current?.[key] !== assetsObject?.[key])
            ) {
              if (key === "avatar") {
                const startTime = performance.now();
                keyToLoad.push(key);
                const { lowPolyGlbUrl, highPolyGlbUrl, name, bodyType } =
                  assetsObject[key];
                const isHighGraphics = await AsyncStorage.getItem(Graphics_Key);
                promiseArray.push(
                  new Promise(async (resolve, reject) => {
                    console.log(loader, "loader");
                    loader
                      .loadAsync(
                        isHighGraphics ? highPolyGlbUrl : lowPolyGlbUrl
                      )
                      .then((result) => {
                        resolve(result);
                        const endTime = performance.now();
                        avatarMetrics.time = (endTime - startTime) / 1000;
                        avatarMetrics.model_Name = name;
                        avatarMetrics.bodyType = bodyType;
                        avatarMetrics.deviceType = "Mobile-App";
                        avatarMetrics.graphics = isHighGraphics
                          ? "High"
                          : "Low";
                        glb_Loading_Time_Metrics(avatarMetrics);
                      })
                      .catch((error) => {
                        console.error(error);
                      });
                  })
                );
                setIsLoading(true);
                continue;
              }
              setIsAssetReplacing(true);
              keyToLoad.push(key); // Only the keys which are going to be loaded
              const { glbUrl } = assetsObject[key];
              promiseArray.push(loader.loadAsync(glbUrl));
            }
          }

          prevAssetObject.current = { ...assetsObject }; // Copy to prevent mutation issues

          const results = await Promise.all(promiseArray);

          // Accumulate results and update state once to avoid multiple renders
          const newMeshes = {};
          for (let i = 0; i < results.length; i++) {
            newMeshes[keyToLoad[i]] = results[i];
          }

          setMeshes((prev) => ({
            ...prev,
            ...newMeshes,
          }));

          setIsAssetReplacing(false);
          setIsLoading(false);
        }
      };

      loadQueue.current = loadQueue.current
        .then(loadEverything)
        .catch(console.error);
    },
    [meshes]
  );

  return {
    LoadMeshes,
    meshes,
    isLoading,
    isAssetReplacing,
  };
};

export default useMeshLoader;
1 Like

Have the exact same problem. Did you find a fix for it?