Partager via


Tutoriel : Créer un modèle de piano 3D

Dans le tutoriel précédent de la série, vous avez configuré une page web contenant une scène Babylon.js avec une caméra et une lumière. Dans ce tutoriel, vous allez créer et ajouter un modèle de piano à la scène.

Standup Piano Mesh

Dans ce tutoriel, vous apprenez à effectuer les opérations suivantes :

  • Créer, positionner et fusionner des maillages
  • Créer un clavier de piano à partir de maillages de boîtes
  • Importer un modèle 3D d’un cadre de piano

Avant de commencer

Assurez-vous que vous avez terminé le tutoriel précédent de la série et que vous êtes prêt à continuer à ajouter au code.

index.html

<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>

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;
}

Prise en main

Commençons par créer un clavier de piano simple avec cette structure :

Description du registre du piano

Dans cette image, il y a sept clés blanches et cinq touches noires, chacune étiquetée avec le nom de la note. Un clavier de piano complet de 88 touches contient sept répétitions complètes de cette sélection de touches (également appelée registre) et quatre touches supplémentaires. Chaque registre a le double de la fréquence de son registre précédent. Par exemple, la fréquence de tangage de C5 (ce qui signifie que la note C dans le cinquième registre) est le double de celle de C4, la fréquence de tangage de D5 est le double de celle de D4, et ainsi de suite.

Visuellement, chaque registre ressemble exactement à un autre, donc nous pouvons commencer par examiner comment créer un clavier de piano simple avec cette sélection de touches. Plus tard, nous trouverons un moyen d’étendre l’étendue à un clavier de piano complet de 88 touches.

Créer un clavier de piano simple

Remarque

