Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Importing .glb file with useGLTF on ReactNative Expo fails #2700

Closed
domagude opened this issue Jan 9, 2023 · 17 comments
Closed

Importing .glb file with useGLTF on ReactNative Expo fails #2700

domagude opened this issue Jan 9, 2023 · 17 comments
Labels
bug Something isn't working needs reproduction

Comments

@domagude
Copy link

domagude commented Jan 9, 2023

It seems that I'm doing everything according to the documentation https://docs.pmnd.rs/react-three-fiber/tutorials/v8-migration-guide for React Native Expo.

image

I have the latest dependencies, just installed everything freshly and overall @react-three/fiber/native works great and renders my 3D stuff. It just fails to load .glb file. What am I doing wrong? Could it be something related to the way expo imports the .glb file? I have also configured my metro.config.js according to the documentation

metro.config.js

const { getDefaultConfig } = require('expo/metro-config');

const config = getDefaultConfig(__dirname);

config.resolver.assetExts.push('glb', 'gltf', 'png', 'jpg', 'svg');

config.resolver.sourceExts.push('js', 'jsx', 'json', 'ts', 'tsx', 'cjs');

module.exports = config;

My dependencies

{
  "name": "greatApp",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\""
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "dependencies": {
    "@react-three/drei": "^9.51.20",
    "@react-three/fiber": "^8.10.0",
    "expo": "~47.0.12",
    "expo-gl": "~12.0.1",
    "expo-status-bar": "~1.4.2",
    "expo-three": "^7.0.0",
    "immer": "^9.0.17",
    "r3f-native-orbitcontrols": "^1.0.5",
    "react": "18.1.0",
    "react-native": "0.70.5",
    "three": "^0.148.0",
    "three-noise": "^1.1.2",
    "three-stdlib": "^2.21.5",
    "typescript": "^4.6.3",
    "zustand": "^4.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@react-native-community/eslint-config": "^3.2.0",
    "@tsconfig/react-native": "^2.0.3",
    "@types/react-native": "^0.70.8",
    "@types/three": "^0.148.0",
    "@typescript-eslint/eslint-plugin": "^5.48.0",
    "@typescript-eslint/parser": "^5.48.0",
    "eslint": "^8.31.0",
    "eslint-config-prettier": "^8.6.0",
    "eslint-plugin-prettier": "^4.2.1",
    "jest": "^29.3.1",
    "prettier": "^2.8.2"
  },
  "jest": {
    "preset": "react-native",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  },
  "private": true
}

Here's a code example that fails

...
import { useGLTF } from '@react-three/drei/native'

const MyModel = () => {
   // Calling this line fails and gives me an error
   const { nodes } = useGLTF(require('./models/fancyModel.glb'))

   return (
      ...
   )
}

I do have a .glb file in the ./models/fancyModel.glb which works fine on the web app.

The error I'm getting
image

Thanks

@CodyJasonBennett
Copy link
Member

GLTFLoader may not decode textures correctly as reported in #1972, but the stack trace I'm seeing here looks to be coming from a non-three element mounted in your app, or coming from the GLTF.

@CodyJasonBennett CodyJasonBennett added bug Something isn't working needs reproduction labels Jan 21, 2023
@thiagobrez
Copy link

Hey @CodyJasonBennett , I've got a minimal reproduction here: https://github.com/thiagobrez/expo-useGLTF

Basic r3f scene works, but when trying to load a local model (either local or remote URL), useGLTF fails with

Possible Unhandled Promise Rejection (id: 0):
Error: Unable to download file: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL"

Checklist:

  • Importing from @react-three/fiber/native, @react-three/drei/native
  • Configured metro according to docs
  • Tried loading model locally using Expo's Asset.fromModule
  • Tried loading model from remote pmndrs' market URL
  • Explicitly passing a meshStandardMaterial to prevent the material bug in expo-gl

Do you have any insights on this? Thank you in advance!

I'd be happy to contribute to the docs if there is any good practice that I'm missing. If you think this issue might be better suited for the drei repo, or even Expo, please let me know!

@CarsoteCosmin
Copy link

I get the same error...

@samevision
Copy link

