I have been trying to run two BabylonJS instances on two separate canvases, but I’m running into various problems. I’m wondering if this scenario is supported at all or not.
Unfortunately I don’t know how to sensibly reproduce this problem on the playground which uses just a single canvas to render a scene. However, here’s an example of what I’ve tried to do:
I downloaded the code of the official GizmoManager example: https://playground.babylonjs.com/#4TBMBR#33
I cleaned it up from global variables (ugh) and wrapped inside the following function:
function runBabylonJs(canvasId) {
var canvas = document.getElementById(canvasId);
var startRenderLoop = function (engine, canvas) {
engine.runRenderLoop(function () {
if (sceneToRender && sceneToRender.activeCamera) {
sceneToRender.render();
}
});
};
var engine = null;
var scene = null;
var sceneToRender = null;
var createDefaultEngine = function () {
return new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true,
disableWebGL2Support: false,
});
};
var createScene = function () {
// Create scene
var scene = new BABYLON.Scene(engine);
var camera = new BABYLON.FreeCamera(
"camera1",
new BABYLON.Vector3(0, 0, 0),
scene,
);
var light = new BABYLON.DirectionalLight(
"light",
new BABYLON.Vector3(0, -0.5, 1.0),
scene,
);
light.position = new BABYLON.Vector3(0, 5, -2);
// Create simple meshes
var spheres = [];
for (var i = 0; i < 5; i++) {
var sphere = BABYLON.Mesh.CreateIcoSphere(
"sphere",
{ radius: 0.2, flat: true, subdivisions: 1 },
scene,
);
sphere.scaling.x = 2;
sphere.position.y = 1;
sphere.material = new BABYLON.StandardMaterial("sphere material", scene);
sphere.position.z = i + 5;
spheres.push(sphere);
}
// Initialize GizmoManager
var gizmoManager = new BABYLON.GizmoManager(scene);
gizmoManager.boundingBoxGizmoEnabled = true;
// Restrict gizmos to only spheres
gizmoManager.attachableMeshes = spheres;
// Toggle gizmos with keyboard buttons
document.onkeydown = (e) => {
if (e.key == "w") {
gizmoManager.positionGizmoEnabled = !gizmoManager.positionGizmoEnabled;
}
if (e.key == "e") {
gizmoManager.rotationGizmoEnabled = !gizmoManager.rotationGizmoEnabled;
}
if (e.key == "r") {
gizmoManager.scaleGizmoEnabled = !gizmoManager.scaleGizmoEnabled;
}
if (e.key == "q") {
gizmoManager.boundingBoxGizmoEnabled =
!gizmoManager.boundingBoxGizmoEnabled;
}
};
return scene;
};
var initFunction = async function () {
var asyncEngineCreation = async function () {
try {
return createDefaultEngine();
} catch (e) {
console.log(
"the available createEngine function failed. Creating the default engine instead",
);
return createDefaultEngine();
}
};
engine = await asyncEngineCreation();
if (!engine) throw "engine should not be null.";
startRenderLoop(engine, canvas);
scene = createScene();
};
initFunction().then(() => {
sceneToRender = scene;
});
}
Then inside my page I have the two canvas elements:
<canvas id="renderCanvas1" style="width: 400px; height: 400px"></canvas>
<canvas id="renderCanvas2" style="width: 400px; height: 400px"></canvas>
And then I call the runBabylonJs()
function twice to render on both canvases:
runBabylonJs("renderCanvas1");
runBabylonJs("renderCanvas2");
The result of running this is that I do get two scenes, but the gizmomanagers are not independent. The gizmo gets rendered on one canvas, but the movement happens on another canvas:
I also tried adding a 10 second sleep between the two runBabylonJs()
calls to ensure I don’t run into this bug. Didn’t help.
FYI, I’m able to achieve this functionality just fine with THREE.js, so it doesn’t look like some inherent WebGL limitation.