Bien qu’il soit possible de trouver des modèles 3D prédéfinis de claviers de piano à partir de sources en ligne et de les importer dans notre page web, nous allons créer le clavier à partir de zéro dans ce tutoriel pour permettre une personnalisation maximale et pour montrer comment les modèles 3D peuvent être créés via Babylon.js.

  1. Avant de commencer à créer des maillages pour la construction du clavier, notez que chaque touche noire n’est pas parfaitement alignée au milieu des deux touches blanches qui l’entourent, et que toutes les touches n’ont pas la même largeur. Cela signifie que nous devons créer et positionner le maillage pour chaque clé individuellement.

    Alignement des touches noires

  2. Pour les touches blanches, nous pouvons faire une observation que chaque clé blanche est composée de deux parties : (1) la partie inférieure sous la ou les touches noires et (2) la partie supérieure en regard de la ou des touches noires. Les deux parties ont des dimensions différentes, mais sont empilées ensemble pour créer une clé blanche complète.

    Forme de clé blanche

  3. Voici le code permettant de créer une clé blanche unique pour la note C (ne vous inquiétez pas encore de l’ajouter à scene.js ) :

    const whiteKeyBottom = BABYLON.MeshBuilder.CreateBox("whiteKeyBottom", {width: 2.3, height: 1.5, depth: 4.5}, scene);
    const whiteKeyTop = BABYLON.MeshBuilder.CreateBox("whiteKeyTop", {width: 1.4, height: 1.5, depth: 5}, scene);
    whiteKeyTop.position.z += 4.75;
    whiteKeyTop.position.x -= 0.45;
    
    // Parameters of BABYLON.Mesh.MergeMeshes:
    // (arrayOfMeshes, disposeSource, allow32BitsIndices, meshSubclass, subdivideWithSubMeshes, multiMultiMaterials)
    const whiteKeyV1 = BABYLON.Mesh.MergeMeshes([whiteKeyBottom, whiteKeyTop], true, false, null, false, false);
    whiteKeyV1.material = whiteMat;
    whiteKeyV1.name = "C4";
    

    Ici, nous avons créé deux maillages Box , un pour la partie inférieure et l’autre pour la partie supérieure de la clé blanche. Nous modifions ensuite la position de la partie supérieure pour l’empiler sur la partie inférieure et la déplacer vers la gauche pour laisser de l’espace pour la clé noire voisine (C#).

    Enfin, ces deux parties ont été fusionnées à l’aide de la fonction MergeMeshes pour devenir une clé blanche complète. Il s’agit du maillage résultant que ce code produirait :

    Touche blanche C

  4. La création d’une clé noire est plus simple. Étant donné que toutes les touches noires sont de la forme d’une boîte, nous pouvons créer une clé noire simplement en créant un maillage de boîte avec un StandardMaterial de couleur noire.

    Remarque

    Étant donné que la couleur de maillage par défaut est un gris clair qui ressemble au blanc, ce tutoriel n’inclut pas d’étapes pour ajouter un matériau de couleur blanche aux touches blanches. Toutefois, n’hésitez pas à ajouter le matériau vous-même si vous souhaitez une vraie couleur blanche sur les touches blanches.

    Voici le code permettant de créer la clé noire C# (ne vous inquiétez pas non plus de l’ajouter à scene.js ) :

    const blackMat = new BABYLON.StandardMaterial("black");
    blackMat.diffuseColor = new BABYLON.Color3(0, 0, 0);
    
    const blackKey = BABYLON.MeshBuilder.CreateBox("C#4", {width: 1.4, height: 2, depth: 5}, scene);
    blackKey.position.z += 4.75;
    blackKey.position.y += 0.25;
    blackKey.position.x += 0.95;
    blackKey.material = blackMat;
    

    La clé noire produite par ce code (avec la clé blanche précédente) se présente comme suit :

    Black Key C#

  5. Comme vous pouvez le voir, la création de chaque clé peut entraîner un grand nombre de codes similaires, car nous devons spécifier chacune de leurs dimensions et position. Essayons de rendre le processus de création plus efficace dans la section suivante.

Créer efficacement un clavier de piano simple

  1. Bien que chaque clé blanche ait une forme légèrement différente les unes des autres, toutes peuvent être créées en combinant une partie supérieure et une partie inférieure. Implémentons une fonction générique pour créer et positionner n’importe quelle clé blanche.

    Ajoutez la fonction ci-dessous pour scene.js, en dehors de la createScene() fonction :

    const buildKey = function (scene, parent, props) {
        if (props.type === "white") {
            /*
            Props for building a white key should contain: 
            note, topWidth, bottomWidth, topPositionX, wholePositionX, register, referencePositionX
    
            As an example, the props for building the middle C white key would be
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4, register: 4, referencePositionX: 0}
            */
    
            // Create bottom part
            const bottom = BABYLON.MeshBuilder.CreateBox("whiteKeyBottom", {width: props.bottomWidth, height: 1.5, depth: 4.5}, scene);
    
            // Create top part
            const top = BABYLON.MeshBuilder.CreateBox("whiteKeyTop", {width: props.topWidth, height: 1.5, depth: 5}, scene);
            top.position.z =  4.75;
            top.position.x += props.topPositionX;
    
            // Merge bottom and top parts
            // Parameters of BABYLON.Mesh.MergeMeshes: (arrayOfMeshes, disposeSource, allow32BitsIndices, meshSubclass, subdivideWithSubMeshes, multiMultiMaterials)
            const key = BABYLON.Mesh.MergeMeshes([bottom, top], true, false, null, false, false);
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.name = props.note + props.register;
            key.parent = parent;
    
            return key;
        }
    }
    

    Dans ce bloc de code, nous avons créé une fonction nommée buildKey(), qui génère et retourne une clé blanche si props.type a la valeur "white". En identifiant le type de la clé dans le paramètre props, nous pouvons créer des clés noires et des clés blanches dans la même fonction en créant une branche à l’aide d’une instruction if.

    Les paramètres de buildKey() sont les suivants :

    • scene : scène dans laquelle se trouve la clé
    • parent : parent du maillage (cela nous permet de regrouper toutes les clés en un seul parent)
    • props : propriétés de la clé qui sera générée

    Le props pour une clé blanche contient les éléments suivants :

    • type : « blanc »
    • name : nom de la note que représente la clé
    • topWidth : largeur de la partie supérieure
    • bottomWidth : largeur de la partie inférieure
    • topPositionX : position x de la partie supérieure par rapport à la partie inférieure
    • wholePositionX : position x de l’ensemble de la clé par rapport au point de terminaison du registre (le bord droit de la clé B).
    • register : inscrire à laquelle appartient la clé (un nombre compris entre 0 et 8)
    • referencePositionX : coordonnée x du point de terminaison du registre (utilisé comme point de référence).

    En séparant wholePositionX et referencePositionX, nous sommes en mesure d’initialiser les props paramètres nécessaires pour créer un type spécifique de clé (par exemple, C) dans n’importe quel registre, puis d’ajouter register et referencePositionX à lors de la props création de cette clé dans un registre spécifique (par exemple, C4, C5).

  2. De même, nous pouvons également écrire une fonction générique pour créer une clé noire. Nous allons développer la buildKey() fonction pour inclure cette logique :

    const buildKey = function (scene, parent, props) {
        if (props.type === "white") {
            /*
            Props for building a white key should contain: 
            note, topWidth, bottomWidth, topPositionX, wholePositionX, register, referencePositionX
    
            As an example, the props for building the middle C white key would be
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4, register: 4, referencePositionX: 0}
            */
    
            // Create bottom part
            const bottom = BABYLON.MeshBuilder.CreateBox("whiteKeyBottom", {width: props.bottomWidth, height: 1.5, depth: 4.5}, scene);
    
            // Create top part
            const top = BABYLON.MeshBuilder.CreateBox("whiteKeyTop", {width: props.topWidth, height: 1.5, depth: 5}, scene);
            top.position.z =  4.75;
            top.position.x += props.topPositionX;
    
            // Merge bottom and top parts
            // Parameters of BABYLON.Mesh.MergeMeshes: (arrayOfMeshes, disposeSource, allow32BitsIndices, meshSubclass, subdivideWithSubMeshes, multiMultiMaterials)
            const key = BABYLON.Mesh.MergeMeshes([bottom, top], true, false, null, false, false);
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.name = props.note + props.register;
            key.parent = parent;
    
            return key;
        }
        else if (props.type === "black") {
            /*
            Props for building a black key should contain: 
            note, wholePositionX, register, referencePositionX
    
            As an example, the props for building the C#4 black key would be
            {type: "black", note: "C#", wholePositionX: -13.45, register: 4, referencePositionX: 0}
            */
    
            // Create black color material
            const blackMat = new BABYLON.StandardMaterial("black");
            blackMat.diffuseColor = new BABYLON.Color3(0, 0, 0);
    
            // Create black key
            const key = BABYLON.MeshBuilder.CreateBox(props.note + props.register, {width: 1.4, height: 2, depth: 5}, scene);
            key.position.z += 4.75;
            key.position.y += 0.25;
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.material = blackMat;
            key.parent = parent;
    
            return key;
        }
    }
    

    Le props pour une clé noire contient les éléments suivants :

    • type : « black »
    • name : nom de la note que représente la clé
    • wholePositionX : position x de l’ensemble de la clé par rapport au point de terminaison du registre (le bord droit de la clé B)
    • register : inscrire à laquelle appartient la clé (un nombre compris entre 0 et 8)
    • referencePositionX : coordonnée x du point de terminaison du registre (utilisé comme point de référence).

    Le props pour créer une clé noire est beaucoup plus simple, car la création d’une clé noire implique uniquement la création d’une boîte, et la largeur et la position z de chaque clé noire sont identiques.

  3. Maintenant que nous avons un moyen plus efficace de créer les touches, initialisons un tableau qui stocke pour props chaque touche qui correspond à une note dans un registre, puis appelons la buildKey() fonction avec chacune d’elles pour créer un clavier simple dans le quatrième registre.

    Nous allons également créer un TransformNode nommé keyboard pour agir en tant que parent de toutes les touches de piano. Étant donné que toute modification de position ou de mise à l’échelle appliquée au parent est également appliquée aux enfants, le regroupement des clés de cette façon nous permet de les mettre à l’échelle ou de les déplacer dans leur ensemble.

    Ajoutez les lignes de code suivantes dans la createScene() fonction :

    const keyParams = [
        {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4},
        {type: "black", note: "C#", wholePositionX: -13.45},
        {type: "white", note: "D", topWidth: 1.4, bottomWidth: 2.4, topPositionX: 0, wholePositionX: -12},
        {type: "black", note: "D#", wholePositionX: -10.6},
        {type: "white", note: "E", topWidth: 1.4, bottomWidth: 2.3, topPositionX: 0.45, wholePositionX: -9.6},
        {type: "white", note: "F", topWidth: 1.3, bottomWidth: 2.4, topPositionX: -0.55, wholePositionX: -7.2},
        {type: "black", note: "F#", wholePositionX: -6.35},
        {type: "white", note: "G", topWidth: 1.3, bottomWidth: 2.3, topPositionX: -0.2, wholePositionX: -4.8},
        {type: "black", note: "G#", wholePositionX: -3.6},
        {type: "white", note: "A", topWidth: 1.3, bottomWidth: 2.3, topPositionX: 0.2, wholePositionX: -2.4},
        {type: "black", note: "A#", wholePositionX: -0.85},
        {type: "white", note: "B", topWidth: 1.3, bottomWidth: 2.4, topPositionX: 0.55, wholePositionX: 0},
    ]
    
    // Transform Node that acts as the parent of all piano keys
    const keyboard = new BABYLON.TransformNode("keyboard");
    
    keyParams.forEach(key => {
        buildKey(scene, keyboard, Object.assign({register: 4, referencePositionX: 0}, key));
    })
    

    Comme vous l’avez probablement remarqué, dans ce bloc de code, nous plaçons toutes les clés relatives à l’origine de l’espace.

  4. Voici le code que scene.js contient jusqu’à présent :

    const buildKey = function (scene, parent, props) {
        if (props.type === "white") {
            /*
            Props for building a white key should contain: 
            note, topWidth, bottomWidth, topPositionX, wholePositionX, register, referencePositionX
    
            As an example, the props for building the middle C white key would be
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4, register: 4, referencePositionX: 0}
            */
    
            // Create bottom part
            const bottom = BABYLON.MeshBuilder.CreateBox("whiteKeyBottom", {width: props.bottomWidth, height: 1.5, depth: 4.5}, scene);
    
            // Create top part
            const top = BABYLON.MeshBuilder.CreateBox("whiteKeyTop", {width: props.topWidth, height: 1.5, depth: 5}, scene);
            top.position.z =  4.75;
            top.position.x += props.topPositionX;
    
            // Merge bottom and top parts
            // Parameters of BABYLON.Mesh.MergeMeshes: (arrayOfMeshes, disposeSource, allow32BitsIndices, meshSubclass, subdivideWithSubMeshes, multiMultiMaterials)
            const key = BABYLON.Mesh.MergeMeshes([bottom, top], true, false, null, false, false);
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.name = props.note + props.register;
            key.parent = parent;
    
            return key;
        }
        else if (props.type === "black") {
            /*
            Props for building a black key should contain: 
            note, wholePositionX, register, referencePositionX
    
            As an example, the props for building the C#4 black key would be
            {type: "black", note: "C#", wholePositionX: -13.45, register: 4, referencePositionX: 0}
            */
    
            // Create black color material
            const blackMat = new BABYLON.StandardMaterial("black");
            blackMat.diffuseColor = new BABYLON.Color3(0, 0, 0);
    
            // Create black key
            const key = BABYLON.MeshBuilder.CreateBox(props.note + props.register, {width: 1.4, height: 2, depth: 5}, scene);
            key.position.z += 4.75;
            key.position.y += 0.25;
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.material = blackMat;
            key.parent = parent;
    
            return key;
        }
    }
    
    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 keyParams = [
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4},
            {type: "black", note: "C#", wholePositionX: -13.45},
            {type: "white", note: "D", topWidth: 1.4, bottomWidth: 2.4, topPositionX: 0, wholePositionX: -12},
            {type: "black", note: "D#", wholePositionX: -10.6},
            {type: "white", note: "E", topWidth: 1.4, bottomWidth: 2.3, topPositionX: 0.45, wholePositionX: -9.6},
            {type: "white", note: "F", topWidth: 1.3, bottomWidth: 2.4, topPositionX: -0.55, wholePositionX: -7.2},
            {type: "black", note: "F#", wholePositionX: -6.35},
            {type: "white", note: "G", topWidth: 1.3, bottomWidth: 2.3, topPositionX: -0.2, wholePositionX: -4.8},
            {type: "black", note: "G#", wholePositionX: -3.6},
            {type: "white", note: "A", topWidth: 1.3, bottomWidth: 2.3, topPositionX: 0.2, wholePositionX: -2.4},
            {type: "black", note: "A#", wholePositionX: -0.85},
            {type: "white", note: "B", topWidth: 1.3, bottomWidth: 2.4, topPositionX: 0.55, wholePositionX: 0},
        ]
    
        // Transform Node that acts as the parent of all piano keys
        const keyboard = new BABYLON.TransformNode("keyboard");
    
        keyParams.forEach(key => {
            buildKey(scene, keyboard, Object.assign({register: 4, referencePositionX: 0}, key));
        })
    
        const xrHelper = await scene.createDefaultXRExperienceAsync();
    
        return scene;
    }
    
  5. Voici à quoi ressemblerait le clavier obtenu :

    Clavier piano avec un registre

