question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

loadAsync not working with FBX [Android]

See original GitHub issue

Hello! I’m trying to render a FBX file on Android but am running into an error. It renders an OBJ file fine on Android and the OBJ and FBX fine on iOS. I think the issue is related to #85 and #93 . Same issue as here. Is there any workaround? I’ve copied the offending error message below. Thanks.

Edit: I traced the issue to line 85 of loadModelsAsync.js, this promise always gets rejected on Android

return new Promise((res, rej) => loader.load(uri, res, onProgress, rej));

Edit 2: I’ve spent a few hours on this with no luck. GLView does not work with remote debugging which makes this especially difficult. Any suggestions appreciated.

NOTE: This works fine in IOS only having issue with Android.

Object {
  "bubbles": false,
  "cancelable": false,
  "currentTarget": XMLHttpRequest {
    "DONE": 4,
    "HEADERS_RECEIVED": 2,
    "LOADING": 3,
    "OPENED": 1,
    "UNSENT": 0,
    "_aborted": false,
    "_cachedResponse": undefined,
    "_hasError": true,
    "_headers": Object {},
    "_incrementalEvents": true,
    "_lowerCaseResponseHeaders": Object {},
    "_method": "GET",
    "_requestId": null,
    "_response": "",
    "_responseType": "arraybuffer",
    "_sent": true,
    "_subscriptions": Array [],
    "_timedOut": false,
    "_trackingName": "unknown",
    "_url": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fthreedemo-3D-expo-2992d51a-3466-48b9-bd1f-6e46e749520c/ExponentAsset-9a80489e046f0d3e164a6f0955a8df98.fbx",
    "readyState": 4,
    "responseHeaders": undefined,
    "status": 0,
    "timeout": 0,
    "upload": XMLHttpRequestEventTarget {
      Symbol(listeners): Object {},
    },
    "withCredentials": true,
    Symbol(listeners): Object {
      "abort": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "error": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "load": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "progress": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
    },
  },
  "eventPhase": 2,
  "isTrusted": false,
  "target": XMLHttpRequest {
    "DONE": 4,
    "HEADERS_RECEIVED": 2,
    "LOADING": 3,
    "OPENED": 1,
    "UNSENT": 0,
    "_aborted": false,
    "_cachedResponse": undefined,
    "_hasError": true,
    "_headers": Object {},
    "_incrementalEvents": true,
    "_lowerCaseResponseHeaders": Object {},
    "_method": "GET",
    "_requestId": null,
    "_response": "",
    "_responseType": "arraybuffer",
    "_sent": true,
    "_subscriptions": Array [],
    "_timedOut": false,
    "_trackingName": "unknown",
    "_url": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fthreedemo-3D-expo-2992d51a-3466-48b9-bd1f-6e46e749520c/ExponentAsset-9a80489e046f0d3e164a6f0955a8df98.fbx",
    "readyState": 4,
    "responseHeaders": undefined,
    "status": 0,
    "timeout": 0,
    "upload": XMLHttpRequestEventTarget {
      Symbol(listeners): Object {},
    },
    "withCredentials": true,
    Symbol(listeners): Object {
      "abort": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "error": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "load": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
      "progress": Object {
        "kind": 2,
        "listener": [Function anonymous],
        "next": null,
      },
    },
  },
  "timeStamp": 1575344131854,
  "type": "error",
  Symbol(stop_immediate_propagation_flag): false,
  Symbol(canceled_flag): false,
  Symbol(original_event): Object {
    "type": "error",
  },
}

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:15 (1 by maintainers)

github_iconTop GitHub Comments

26reactions
kyarorucommented, Aug 25, 2021

After going through so many googling & github issues or even three.js forum (from 0 exp in 3d rendering few weeks back until today), I’m finally able to load these 3 types of models: OBJ, FBX, GLTF - (.glb) in release mode for both android & ios using RN standalone app (barebone RN app with react-native-unimodules installed)

To learn three.js, I created https://github.com/kyaroru/ShibaThree & https://github.com/kyaroru/ReactShibaThree and finally trying out on mobile app using expo-three, but I face so many issues and seems to be unresolvable at first.

Not until today! Argh! So I’m going to share my findings for the newbies out there who are just like me (this might not be an official solution but it just works)

My package.json dependencies:

    "base64-arraybuffer": "^1.0.1", // this is needed at the end! (for FBX and GLTF)
    "expo-gl": "^10.4.2",
    "expo-gl-cpp": "^10.4.1",
    "expo-three": "^5.7.0",
    "react-native-unimodules": "^0.14.6",
    "three": "^0.131.2"

Using expo-three, I tried few different ways to load models:

eg. import OBJLoader or FBXLoader or GLTFLoader directly from three

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

And load using

const loaderFbx = new FBXLoader();
const loaderObj = new OBJLoader();
const loaderGlb = new GLTFLoader();

const model = Asset.fromModule(require('../models/bear/model.obj'));
await model.downloadAsync();
const loader = loaderObj;
loader.load(
      model.uri || '', // .uri / .localUri will not work in release mode on android!
      result => { scene.add(model) },
      onLoad => {},
      onError => {},
);

