Performance of react native version and web version

I have a question about the performance of react native and the web version of babylonjs,
I found this example for playground,
https://playground.babylonjs.com/#NLLNMD#8,
to check physics and test the scene,
and decided to check it out in “@babylonjs/react-native”: “^1.8.2”,
and created this example based on the example on the library website
BabylonJS/BabylonReactNativeSample,
in this example I see that the test animation and the model are working fine,
https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoxAnimated/glTF/BoxAnimated.gltf’;

but there is no lighting and ground elements,
I decided to implement the physics example in react native version,
but even before implementation, I see that when the camera is mooving in the presence of 1 cube and a surface and simple light, there is a drawdown of 9 fps,
in physics via import * as CANNON from ‘cannon’;
and launching a physics scene of 10 cubes, fps drops to 6.5 fps.
but when I run the playground example https://playground.babylonjs.com/#NLLNMD#8,
in the chrome browser on the same device I see a drawdown only at first for a couple of seconds, perhaps this is loading libraries or adapting the rendering to the device and there are no more drawdowns, although visually the square rendering is slightly different from react native, then I remove the shadows
shadowGenerator.addShadowCaster(box );
and I do even 50 cubes, I don’t see any drops in FPS on the phone, and when I rotate the camera I don’t see any drops,
In this case, maybe I’m somehow working incorrectly in the react native version? Or do I have the wrong packages installed?
What could this be related to?

import React, { FunctionComponent, useEffect, useState } from 'react';
import { View, ViewProps } from 'react-native';
import { EngineView, useEngine } from '@babylonjs/react-native';
import { MeshBuilder, StandardMaterial, PhysicsImpostor, HemisphericLight, Color3 } from '@babylonjs/core';
import * as BABYLON from '@babylonjs/core';
import * as CANNON from 'cannon';

const EngineScreen: FunctionComponent<ViewProps> = (props: ViewProps) => {
  const engine = useEngine();
  const [camera, setCamera] = useState<BABYLON.Camera>();
  const [scene, setScene] = useState<BABYLON.Scene>();

  useEffect(() => {
    if (engine) {
      const createScene = async () => {
        const newScene = new BABYLON.Scene(engine);

        const camera = new BABYLON.ArcRotateCamera('camera', Math.PI / 2, Math.PI / 3, 10, BABYLON.Vector3.Zero(), newScene);
        camera.attachControl(true);
        
        setCamera(camera);
  
        const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), newScene);
        light.intensity = 0.7;

        newScene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.CannonJSPlugin(undefined, undefined, CANNON));
  
        const ground = MeshBuilder.CreateGround('ground', { width: 20, height: 20, depth: 0.1 }, newScene);
        const groundMaterial = new BABYLON.StandardMaterial('Ground Material', newScene);
        ground.material = groundMaterial;
        ground.receiveShadows = false; // Disable receiving shadows

        const stackHeight = 10;
        const boxSize = 1;
        for (let i = 0; i < stackHeight; i++) {
          const box = MeshBuilder.CreateBox(`box${i}`, { size: boxSize }, newScene);
          box.position.y = i * boxSize; // Set the vertical position of each box
          const boxMaterial = new BABYLON.StandardMaterial(`Box Material ${i}`, newScene);
          boxMaterial.diffuseColor = new BABYLON.Color3(1, 0, 0);
          box.material = boxMaterial;

          box.physicsImpostor = new PhysicsImpostor(box, PhysicsImpostor.BoxImpostor, { mass: 1, friction: 0.5, restitution: 0.5 });
        }
  
        ground.physicsImpostor = new PhysicsImpostor(ground, PhysicsImpostor.BoxImpostor, { mass: 0, friction: 0.5, restitution: 0.5 });

        return newScene;
      };
  
      createScene().then((loadedScene) => {
        setScene(loadedScene);
      });
    }
  }, [engine]);
  

  return (
    <View style={props.style}>
      <View style={{ flex: 1 }}>
        <EngineView camera={camera} displayFrameRate={true} />
      </View>
    </View>
  );
};

export default EngineScreen;

 "dependencies": {
    "@babylonjs/core": "6.14.0",
    "@babylonjs/loaders": "6.14.0",
    "@babylonjs/react-native": "^1.8.2",
    "@babylonjs/react-native-iosandroid-0-71": "^1.8.2",
    "cannon": "^0.6.2",
    "react": "18.2.0",
    "react-native": "0.71.8",
    "react-native-permissions": "^3.0.0"
  },

Generally speaking, given a Babylon.js scene, it will typically run slower in Babylon React Native. This is because there is no JavaScript JIT (just in time compilation from JS to native), rather the JS is always interpreted. This is in part because some platforms (iOS) do not allow JS JIT outside of Safari, but also because Hermes (Meta’s JS engine made for React Native and the default JS engine in RN 0.70+) does not and will not support JIT. Meta is experimenting with AOT (ahead of time compilation from JS to native) for Hermes though, so this is probably the longer term hope for getting JS execution speed in a React Native app (including with Babylon) to be on par with the browser.

All of that said, I tested out your code in the BRN Playground app on my Pixel 4a Android device and got the following result:

  1. 10 cubes, using Hermes: 40fps
  2. 10 cubes, using JSC: 60fps
  3. 50 cubes, using JSC: 25fps

What device make and model are you using? I’m guessing some kind of Android device from your description above?

1 Like

I use Samsung SM-A730F, its nominal 43-44 fps,
I haven’t tested it on another phone yet,
I made new tests and I managed to run a local file in webview for the test, I used ammo js and a simple scene with 40 plates { height: 0.4, width: 1.5, depth: 2 });,
I see that at some point braking begins, but I have not yet been able to reduce it and make it smooth, but the fact that the camera rotates smoothly even with 40 plates is good,
I expected the worst, and also the standard frequency meter no longer works, I need to insert something into the webview.
It’s also a pity that many touchscreen packages for react native cannot be used in this way, this is also a disadvantage.