Extension à un piano à 88 touches

Dans cette section, nous allons développer l’utilisation des fonctions de création de touches pour générer un clavier de piano complet de 88 touches.

  1. Comme mentionné précédemment, un clavier de piano complet de 88 touches contient sept registres répétés et quatre autres notes. Trois de ces notes supplémentaires se trouvent dans le registre 0 (extrémité gauche du clavier) et 1 dans le registre 8 (extrémité droite du clavier).

    Disposition du piano à 88 touches

  2. Nous allons d’abord travailler sur la création des sept répétitions complètes en ajoutant une boucle supplémentaire autour de la boucle que nous avons écrite précédemment. Remplacez la boucle précédente pour la buildKey() fonction par le code suivant :

    // Register 1 through 7
    var referencePositionX = -2.4*14;
    for (let register = 1; register <= 7; register++) {
        keyParams.forEach(key => {
            buildKey(scene, keyboard, Object.assign({register: register, referencePositionX: referencePositionX}, key));
        })
        referencePositionX += 2.4*7;
    }
    

    Dans cette boucle, nous créons les clés du registre 1 à 7 et incrémentons la position de référence chaque fois que nous passons au registre suivant.

  3. Ensuite, nous allons créer le reste des clés. Ajoutez l’extrait de code suivant à la createScene() fonction :

    // Register 0
    buildKey(scene, keyboard, {type: "white", note: "A", topWidth: 1.9, bottomWidth: 2.3, topPositionX: -0.20, wholePositionX: -2.4, register: 0, referencePositionX: -2.4*21});
    keyParams.slice(10, 12).forEach(key => {
        buildKey(scene, keyboard, Object.assign({register: 0, referencePositionX: -2.4*21}, key));
    })
    
    // Register 8
    buildKey(scene, keyboard, {type: "white", note: "C", topWidth: 2.3, bottomWidth: 2.3, topPositionX: 0, wholePositionX: -2.4*6, register: 8, referencePositionX: 84});
    

    Notez que la touche la plus à gauche et la touche la plus à droite du clavier du piano ne tiennent pas dans les dimensions des accessoires définis dans keyParams (car elles ne sont pas à côté d’une touche noire au bord), nous devons donc définir un nouvel props objet pour chacun d’eux afin de spécifier leur forme spéciale.

  4. Le clavier produit doit ressembler à ceci une fois les modifications apportées :

    Maillage complet du clavier piano

