教程:使用 Babylon.js 在 WebXR 中构建钢琴

在现实世界中建造钢琴需要大量的时间、技能和材料。 为 VR/AR 世界构建一个呢?

本教程系列介绍如何使用 Babylon.js 创建一个混合现实 Web 应用,该应用包含虚拟世界中正常运行的 88 键立钢琴。 在已完成的应用中,可以使用混合现实控制器传送到钢琴并播放键。

本教程系列介绍如何:

  • 创建、定位和合并网格以生成钢琴键盘
  • 导入站立钢琴框架的 Babylon.js 模型
  • 向每个钢琴键添加指针交互
  • 在 WebXR 中启用传送和多点支持

先决条件

入门

让我们首先设置将包含 Babylon.js 场景的 HTML 网页。

  1. 创建名为 babylonjs-piano-tutorial 的文件夹,并在 Visual Studio Code 中打开该文件夹。

    注意

    虽然可以使用任何代码编辑器来跟进,但为了方便起见,我们将在整个本教程中使用Visual Studio Code。

  2. 在 文件夹中,创建名为 index.html 的文件,并将以下模板插入文件中:

    <html>
        <head>
            <title>Piano in BabylonJS</title>
            <script src="https://cdn.babylonjs.com/babylon.js"></script>
            <style>
                body,#renderCanvas { width: 100%; height: 100%;}
            </style>
        </head>
        <body>
            <canvas id="renderCanvas"></canvas>
            <script type="text/javascript">
                const canvas = document.getElementById("renderCanvas"); 
                const engine = new BABYLON.Engine(canvas, true); 
    
                createScene(engine).then(sceneToRender => {
                    engine.runRenderLoop(() => sceneToRender.render());
                });
    
                // Watch for browser/canvas resize events
                window.addEventListener("resize", function () {
                    engine.resize();
                });
            </script>
        </body>
    </html>
    

    如果需要有关此模板内容的更多说明,请参阅本教程的先决条件Hello World教程

  3. 如果尝试在浏览器中打开此文件,控制台会显示一个错误,指示找不到该 createScene() 函数。 让我们在下一节中实现 函数 createScene() 来解决此错误。

设置场景

  1. 与index.html相同的文件夹中,创建另一个名为 scene.js的文件。 我们将存储与此文件中设置场景和创建钢琴相关的所有 javascript 代码。

  2. 让我们将 createScene() 函数添加到 scene.js

    const createScene = async function(engine) {
        const scene = new BABYLON.Scene(engine);
        return scene;
    }
    

    请注意,我们正在创建 createScene() 一个异步函数。 请继续关注,找出原因。

  3. 接下来,我们需要一个灯和一个相机,使场景可见。 createScene()更新函数:

    const createScene = async function(engine) {
        const scene = new BABYLON.Scene(engine);
    
        const alpha =  3*Math.PI/2;
        const beta = Math.PI/50;
        const radius = 220;
        const target = new BABYLON.Vector3(0, 0, 0);
    
        const camera = new BABYLON.ArcRotateCamera("Camera", alpha, beta, radius, target, scene);
        camera.attachControl(canvas, true);
    
        const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
        light.intensity = 0.6;
    
        return scene;
    }
    

    在这里,我们创建了一个 ArcRotateCamera,它几乎完全向下指向并定位空间的原点。 我们创建的光是指向天空的 HemisphericLight ,可用于模拟环境空间。 我们还通过降低其强度来调暗光线。

    如果需要有关如何创建相机和光线的复习,请重新访问Hello World教程系列中的“准备场景”部分,然后继续下一步。

  4. 最后,由于我们针对 WebXR 平台进行开发,因此需要在场景中通过在前面return scene;插入以下行来启用 XR 体验

    const xrHelper = await scene.createDefaultXRExperienceAsync();
    

    在 javascript 中,若要对函数内的函数使用 await 关键字 (keyword) async,父函数也必须是 async,这就是我们之前将函数定义为createScene异步的原因。 在本教程系列的后面部分,我们将使用它 xrHelper 来启用和配置 Babylon.js 支持的不同 WebXR 功能。

  5. 已完成 的scene.js 应如下所示:

    const createScene = async function(engine) {
        const scene = new BABYLON.Scene(engine);
    
        const alpha =  3*Math.PI/2;
        const beta = Math.PI/50;
        const radius = 220;
        const target = new BABYLON.Vector3(0, 0, 0);
    
        const camera = new BABYLON.ArcRotateCamera("Camera", alpha, beta, radius, target, scene);
        camera.attachControl(canvas, true);
    
        const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
        light.intensity = 0.6;
    
        const xrHelper = await scene.createDefaultXRExperienceAsync();
    
        return scene;
    }
    
  6. 现在,我们已经有了一个工作 createScene() 函数,让我们 index.htmlscene.js 文件作为脚本加载, createScene() 以便在 index.html中识别该函数。 在 html 文件的 节中添加 <header> 以下代码行:

    <html>
        <head>
            <title>Piano in BabylonJS</title>
            <script src="https://cdn.babylonjs.com/babylon.js"></script>
            <script src="scene.js"></script>
            <style>
                body,#renderCanvas { width: 100%; height: 100%;}
            </style>
        </head>
        <body>
            <canvas id="renderCanvas"></canvas>
            <script type="text/javascript">
                const canvas = document.getElementById("renderCanvas");
                const engine = new BABYLON.Engine(canvas, true); 
    
                createScene(engine).then(sceneToRender => {
                    engine.runRenderLoop(() => sceneToRender.render());
                });
    
                // Watch for browser/canvas resize events
                window.addEventListener("resize", function () {
                    engine.resize();
                });
            </script>
        </body>
    </html>
    
  7. 在浏览器中打开 index.html ,你会发现前面看到的错误消息不再存在,并且页面中有一个空的 Babylon.js 场景。

后续步骤