You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:40:29