Ajout d’un cadre de piano

  1. La scène semble un peu étrange avec juste un clavier flottant dans l’espace. Ajoutons un cadre de piano autour du clavier pour créer l’apparence d’un piano debout.

  2. À l’instar de la façon dont nous avons créé les clés, nous pouvons également créer le cadre en positionnant et en combinant un groupe de maillages de boîtes.

    Cependant, nous allons laisser ce défi pour vous d’essayer par vous-même et d’utiliser BABYLON. SceneLoader.ImportMesh pour importer un maillage prédéfini d’un cadre de piano debout. Ajoutez ce morceau de code à createScene():

    // Transform node that acts as the parent of all piano components
    const piano = new BABYLON.TransformNode("piano");
    keyboard.parent = piano;
    
    // Import and scale piano frame
    BABYLON.SceneLoader.ImportMesh("frame", "https://raw.githubusercontent.com/MicrosoftDocs/mixed-reality/docs/mixed-reality-docs/mr-dev-docs/develop/javascript/tutorials/babylonjs-webxr-piano/files/", "pianoFrame.babylon", scene, function(meshes) {
        const frame = meshes[0];
        frame.parent = piano;
    });
    

    Notez que nous créons à nouveau un parent TransformNode nommé piano pour regrouper le clavier et le cadre dans son ensemble. Cela rendra le déplacement ou la mise à l’échelle de l’ensemble du piano beaucoup plus facile si nous avons jamais besoin de le faire.

  3. Une fois le frame importé, notez que le clavier se trouve en bas du cadre (car les coordonnées y des touches sont à 0 par défaut). Soulevons le clavier pour qu’il s’intègre dans le cadre du piano debout :

    // Lift piano keys
    keyboard.position.y += 80;
    

    Étant donné que keyboard est le parent de toutes les touches de piano, nous pouvons soulever toutes les touches de piano en modifiant simplement la position y de keyboard.

  4. Le code final de scene.js doit ressembler à ceci :

    const buildKey = function (scene, parent, props) {
        if (props.type === "white") {
            /*
            Props for building a white key should contain: 
            note, topWidth, bottomWidth, topPositionX, wholePositionX, register, referencePositionX
    
            As an example, the props for building the middle C white key would be
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4, register: 4, referencePositionX: 0}
            */
    
            // Create bottom part
            const bottom = BABYLON.MeshBuilder.CreateBox("whiteKeyBottom", {width: props.bottomWidth, height: 1.5, depth: 4.5}, scene);
    
            // Create top part
            const top = BABYLON.MeshBuilder.CreateBox("whiteKeyTop", {width: props.topWidth, height: 1.5, depth: 5}, scene);
            top.position.z =  4.75;
            top.position.x += props.topPositionX;
    
            // Merge bottom and top parts
            // Parameters of BABYLON.Mesh.MergeMeshes: (arrayOfMeshes, disposeSource, allow32BitsIndices, meshSubclass, subdivideWithSubMeshes, multiMultiMaterials)
            const key = BABYLON.Mesh.MergeMeshes([bottom, top], true, false, null, false, false);
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.name = props.note + props.register;
            key.parent = parent;
    
            return key;
        }
        else if (props.type === "black") {
            /*
            Props for building a black key should contain: 
            note, wholePositionX, register, referencePositionX
    
            As an example, the props for building the C#4 black key would be
            {type: "black", note: "C#", wholePositionX: -13.45, register: 4, referencePositionX: 0}
            */
    
            // Create black color material
            const blackMat = new BABYLON.StandardMaterial("black");
            blackMat.diffuseColor = new BABYLON.Color3(0, 0, 0);
    
            // Create black key
            const key = BABYLON.MeshBuilder.CreateBox(props.note + props.register, {width: 1.4, height: 2, depth: 5}, scene);
            key.position.z += 4.75;
            key.position.y += 0.25;
            key.position.x = props.referencePositionX + props.wholePositionX;
            key.material = blackMat;
            key.parent = parent;
    
            return key;
        }
    }
    
    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 keyParams = [
            {type: "white", note: "C", topWidth: 1.4, bottomWidth: 2.3, topPositionX: -0.45, wholePositionX: -14.4},
            {type: "black", note: "C#", wholePositionX: -13.45},
            {type: "white", note: "D", topWidth: 1.4, bottomWidth: 2.4, topPositionX: 0, wholePositionX: -12},
            {type: "black", note: "D#", wholePositionX: -10.6},
            {type: "white", note: "E", topWidth: 1.4, bottomWidth: 2.3, topPositionX: 0.45, wholePositionX: -9.6},
            {type: "white", note: "F", topWidth: 1.3, bottomWidth: 2.4, topPositionX: -0.55, wholePositionX: -7.2},
            {type: "black", note: "F#", wholePositionX: -6.35},
            {type: "white", note: "G", topWidth: 1.3, bottomWidth: 2.3, topPositionX: -0.2, wholePositionX: -4.8},
            {type: "black", note: "G#", wholePositionX: -3.6},
            {type: "white", note: "A", topWidth: 1.3, bottomWidth: 2.3, topPositionX: 0.2, wholePositionX: -2.4},
            {type: "black", note: "A#", wholePositionX: -0.85},
            {type: "white", note: "B", topWidth: 1.3, bottomWidth: 2.4, topPositionX: 0.55, wholePositionX: 0},
        ]
    
        // Transform Node that acts as the parent of all piano keys
        const keyboard = new BABYLON.TransformNode("keyboard");
    
        // Register 1 through 7
        var referencePositionX = -2.4*14;
        for (let register = 1; register <= 7; register++) {
            keyParams.forEach(key => {
                buildKey(scene, keyboard, Object.assign({register: register, referencePositionX: referencePositionX}, key));
            })
            referencePositionX += 2.4*7;
        }
    
        // Register 0
        buildKey(scene, keyboard, {type: "white", note: "A", topWidth: 1.9, bottomWidth: 2.3, topPositionX: -0.20, wholePositionX: -2.4, register: 0, referencePositionX: -2.4*21});
        keyParams.slice(10, 12).forEach(key => {
            buildKey(scene, keyboard, Object.assign({register: 0, referencePositionX: -2.4*21}, key));
        })
    
        // Register 8
        buildKey(scene, keyboard, {type: "white", note: "C", topWidth: 2.3, bottomWidth: 2.3, topPositionX: 0, wholePositionX: -2.4*6, register: 8, referencePositionX: 84});
    
        // Transform node that acts as the parent of all piano components
        const piano = new BABYLON.TransformNode("piano");
        keyboard.parent = piano;
    
        // Import and scale piano frame
        BABYLON.SceneLoader.ImportMesh("frame", "https://raw.githubusercontent.com/MicrosoftDocs/mixed-reality/docs/mixed-reality-docs/mr-dev-docs/develop/javascript/tutorials/babylonjs-webxr-piano/files/", "pianoFrame.babylon", scene, function(meshes) {
            const frame = meshes[0];
            frame.parent = piano;
        });
    
        // Lift the piano keyboard
        keyboard.position.y += 80;
    
        const xrHelper = await scene.createDefaultXRExperienceAsync();
    
        return scene;
    }
    
  5. Maintenant, nous devrions avoir un piano debout qui ressemble à ceci : Standup Piano Mesh

Étapes suivantes