App crashes if screen is navigated to a view with EngineView

I’m using BabylonJS ReactNative. My code works fine but only one type of behaviour it crashes.

I’ve a Home.tsx where I’m loading a 3D modal

  const engine = useEngine();
  const [scene, setScene] = useState<Scene>();
  const [camera, setCamera] = useState<Camera>();

useEffect(() => {
    if (engine) {
      loadGLTF();
    }
  }, [engine]);

const loadGLTF = () => {
    SceneLoader.LoadAsync(GLTF_URL, undefined, engine)
      .then(loadedScene => {
        if (loadedScene) {
          setScene(loadedScene);

          // Camera & Light
          loadedScene.createDefaultCameraOrLight(true, undefined, true);
          const defaultCamera = loadedScene.activeCamera as ArcRotateCamera;
          if (defaultCamera) {
            defaultCamera.alpha += Math.PI;
            setCamera(defaultCamera);
          }
        }
      })
    }

  const renderLoading = () => {
    return (
      <View style={styles.absoluteView}>
        <ActivityIndicator size="large" />
      </View>
    );
  };

  return (
    <View style={styles.container}>
        <EngineView camera={camera} displayFrameRate={false} />
      {!scene && renderLoading()}
    </View>
  );

The above code works fine if this screen is the first to load when the app launches. If I navigate to this screen it crashes the app as soon as the scene is loaded, so I’m not sure what only in this particular case it crashes I have tried doing the below as well:

      {scene && (
        <EngineView camera={camera} displayFrameRate={false} />
      )}

But in this case, it just keep showsing the loading and nothing happens. For navigation I’m using:

    "@react-navigation/native": "6.1.17",
    "@react-navigation/stack": "6.4.0",

I’m not sure at this point as to why it would crash in the case when it’s navigated to and not when it’s loaded as the first screen. When it crash the logs are:

#00 pc 0000000000634f48  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#01 pc 00000000006229bc  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (bgfx::createTexture2D(unsigned short, unsigned short, bool, unsigned short, bgfx::TextureFormat::Enum, unsigned long, bgfx::Memory const*)+44) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#02 pc 0000000000620864  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (Babylon::Graphics::Texture::Create2D(unsigned short, unsigned short, bool, unsigned short, bgfx::TextureFormat::Enum, unsigned long)+140) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#03 pc 0000000000362ddc  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#04 pc 0000000000373ff0  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#05 pc 0000000000374108  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myapp-bkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (arcana::internal::task_payload_with_work<void, std::exception_ptr, 56ul>::do_work(arcana::internal::base_task_payload&, arcana::internal::base_task_payload*)+60) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)
#06 pc 000000000037428c  /data/app/~~FWMFDplcfvO3fHn-S4NWfg==/com.myappbkoMAO5bFCkWTXssAwjfcA==/base.apk!libBabylonNative.so (offset 0x1c17000) (BuildId: 745b36b386471bf3e4c7c2585dd63232a023634f)

One potential cause that I was able to track was that I used const isFocused = useIsFocused(); from @react-navigation/native and I had it as a dependency of a useEffect in the screen I was navigating to the EngineView screen from. Which for some reason was causing the screen to load twice and hence it was crashing.

cc @ryantrem

Sounds like you found the cause of the issue already. It is true that Babylon Native currently can only render a single view at a time. I don’t think we have good error handling in either Babylon Native or Babylon React Native to guard against this. Feel free to log an issue on this: Issues · BabylonJS/BabylonReactNative (github.com)

@ryantrem there is a weird issue that I’m facing with React-Navigation. Here is the scenario:

I have three screens:

  1. HomeScreen
  2. BabylonJS3DModelScreen
  3. ProfileScreen

In the HomeScreen I have basic react-native components like <Text>, <ScrollView> etc. Upon a successful API call result I navigate to the BabylonJS3DModelScreen where I’m loading the I’m loading the GLTF as:


  useEffect(() => {
    renderGLTF();
  }, [engine]);

const renderGLTF = async () => {
    if (engine) {
      try {
        const loadedScene = await SceneLoader.LoadAsync(
          GLTF_URL,
          undefined,
          engine,
        );

        if (!loadedScene) {
          return;
        }
        loadedScene.createDefaultCameraOrLight(true, undefined, false);
        const defaultCamera = loadedScene.activeCamera as ArcRotateCamera;

//... remaining code

From this screen I can navigate to ProfileScreen screen. And then from ProfileScreen on a button Press I’m trying to navigate back to HomeScreen. But it gets stuck when the button is pressed. If I remove the renderGLTF part of the code from the screen it all works fine.

Upon checking I was only able to stumble upon the solution to dispose the scene and/or engine, which I tried by updating the useEffect which calls the renderGLTF on mount as shown below:

  useEffect(() => {
    renderGLTF();
    return () => {
      if (engine && scene) {
          scene.dispose();
          engine.dispose();
      } else {
        console.log('Engine or Scene is null');
      }
    };
  }, [engine]);

Which doesn’t work for some reason, here is the console log that I see:

 LOG  BJS: Babylon Native (v7.12.0) launched
 LOG  Engine or Scene is null

After the Engine or Scene is null the 3D model loads and when the BabylonJS3DModelScreen unmounts i.e. I navigate to ProfileScreen, it doesn’t dispose the scene or engine.

Not sure why, but I’m stuck on this now as navigation works otherwise, so it’s a bit hard to debug as it’s my first time working with BabylonJS and I get to do it with ReactNative :smiley:

useEngine disposes the engine instance when the component that calls useEngine is unmounted. If it is not being disposed, it sounds like your component may not actually be unmounted. If you find EngineHook.js in your node_modules/@babylonjs/react-native, you can try debugging or adding a console.log to make sure that call to engine. Dispose is happening. It it is not, then it would seem that your component is not unmounting. If I recall React-Navigation can be configured to either unmount components on navigation, or keep them alive in a navigation stack, but my memory on this is fuzzy…