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

Issue with Loading OBJ File using OBJLoader in React Native #3085

Open
narohan opened this issue Nov 4, 2023 · 12 comments · May be fixed by #3086
Open

Issue with Loading OBJ File using OBJLoader in React Native #3085

narohan opened this issue Nov 4, 2023 · 12 comments · May be fixed by #3086
Labels
bug Something isn't working react-native to do with react-native

Comments

@narohan
Copy link

narohan commented Nov 4, 2023

I encountered an issue while using the OBJLoader library from Three.js to load an OBJ file in a React Native application. I placed the OBJ file in the assets directory of my React Native project and I'm trying to load it using useLoader from the @react-three/fiber/native library.

I get the following error: Error: Could not load 2: text.indexOf is not a function (it is undefined) which comes from the line const obj = useLoader(OBJLoader, require('./assets/tableau.obj'));

My code :

import { Suspense } from 'react';
import { Canvas, useLoader } from '@react-three/fiber/native';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';

function Box() {

  const obj = useLoader(OBJLoader, require('./assets/tableau.obj'));

  return <primitive object={obj} scale={10} />
}

export default function App() {


  return (
    <Canvas>
      <ambientLight />
      <pointLight position={[1, 1, 1]} />
      <Suspense fallback={null}>
        <Box />
      </Suspense>
    </Canvas>

  );
}

node v21.1.0
"@react-three/fiber": "^8.15.9",
"@types/three": "^0.158.1",
"expo": "~49.0.15",
"expo-file-system": "~15.4.4",
"expo-gl": "~13.0.1",
"expo-status-bar": "~1.6.0",
"expo-three": "^7.0.0",
"react": "18.2.0",
"react-native": "0.72.6",
"three": "^0.158.0"
@CodyJasonBennett CodyJasonBennett added bug Something isn't working react-native to do with react-native labels Nov 4, 2023
@CodyJasonBennett CodyJasonBennett linked a pull request Nov 4, 2023 that will close this issue
@CodyJasonBennett
Copy link
Member

CodyJasonBennett commented Nov 4, 2023

Seems that loaders internally are not creating the correct response type. The following is what #3086 should do:

function Box() {
  const buffer = useLoader(THREE.FileLoader, require('./assets/tableau.obj'));
  const obj = useMemo(() => new OBJLoader().parse(THREE.LoaderUtils.decodeText(buffer)), [buffer])
  return <primitive object={obj} scale={10} />
}

@narohan
Copy link
Author

narohan commented Nov 5, 2023

I have another error with this code,
TypeError: OBJLoader.OBJLoader.parse is not a function (it is undefined)

More informations :
require('./assets/tableau.obj') return a number 1
const buffer = useLoader(THREE.FileLoader, require('./assets/table.obj')); return a empty array
THREE.LoaderUtils.decodeText(buffer) logically returns an empty string

@sicnarf14sf
Copy link

Hi, has this been solved already? I'm having the same issues with you. Please let me know if that has been resolved already. Thanks!

@sicnarf14sf
Copy link

Hello?

@CodyJasonBennett
Copy link
Member

CodyJasonBennett commented Dec 3, 2023

I have a workaround you can try in #3085 (comment).

function Box() {
  const buffer = useLoader(THREE.FileLoader, require('./assets/tableau.obj'));
  const obj = useMemo(() => new OBJLoader().parse(THREE.LoaderUtils.decodeText(buffer)), [buffer])
  return <primitive object={obj} scale={10} />
}

I also have a PR that would fix this issue, but it needs better integration testing since I'm already seeing fail cases with GLTFLoader.

{
  "dependencies": {
    "@react-three/fiber": "https://pkg.csb.dev/pmndrs/react-three-fiber/commit/a689a1f9/@react-three/fiber"
  }
}

@sicnarf14sf
Copy link

Thanks!

@expolli
Copy link

expolli commented Feb 4, 2024

Was able to use obj assets with this snippet:

const obj = useLoader( OBJLoader, Asset.fromModule(require("./assets/Airmax/shoe.obj")).uri )

Hope it works for you too.

@Tricho340
Copy link

Was able to use obj assets with this snippet:

const obj = useLoader( OBJLoader, Asset.fromModule(require("./assets/Airmax/shoe.obj")).uri )

Hope it works for you too.

actually worked for me.

@anurbecirovic
Copy link

I have the same issue now. But the code from @expolli didn't work :(. Any suggestions ?
import { Asset } from 'expo-asset'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'

function Island() { const obj = useLoader( OBJLoader, Asset.fromModule(require("../assets/shoe.obj")).uri ) return <primitive object={obj} scale={10} /> }

const Home = ({ route }) => { return ( <Canvas> <ambientLight /> <pointLight position={[1, 1, 1]} /> <Suspense fallback={<View />}> <Island /> </Suspense> </Canvas> ) }
Any help would be awesome ! 🙏

@CodyJasonBennett
Copy link
Member

What is the issue exactly? Do neither of these work also? I'll look into getting #3086 out, but it may not be enough on its own.

// https://github.com/pmndrs/react-three-fiber/issues/3085#issuecomment-1837583297
function A() {
  const buffer = useLoader(THREE.FileLoader, require('./assets/tableau.obj'));
  const obj = useMemo(() => new OBJLoader().parse(THREE.LoaderUtils.decodeText(buffer)), [buffer])
  return <primitive object={obj} scale={10} />
}

// Likely indicates a deeper regression since the start of the thread
// https://github.com/pmndrs/react-three-fiber/issues/3085#issuecomment-1925877969
import { Asset } from 'expo-asset'
function B() {
  const buffer = useLoader(THREE.FileLoader, Asset.fromModule(require('./assets/Airmax/shoe.obj')).uri);
  const obj = useMemo(() => new OBJLoader().parse(THREE.LoaderUtils.decodeText(buffer)), [buffer])
  return <primitive object={obj} scale={10} />
}

@anurbe
Copy link

anurbe commented Feb 17, 2024

Do you know will this work also if you want to add the material / load a material ?

function A() {
const buffer = useLoader(THREE.FileLoader, require('./assets/tableau.obj'));
const obj = useMemo(() => new OBJLoader().parse(THREE.LoaderUtils.decodeText(buffer)), [buffer])
return
}

Looks like this example works. Thank you @CodyJasonBennett

@CodyJasonBennett
Copy link
Member

That example should work until #3086 is merged which lets the normal useLoader path for OBJLoader work again. Currently, loader internals return an ArrayBuffer due to how they are polyfilled instead of also a string which OBJLoader expects. GLTFLoader and more modern loaders already work OOTB.

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

Successfully merging a pull request may close this issue.

7 participants