Issue with multiple views

Hi, I have a 2x2 grid of canvas’s and I want to attach a camera to each. So that we have front,back and side views of a scene at once.

So HTML wise we have

      <canvas class="scene-multi" ref="camera1" touch-action="none"></canvas>
      <canvas class="scene-multi" ref="camera2" touch-action="none"></canvas>
      <canvas class="scene-multi" ref="camera3" touch-action="none"></canvas>
      <canvas class="scene-multi" ref="camera4" touch-action="none"></canvas>

In my create scene code I have

    scene = new BABYLON.Scene(engine);
    const camera1 = new BABYLON.ArcRotateCamera("camera1", 0, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera2 = new BABYLON.ArcRotateCamera("camera2", Math.PI/2, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera3 = new BABYLON.ArcRotateCamera("camera3", Math.PI, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera4 = new BABYLON.ArcRotateCamera("camera4", Math.PI*1.5, 0.8, 20, new BABYLON.Vector3.Zero(), scene);

Then we attach with

    this.loadScene(Scene.createScene(vue.engine))
    Scene.addCamera(vue.engine,vue.$refs['camera1'],'camera1')
    Scene.addCamera(vue.engine,vue.$refs['camera2'],'camera2')
    Scene.addCamera(vue.engine,vue.$refs['camera3'],'camera3')
    Scene.addCamera(vue.engine,vue.$refs['camera4'],'camera4')

function addCamera(engine,canvas, name){

    let camera = scene.getCameraByName(name)
    console.log("Attaching Camera")
    console.log(camera)
    console.log(canvas)
    engine.registerView(canvas, camera);
}

The issue is with canvas1, it uses camera4 no matter what I do. I have tried creating camera1 last, I have tried setting it as the active camera for the scene. you can see I am registering it as a view. Cant think what to try next. I supect a bug, or a at-least I need to do something unintuitive

Hard to tell from snippet code as the official sample is working with the current v5.0 alpha.

Maybe you can have a look to the source code and see if something rings a bell: Website/build/Demos/Views at master · BabylonJS/Website · GitHub

[…] What I can see from the sample code is that the first view is registered without providing a camera, it seems it’s the first created camera that will be automatically used with this view…

Thanks, Yeah I did try that so I did try converting the snippet to:

    this.loadScene(Scene.createScene(vue.engine))
   vue.engine.registerView(vue.canvas);
    Scene.addCamera(vue.engine,vue.$refs['camera2'],'camera2')
    Scene.addCamera(vue.engine,vue.$refs['camera3'],'camera3')
    Scene.addCamera(vue.engine,vue.$refs['camera4'],'camera4')

Made no difference.

I also tried creating camera1 last incase the order was special, and also using a camera1.setActiveCamera()

I have found this playground:

https://playground.babylonjs.com/#MQ4HU3#2

I am going to try and work out what is different between its code and mine, but I cant see it yet.

This also does not work, I tried doing all the resigistering of views in the create scene rather than after incase that made a difference.

function createScene(engine,canvas_list) {
    /* eslint-disable no-unused-vars */

    scene = new BABYLON.Scene(engine);
    
    let r =0
    canvas_list.forEach((canvas)=>{
        let camera = new BABYLON.ArcRotateCamera("camera"+r, r, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
        r+=Math.PI/2
        engine.registerView(canvas,camera)
    })

Same Issue with:

function createScene(engine,canvas_list) {
    /* eslint-disable no-unused-vars */

    scene = new BABYLON.Scene(engine);
    const camera1 = new BABYLON.ArcRotateCamera("camera1", 0, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    engine.registerView(canvas_list[0])
    const camera2 = new BABYLON.ArcRotateCamera("camera2", Math.PI/2, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    engine.registerView(canvas_list[1],camera2)
    const camera3 = new BABYLON.ArcRotateCamera("camera3", Math.PI, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    engine.registerView(canvas_list[2],camera3)
    const camera4 = new BABYLON.ArcRotateCamera("camera4", Math.PI*1.5, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    engine.registerView(canvas_list[3],camera4)

Same issues with, I wondered if it was a vue issue, so used a native getElementById

    vue.canvas = document.getElementById("camera1"); // Get the canvas element
    vue.engine = new BABYLON.Engine(vue.canvas, true); // Generate the BABYLON 3D engine
    this.loadScene(Scene.createScene(vue.engine))
    vue.engine.registerView(vue.canvas);
    Scene.addCamera(vue.engine,document.getElementById("camera2"),'camera2')
    Scene.addCamera(vue.engine,document.getElementById("camera3"),'camera3')
    Scene.addCamera(vue.engine,document.getElementById("camera4"),'camera4')

I have also tried to build the cameras on the fly incase that made a difference

function addCamera(engine,canvas, name,angle){

    let camera = new BABYLON.ArcRotateCamera(name, angle, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    console.log("Attaching Camera")
    console.log(camera)
    console.log(canvas)

    engine.registerView(canvas, camera);
}

Without a repro in the Playground I think it will be difficult for us to help more.

Yeah, I am going to try, the playground above works, so I suspect its something about my setup. I wonder if Vue is causing the issue or something else.

In this playground:
https://playground.babylonjs.com/#MQ4HU3#3

I do register camera1 as a view and it does not seem to cause an issue
engine.registerView(document.getElementById(“mainCanvas”),camera1);

Indeed, so it must be something else in your code that makes it fail.

Agreed, I am trying to post more of codebase I have gone through and stripped out everything not useful:

scene.js:

import * as BABYLON from 'babylonjs';
import 'babylonjs-loaders';


let scene = null

function createScene(engine) {
    /* eslint-disable no-unused-vars */

    scene = new BABYLON.Scene(engine);
    const camera1 = new BABYLON.ArcRotateCamera("camera1", 0, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera2 = new BABYLON.ArcRotateCamera("camera2", Math.PI/2, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera3 = new BABYLON.ArcRotateCamera("camera3", Math.PI, 0.8, 20, new BABYLON.Vector3.Zero(), scene);
    const camera4 = new BABYLON.ArcRotateCamera("camera4", Math.PI*1.5, 0.8, 200, new BABYLON.Vector3.Zero(), scene);

    const hdr = new BABYLON.HDRCubeTexture("/assets/hdr/sample.hdr", scene, 512);
    hdr.rotationY = Math.PI;
    scene.environmentTexture = hdr;


    // OCEAN
    BABYLON.SceneLoader.LoadAssetContainer("/assets/3d/", "ocean_lg.glb", scene, function (container) {
        for (let mat in container.materials) {
          let material = container.materials[mat];
          if (material.name === 'Water - Low Poly') {
            // #151553
            material.albedoColor = BABYLON.Color3.FromHexString("151553");
          }
        }
        container.addAllToScene();
      })


    scene.debugLayer.show()
    //updateText()
    return scene;
/* eslint-enable no-unused-vars */
}

function addCamera(engine,canvas, name){

    let camera = scene.getCameraByName(name)
    console.log("Attaching Camera")
    console.log(camera)
    console.log(canvas)

    engine.registerView(canvas, camera);
}

export {
    createScene,
    addCamera
}

HTML

    <div class="-camera-layout">  
      <canvas class="-scene-multi" ref="camera1" id="camera1" touch-action="none"></canvas>
      <canvas class="-scene-multi" ref="camera2" id="camera2" touch-action="none"></canvas>
      <canvas class="-scene-multi" ref="camera3" id="camera3" touch-action="none"></canvas>
      <canvas class="-scene-multi" ref="camera4" id="camera4" touch-action="none"></canvas>
  </div>

  </div>

Vue:

export default {
  name: 'xxxx',
  data: function () {
    return {
      scene: null,
      engine: null,
      canvas: null,
      modals: {
        loading: false
      }
    }
  },
  mounted () {
    let vue = this
    vue.canvas = vue.$refs['camera1']; // Get the canvas element
    vue.engine = new BABYLON.Engine(vue.canvas, true); // Generate the BABYLON 3D engine
    this.loadScene(Scene.createScene(vue.engine))
    vue.engine.registerView(vue.canvas);
    Scene.addCamera(vue.engine,vue.$refs['camera2'],'camera2')
    Scene.addCamera(vue.engine,vue.$refs['camera3'],'camera3')
    Scene.addCamera(vue.engine,vue.$refs['camera4'],'camera4')
  },
  methods: {
    loadScene (scene) {
      let vue = this;
      vue.modals.loading = true;
      if (vue.engine) {
        vue.engine.stopRenderLoop()
      }
      if(vue.scene) {
        vue.scene.dispose();
      }
      vue.scene = scene
      // Register a render loop to repeatedly render the scene
      vue.engine.runRenderLoop(function () {
        vue.scene.render();
      });
      // Scene has finished loading
      vue.scene.executeWhenReady(()=>
      {
        vue.modals.loading = false;
      })
      // Watch for browser/canvas resize events
      window.addEventListener("resize", function () {
        vue.engine.resize();
      });
    }
  }
}

I would advise to make a repro in the Playground, I’m not sure a lot of people will be able to help only from snipped code. Also, you are using Vue and I don’t think a lot of users from this forum know it / is using it in relation with Babylon.

So, making a repro in the Playground would allow people to help you in case the repro does not work, or may help you narrow the problem down in case it does work.

One thing I forgot: are you using the latest version of Babylon? If not, you could give it a shot.

1 Like

Thanks Evgeni, but that seems to be the issue, I cant replicate it a playground
This https://playground.babylonjs.com/#MQ4HU3#3

Is pretty close to my code, and it works. I can see any meaningful difference between that and my code snippets from above. So I think its something about my local code but I cant tell what. I am really quite lost.

We are using 4.2 for the project, but I will try 5 now to see if works.

Same Issue under 5.0.0-alpha-16

It must be related to the Vue framework. What you should try is to start from the most basic sample with just two views, no externally loaded scene but with just a box and build up from there until it does not work anymore.