The above works fine on iOS (even in release mode) but not on android release mode (the APK). Android will always get this issue https://github.com/expo/expo-three/issues/182


Then I tried with loadObjAsync(), it works on Android release mode finally!

import {loadObjAsync} from 'expo-three';

const obj = await loadObjAsync({
  asset: require('../models/bear/model.obj')
});

But .png textures was not loading properly, only .mtl working if I try:

import {loadObjAsync} from 'expo-three';

const obj = await loadObjAsync({
  asset: require('../models/bear/model.obj'),
  assetMtl: require('../models/bear/material.mtl')
});

Then, I tried to look for texture issues & I found this => https://github.com/expo/expo-three/issues/185#issuecomment-732161813 (What he explained just strike me in the head… hmmm)

So I renamed all my textures image file extension to prefix with ‘x’, and it became : xpng, xjpeg,xjpg - thus it will bundle into raw folder instead of drawable folder when running assembleRelease

Take note also we have to update metro.config.js:

module.exports = {
  ...
  resolver: {
    assetExts: [
      ...,
      'xpng',
      'xjpg',
      'xjpeg',
    ],
  },
};

Then I can finally load OBJ model in android release APK using

import {loadObjAsync, loadTextureAsync} from 'expo-three';
const texture = await loadTextureAsync({
  asset: require('../models/bear/textures.xpng'),
});
const obj = await loadObjAsync({
  asset: require('../models/bear/model.obj')
});
// to map texture to model (in case some newbie like me doesn't know how ><)
obj.traverse(function(object) {
  if (object instanceof THREE.Mesh) {
    object.material.map = texture;
  }
});
scene.add(obj);

OBJ is down, how about FBX & GLTF? To know how things work, I look into loadObjAsync method inside node_modules\expo-three\build\loaders\loadModelsAsync.js

I found out it was actually calling loader.parse() method instead of loader.load()

So I attempted to do similar approach for FBX and GLTF models after referring to https://github.com/expo/expo-three/issues/151#issuecomment-593267436


First, install base64-arraybuffer using npm/yarn

yarn add base64-arraybuffer

Then. In wherever file that you wanted to load fbx or gltf model, add the following codes: (of course we can also fork expo-three and add these new methods - so the newbie don’t get stucked! )

import { loadObjAsync, loadTextureAsync } from 'expo-three';
import { resolveAsync } from 'expo-asset-utils';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { FileSystem } from 'react-native-unimodules';
import { decode } from 'base64-arraybuffer';

// this was actually copied from node_modules\expo-three\build\loaders\loadModelsAsync.js
async function loadFileAsync({ asset, funcName }) {
  if (!asset) {
    throw new Error(`ExpoTHREE.${funcName}: Cannot parse a null asset`);
  }
  return (await resolveAsync(asset)).localUri ?? null;
}

// newly added method 
export async function loadFbxAsync({ asset, onAssetRequested }) {
  const uri = await loadFileAsync({
    asset,
    funcName: 'loadFbxAsync',
  });
  if (!uri) return;
  const base64 = await FileSystem.readAsStringAsync(uri, {
    encoding: FileSystem.EncodingType.Base64,
  });
  const arrayBuffer = decode(base64);
  const loader = new FBXLoader();
  return loader.parse(arrayBuffer, onAssetRequested);
}

// newly added method
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((resolve, reject) => {
    loader.parse(
      arrayBuffer,
      onAssetRequested,
      result => {
        resolve(result);
      },
      err => {
        reject(err);
      },
    );
  });
}


And that’s all! We can now load OBJ, FBX, GLTF models proudly inside Barebone RN app!

  • For GLTF model, only .glb is working for now because using .gltf file will require loading .bin file as well but I haven’t figure out how to load .bin file yet 😢)
  • Stay tune!

For more info, can refer to my gist:

or clone this example app that I created:

Programmer life is tough… 😉

4reactions
enzopoetacommented, Jan 5, 2020

Hi ! With expo-three 5.3.0 / expo-sdk 36 and react 16.9 I am only able to successfully load obj files. I tried the following extensions without success gltf, glb and dae. I am receiving the following message en try to load them in my android device: Event { “isTrusted”: false, }

Thanks Enzo

Read more comments on GitHub >

github_iconTop Results From Across the Web

Font.loadAsync does not load fonts and because of this shows ...
*In my case, when using expo go, I noticed that it takes a long time to load with AppLoading if the clocks(of my...
Read more >
[Android] Very slow loading of some prefabs in 2017.1
1. After I upgraded to 2017.1, each load takes 3-4 seconds, and all NPC objects are loaded in 45 seconds. (!!!) I tried...
Read more >
Questions in topic: "assetbundle.loadasync"
Hi guys, I'm having a strange problem with the AssetBundleManager.LoadAssetAsync() method on some android devices. All desktop and iOS platforms work fine, with ......
Read more >
USDZ | Apple Developer Forums
I have tried this using Reality Converter beta 3 I did not edit the FBX robot character provided with ... AR not working...
Read more >
How can I load a 3D model asynchronously in three.js? - Reddit
That is not a promise, it's a good old callback. So FBXLoader uses FileLoader, so you're implicitly asynchronously loading your file using ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found