如何在HTML中通过多段JavaScript代码创建多Canvas实例
解决同一HTML中多个Babylon.js Canvas仅第一个渲染的问题
问题根源
你遇到的核心问题是全局变量冲突:两段相似的JS代码如果直接使用全局变量(比如engine、scene),后面的变量会覆盖前面的实例,导致第二个Canvas对应的引擎、场景被冲掉,无法正常执行渲染循环。
解决方法
方法1:用函数作用域隔离渲染逻辑
把每个Canvas的初始化和渲染逻辑封装到独立函数中,通过函数作用域避免全局变量污染:
<canvas id="test-canvas" width="400" height="300"></canvas> <canvas id="test-canvas1" width="400" height="300"></canvas> <script src="https://preview.babylonjs.com/babylon.js"></script> <script> // 第一个Canvas的场景初始化 function initFirstScene() { const canvas = document.getElementById("test-canvas"); const engine = new BABYLON.Engine(canvas, true); function createScene() { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color3.Blue(); // 构建场景内容(相机、灯光、模型) const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI/2, Math.PI/2.5, 10, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene); BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2}, scene); return scene; } const scene = createScene(); engine.runRenderLoop(() => scene.render()); window.addEventListener("resize", () => engine.resize()); } // 第二个Canvas的场景初始化 function initSecondScene() { const canvas = document.getElementById("test-canvas1"); const engine = new BABYLON.Engine(canvas, true); function createScene() { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color3.Red(); // 构建场景内容(注意命名不重复) const camera = new BABYLON.ArcRotateCamera("camera1", -Math.PI/2, Math.PI/2.5, 10, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(-1, 1, 0), scene); BABYLON.MeshBuilder.CreateBox("box", {size: 2}, scene); return scene; } const scene = createScene(); engine.runRenderLoop(() => scene.render()); window.addEventListener("resize", () => engine.resize()); } // 启动两个场景 initFirstScene(); initSecondScene(); </script>
方法2:用ES模块隔离作用域(推荐)
如果项目支持ES模块,将两个场景的代码拆分到独立文件,天然隔离作用域:
scene1.js:
export function initScene1() { const canvas = document.getElementById("test-canvas"); const engine = new BABYLON.Engine(canvas, true); const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color3.Blue(); // 场景内容构建逻辑... const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI/2, Math.PI/2.5, 10, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene); BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2}, scene); engine.runRenderLoop(() => scene.render()); window.addEventListener("resize", () => engine.resize()); }
scene2.js:
export function initScene2() { const canvas = document.getElementById("test-canvas1"); const engine = new BABYLON.Engine(canvas, true); const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color3.Red(); // 场景内容构建逻辑... const camera = new BABYLON.ArcRotateCamera("camera1", -Math.PI/2, Math.PI/2.5, 10, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(-1, 1, 0), scene); BABYLON.MeshBuilder.CreateBox("box", {size: 2}, scene); engine.runRenderLoop(() => scene.render()); window.addEventListener("resize", () => engine.resize()); }
HTML引入模块:
<canvas id="test-canvas" width="400" height="300"></canvas> <canvas id="test-canvas1" width="400" height="300"></canvas> <script src="https://preview.babylonjs.com/babylon.js"></script> <script type="module"> import { initScene1 } from './scene1.js'; import { initScene2 } from './scene2.js'; initScene1(); initScene2(); </script>
关键注意事项
- 确保两个场景中的相机、灯光、网格名称不重复,避免Babylon.js内部的命名冲突。
- 每个场景都要单独调用
engine.runRenderLoop,保证各自的渲染循环正常触发。 - 禁止在全局作用域定义
engine、scene等核心变量,必须通过函数或模块作用域隔离。
内容的提问来源于stack exchange,提问作者Simone Santarsiero
相关产品推荐
相关产品推荐

