1

I have a bare react native app with expo-modules for expo-gl and react-three/fiber and react-three/drei. I'm trying to render a 3d .glb model with animations and external textures in a separate .jpg file and it is all working fine on debug but on release build the application crashes as soon as the application opens.

FATAL EXCEPTION: mqt_native_modules com.facebook.react.common.JavascriptException: Error: Could not load 36: undefined)

This is the error that i'm getting in adb logcat

github repo

Here is the code in app.js:

   import React, { Suspense, useEffect, useRef, useState } from 'react'
import {View, Text, Button} from 'react-native';
import { useFrame, Canvas, useLoader, useThree, extend } from '@react-three/fiber/native'
import { useGLTF, Environment, useAnimations, useTexture } from '@react-three/drei/native'

import iphoneModelPath from './assets/iphone.glb'
import stacy from './assets/stacy.glb';
import stacyTex from './assets/stacy.jpg';
// import {Ipgone} from './Iphone.js';
// import * as THREE from 'three';
import useControls from 'r3f-native-orbitcontrols'

function StacyModel({url, url1}, props) {
  const { nodes, animations } = useGLTF(url)
  const texture = useTexture(url1)
  const { ref, actions, names } = useAnimations(animations)

  const [hovered, setHovered] = useState(false)
  const [index, setIndex] = useState(3)

  useFrame((state, delta) =>{
    actions[names[index]].play();
  })  
  return (
    <group onClick={(event) => setIndex((index + 1) % names.length)} ref={ref} {...props} dispose={null}>
      <group rotation={[Math.PI / 2, 0, 0]} position={[0,-4,0]} scale={0.04}>
        <primitive object={nodes.mixamorigHips} />
        <skinnedMesh
          geometry={nodes.stacy.geometry}
          skeleton={nodes.stacy.skeleton}
          rotation={[-Math.PI / 2, 0, 0]}
          scale={100}>
          <meshStandardMaterial map={texture} map-flipY={false} skinning />
        </skinnedMesh>
      </group>
    </group>
  )
}
// useGLTF.preload(iphoneModelPath)

export default function App() {
  const[OrbitControls, events] = useControls();
  return (
    <View style={{flex: 1}} {...events}>
    <Canvas gl={{ physicallyCorrectLights: true }} camera={{ position: [0, 0, 16], fov: 50 }} 
    onCreated={(state) => {
      const _gl = state.gl.getContext()
      const pixelStorei = _gl.pixelStorei.bind(_gl)
      _gl.pixelStorei = function(...args) {
        const [parameter] = args
        switch(parameter) {
          case _gl.UNPACK_FLIP_Y_WEBGL:
            return pixelStorei(...args)
        }
      }
    }}
    >
      <color attach="background" args={[0x000000]} />
      <directionalLight intensity={0.8} position={[-6, 2, 2]}/>
      <Suspense>
        <Environment preset="park" />
        <StacyModel url={stacy} url1={stacyTex} />
        </Suspense>
      <OrbitControls />
    
      </Canvas>
    {/* </OrbitControlsView> */}
    </View>
    
  )
} 

You can view the build.gradle files from the repo. Any help would be appreciated. Thanks!

I tried bundling the assets, minifying-js: false in build.gradle but nothing supposes to work. If any one can provide further info on what is happening and how it can be solved. it will be highly appreciated.

sedDev
  • 33
  • 4

1 Answers1

0

I found the solution:https://github.com/pmndrs/react-three-fiber/issues/2577

import { resolveAsync } from "expo-asset-utils";
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
import { decode } from "base64-arraybuffer";
import * as FileSystem from "expo-file-system";
import { GLTFLoader } from "three-stdlib";

async function loadFileAsync({ asset, funcName }) {
  if (!asset)
    throw new Error(`ExpoTHREE.${funcName}: Cannot parse a null asset`);
  return (await resolveAsync(asset)).localUri ?? null;
}

export async function loadGLTFAsync({ asset, onAssetRequested }) {
  const uri = await loadFileAsync({
    asset,
    funcName: "loadGLTFAsync",
  });

  if (!uri) return;

  const base64 = await FileSystem.readAsStringAsync(uri, {
    encoding: FileSystem.EncodingType.Base64,
  });

  const arrayBuffer = decode(base64);
  const loader = new GLTFLoader();

  return new Promise<GLTF>((resolve, reject) => {
    loader.parse(
      arrayBuffer,
      onAssetRequested,
      (result) => {
        resolve(result);
      },
      (err) => {
        reject(err);
      }
    );
  });
}

export const loadFile = (file) => {
  return loadGLTFAsync({
    asset: file,
    onAssetRequested: (...args) => console.log(args),
  }).catch((...args) => console.error("LoadFileError" + JSON.stringify(args)));
};

use LoadFile to load your model

Ice Wang
  • 1
  • 1