Viewport ignored for mutiple cameras in React Native

Hi there!

After some detours, I’m back to adding multiple 3D views to the React Native app I’m working on.
A few months ago I’ve posted a question about having multiple views in React Native which is not supported at the moment.

As a workaround I was provided the “Split Screen” example which renders multiple cameras with different viewports. I’ve tried to replicate that in React Native but I’m running into an issue.

The view renders all the cameras but ignores their respective viewport, instead it seems to be using the view port of the last camera and apply to all cameras, no matter which camera it’s being given to render.

I’m using React Native 0.69 and I’m running on Android (both simulator and physical device).

Is this a bug that can be fixed or may be a limitation of the current implementation? Thanks in advance for your help!

Notes:

  • I tried using scissors but got this error Error: Exception in HostFunction: undefined is not an object (evaluating 'gl.enable')
  • I also tried adding a second engine view node but it renders properly only if being given the same camera as the first one.

Below is the app code (the same createScene() function works in playground):

import React, {useState, useEffect} from 'react';
import {Text, View} from 'react-native';
import {EngineView, useEngine} from '@babylonjs/react-native';
import * as BABYLON from '@babylonjs/core';

const createScene = function (engine: BABYLON.Engine) {
  // This creates a basic Babylon Scene object (non-mesh)
  const scene = new BABYLON.Scene(engine);

  // Create cameras
  const numX = 2;
  const numY = 3;
  for (let i = 0; i < numX; ++i) {
    for (let j = 0; j < numY; ++j) {
      const x = 2 * i - numX + 1;
      const y = 2 * j - numY + 1;

      // This creates and positions a free camera (non-mesh)
      const camera = new BABYLON.FreeCamera(
        `camera-${i}-${j}`,
        new BABYLON.Vector3(x, y + 10, -10),
        scene,
      );
      camera.viewport = new BABYLON.Viewport(
        i / numX,
        j / numY,
        1 / numX,
        1 / numY,
      );
      camera.setTarget(new BABYLON.Vector3(x, y, 0));
      scene.activeCameras!.push(camera);
    }
  }

  // This creates a light, aiming 0,1,0 - to the sky (non-mesh)
  const light = new BABYLON.HemisphericLight(
    'light',
    new BABYLON.Vector3(0, 1, 0),
    scene,
  );

  // Default intensity is 1. Let's dim the light a small amount
  light.intensity = 0.7;

  // Our built-in 'sphere' shape.
  const sphere = BABYLON.MeshBuilder.CreateSphere(
    'sphere',
    {diameter: 2, segments: 32},
    scene,
  );

  // Move the sphere upward 1/2 its height
  sphere.position.y = 1;

  // Our built-in 'ground' shape.
  BABYLON.MeshBuilder.CreateGround('ground', {width: 6, height: 6}, scene);

  return scene;
};

const App = () => {
  const engine = useEngine();
  const [scene, setScene] = useState<BABYLON.Scene>();

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

  return (
    <View style={{flex: 1}}>
      <Text>Hello Babylon</Text>
      <EngineView camera={scene?.activeCamera!} displayFrameRate={true} />
    </View>
  );
};

export default App;

cc @BabylonNative

Hey @obasille , how are you doing?

I will take a look at this. From the error Error: Exception in HostFunction: undefined is not an object (evaluating 'gl.enable' it seems like this functionality is not currently implemented in NativeEngine. I will double check why that is.

2 Likes

Hi @srzerbetto, doing well, thanks for asking!
And thanks for looking at this :slight_smile:
I don’t think I need the scissor functionality anyways, it was more of a side note while I tried to get around the issue with the viewport.

Yes, this is a bug on how Babylon Native handles viewport assignment. The logic that is currently there is wrong since viewport is updated instantaneously but rendering commands go through a command queue. The result is that all viewport updates happen before any rendering is done and the result is that only the “last” camera viewport gets applied.

This is not that simple to fix though, It might require us to change the viewport update logic and possibly break other stuff.

I’ve opened an issue to track this:
Changing Viewport multiple times during rendering does not work properly · Issue #1182 · BabylonJS/BabylonNative (github.com)

3 Likes

The work on this is been tracked on this PR:
Fixed issue when setting ViewPort multiple times per frame. by SergioRZMasson · Pull Request #1183 · BabylonJS/BabylonNative (github.com)

However, it way take some time for this to get approved due to holly days, I would like @bghgary to review it since it might have impact on XR and other scenarios I might be missing.

3 Likes

Thank you!

This fix has been release with Babylon React Native version 1.4.4 and Babylon.js version 5.43.0 or latter.

2 Likes

Thanks @srzerbetto, I’ve just tried and it works like a charm :+1:

1 Like