samevision commented Mar 21, 2023

I have only problems on android to load glbs. With exactly this code from the example (https://docs.pmnd.rs/react-three-fiber/tutorials/v8-migration-guide#react-native-support) I receive the error:

Could not load 2: undefined

I receive the same error if I use the local file path instead of the id. Is there a workaround. It would be very important to solve this.

The glb is just a cube - no textures, no animation, ...

@hcklawrence
Copy link

Having the same issue. Please let me know if there is any solution. Thank you so much!

@Lewitje
Copy link

Lewitje commented May 7, 2023

Same issue here:
Error: Unable to download file: Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSErrorFailingURLStringKey=./models/collar.gltf, NSErrorFailingURLKey=./models/collar.gltf, _NSURLErrorRelatedURLSessionTaskErrorKey=( "BackgroundDownloadTask <A56C7466-F277-444C-A403-F9C86885C20A>.<5>"

@beeboopx
Copy link

I found this issue resolves if the GLTF path is specified at the file-level instead of the component-level. For example in the migration guide (https://docs.pmnd.rs/react-three-fiber/tutorials/v8-migration-guide#react-native-support) it specifies the modelPath var which is consumed in the component.

import modelPath from './assets/model.glb'

function Model(props) {
  const { scene } = useGLTF(modelPath)
  return <primitive {...props} object={scene} />
}

@ChanderShekharKestone
Copy link

Please provide demo repo of working example.

@lilraja-x
Copy link

Any solution found??
I'm also trying to use useGLTF but its not working

code::

import React, { Suspense } from 'react';
import { useFrame, Canvas } from '@react-three/fiber/native';
import { useGLTF } from '@react-three/drei/native';
import Bedmodelpath from '../../../assets/Airmax/bed1.glb';

function Model({ url, ...rest }) {
const { scene } = useGLTF(url)
useFrame(() => (scene.rotation.y += 0.01))
return <primitive {...rest} object={scene} />
}

export default function Suggestions() {
return (
<Canvas gl={{ physicallyCorrectLights: true }} camera={{ position: [-6, 0, 16], fov: 36 }}>


<directionalLight intensity={1.1} position={[0.5, 0, 0.866]} />
<directionalLight intensity={0.8} position={[-6, 2, 2]} />




)
}

@hcklawrence
Copy link

Any solution found?? I'm also trying to use useGLTF but its not working

code::

import React, { Suspense } from 'react'; import { useFrame, Canvas } from '@react-three/fiber/native'; import { useGLTF } from '@react-three/drei/native'; import Bedmodelpath from '../../../assets/Airmax/bed1.glb';

function Model({ url, ...rest }) { const { scene } = useGLTF(url) useFrame(() => (scene.rotation.y += 0.01)) return <primitive {...rest} object={scene} /> }

export default function Suggestions() { return ( <Canvas gl={{ physicallyCorrectLights: true }} camera={{ position: [-6, 0, 16], fov: 36 }}> <directionalLight intensity={1.1} position={[0.5, 0, 0.866]} /> <directionalLight intensity={0.8} position={[-6, 2, 2]} /> ) }

I solved this months ago, i am not sure if a remember right, but the reason should be something like the useGLTF(url) cannot locate the glb/glft file path correctly. What I do is that to import the model first, and then pass to the useGLTF() function directly instead of calling Model() to get th url.

import React, { useRef } from "react";
import { useGLTF, useFBX, useAnimations } from "@react-three/drei/native";
import xbot from "./assets/models/Xbot.glb"; // the model path in your directory

export default function CapmiAvatar(props) {
    const group = useRef();

    const { nodes, materials } = useGLTF(xbot);
    return (
        <group ref={group} {...props} dispose={null}>
            <group name='Scene'>
                <group name='Armature' scale={0.01}>
                    <primitive object={nodes.mixamorigHips} />
                    <skinnedMesh
                        name='Beta_Joints'
                        geometry={nodes.Beta_Joints.geometry}
                        material={materials.Beta_Joints_MAT}
                        skeleton={nodes.Beta_Joints.skeleton}
                    />
                    <skinnedMesh
                        name='Beta_Surface'
                        geometry={nodes.Beta_Surface.geometry}
                        material={materials["asdf1:Beta_HighLimbsGeoSG2"]}
                        skeleton={nodes.Beta_Surface.skeleton}
                    />
                </group>
            </group>
        </group>
    );

@pedrofalco
Copy link

Any solution found?? I'm also trying to use useGLTF but its not working
code::
import React, { Suspense } from 'react'; import { useFrame, Canvas } from '@react-three/fiber/native'; import { useGLTF } from '@react-three/drei/native'; import Bedmodelpath from '../../../assets/Airmax/bed1.glb';
function Model({ url, ...rest }) { const { scene } = useGLTF(url) useFrame(() => (scene.rotation.y += 0.01)) return <primitive {...rest} object={scene} /> }
export default function Suggestions() { return ( <Canvas gl={{ physicallyCorrectLights: true }} camera={{ position: [-6, 0, 16], fov: 36 }}> <directionalLight intensity={1.1} position={[0.5, 0, 0.866]} /> <directionalLight intensity={0.8} position={[-6, 2, 2]} /> ) }

I solved this months ago, i am not sure if a remember right, but the reason should be something like the useGLTF(url) cannot locate the glb/glft file path correctly. What I do is that to import the model first, and then pass to the useGLTF() function directly instead of calling Model() to get th url.

import React, { useRef } from "react";
import { useGLTF, useFBX, useAnimations } from "@react-three/drei/native";
import xbot from "./assets/models/Xbot.glb"; // the model path in your directory

export default function CapmiAvatar(props) {
    const group = useRef();

    const { nodes, materials } = useGLTF(xbot);
    return (
        <group ref={group} {...props} dispose={null}>
            <group name='Scene'>
                <group name='Armature' scale={0.01}>
                    <primitive object={nodes.mixamorigHips} />
                    <skinnedMesh
                        name='Beta_Joints'
                        geometry={nodes.Beta_Joints.geometry}
                        material={materials.Beta_Joints_MAT}
                        skeleton={nodes.Beta_Joints.skeleton}
                    />
                    <skinnedMesh
                        name='Beta_Surface'
                        geometry={nodes.Beta_Surface.geometry}
                        material={materials["asdf1:Beta_HighLimbsGeoSG2"]}
                        skeleton={nodes.Beta_Surface.skeleton}
                    />
                </group>
            </group>
        </group>
    );

What versions are you using? I'm dealing with the same problem and this solution doesn't work for me :/

@CodyJasonBennett
Copy link
Member

#2700 (comment) is correct in that you need to let Metro transform the asset into a valid module reference. The only other valid URLs at runtime would be an absolute, remote path via https.

import modelPath from './path/to/model.glb'

function Model() {
  const gltf = useGLTF(modelPath)
}

Note WRT #2700 (comment), you'll want to load and apply textures separately (via https://github.com/pmndrs/gltfjsx) until react-native implements necessary low-level APIs for unpacking images from binary files. Loaders should otherwise work without issue individually, but be prepared to patch react-native in this way to guarantee this behavior.

@AndrewRayCode
Copy link

It's probably worth noting the react-three-fiber react-native quickstart still shows importing a model file directly https://docs.pmnd.rs/react-three-fiber/getting-started/installation#react-native

@CodyJasonBennett
Copy link
Member

That is intentional. I updated it today from the cube example since that workflow is now supported as we implement missing APIs in react-native.

@AndrewRayCode
Copy link

I updated it today from the cube example

I don't follow this, what do you mean? Do you mean we no longer need to use gltfjsx?

Either way, I don't think react-three-fiber works with React Native at all right now, regardless of gltf #3064

@CodyJasonBennett
Copy link
Member

CodyJasonBennett commented Oct 24, 2023

Yes embedded textures load since R3F polyfills previously missing APIs needed to unpack textures from GLB, and I continued there WRT emulator not pushing frames. Unfortunately Apple has been breaking their OpenGL code path under XCode so the only option is to test on device until we move to Metal/WebGPU.

@babucarr32
Copy link

I am facing this issue in 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs reproduction
Projects
None yet
Development

No branches or pull requests