Tutoriel : Créer un modèle de piano 3D
Dans le tutoriel précédent de la série, nous avons configuré une page web contenant une scène Babylon.js avec une caméra et une lumière. Dans ce tutoriel, nous allons créer un modèle de piano et l’ajouter à la scène.
Dans ce didacticiel, vous apprendrez à :
- Créer, positionner et fusionner des maillages
- Créer un clavier de piano à partir de maillages de boîte
- Importer le modèle 3D d’une structure de piano
Avant de commencer
Vérifiez que vous avez bien effectué les étapes du tutoriel précédent de la série et que vous êtes prêt à ajouter du 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 la structure suivante :
Dans cette image, vous avez 7 touches blanches et 5 touches noires, chacune portant le nom de la note. Un clavier de piano à 88 touches contient 7 répétitions complètes de cette sélection de touches (ou « registre ») et 4 touches supplémentaires. La fréquence d’un registre est deux fois celle du registre précédent. Ainsi, la fréquence de la hauteur de C5 (c’est-à-dire la note C dans le cinquième registre) est deux fois celle de C4, la fréquence de la hauteur de D5 est deux fois celle de D4, et ainsi de suite.
Visuellement, tous les registres se ressemblent. Nous pouvons donc commencer par examiner comment créer un clavier de piano simple avec cette sélection de touches. Plus tard, nous verrons comment l’étendre à 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 en ligne et de les importer dans notre page web, nous allons créer dans ce tutoriel un clavier de toutes pièces pour pouvoir le personnaliser au maximum et voir comment créer des modèles 3D avec Babylon.js.
Avant de commencer à créer des maillages pour créer le clavier, notez que chaque touche noire n’est pas parfaitement alignée au milieu des deux touches blanches qui l’entourent, et que chaque touche n’a pas la même largeur. Nous devons donc créer et positionner le maillage pour chaque touche.
Vous pouvez observer que chaque touche blanche se compose de deux parties : (1) la partie inférieure sous la ou les touches noires et (2) la partie supérieure à côté de la ou des touches noires. Les deux parties ont des dimensions différentes, mais sont empilées pour former une touche blanche complète.
Voici le code permettant de créer une touche blanche unique pour la note C (inutile de l’ajouter à scene.js pour l’instant) :
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 créons deux maillages de boîte (Box), un pour la partie inférieure et un pour la partie supérieure de la touche 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 la place à la touche noire voisine (C#).
Enfin, ces deux parties sont fusionnées avec la fonction MergeMeshes pour former une touche blanche complète. Voici le maillage qui est produit par ce code :
Les touches noires sont plus faciles à créer. Dans la mesure où toutes les touches noires sont de forme rectangulaire, nous pouvons simplement créer une touche noire avec un maillage de boîte et 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 les étapes permettant d’ajouter un matériau de couleur blanc aux touches blanches. Toutefois, n’hésitez pas à ajouter vous-même le matériau si vous souhaitez affecter une vraie couleur blanche aux touches blanches.
Voici le code permettant de créer la touche noire C# (là encore, inutile 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 touche noire produite par ce code (avec la touche blanche précédente) ressemble à ceci :
Comme vous pouvez le voir, la création des touches peut générer une grande quantité de code similaire dans la mesure où nous devons spécifier les dimensions et la position de chaque touche. Dans la section suivante, nous allons essayer d’améliorer l’efficacité du processus de création.
Créer un clavier de piano simple de manière efficace
Même si leur forme varie légèrement, toutes les touches blanches sont créées en combinant une partie supérieure et une partie inférieure. Nous allons implémenter une fonction générique pour créer et positionner une touche blanche.
Ajoutez la fonction ci-dessous à scene.js, en dehors de la fonction
createScene()
: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 touche blanche siprops.type
est"white"
. En identifiant le type de la touche dans le paramètreprops
, nous pouvons créer des touches noires et blanches dans la même fonction en créant une branche avec une instruction if.Les paramètres de
buildKey()
sont les suivants :- scene : scène où se trouve la touche
- parent : parent du maillage (ce qui nous permet de regrouper toutes les touches dans un seul parent)
- props : propriétés de la touche qui sera créée
Le paramètre
props
contient les éléments suivants pour une touche blanche :- type : "white"
- name : nom de la note représentée par la touche
- 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 la touche entière par rapport au point d’extrémité du registre (bord droit de la touche B)
- register : registre auquel appartient la touche (nombre compris entre 0 et 8)
- referencePositionX : coordonnée x du point d’extrémité du registre (utilisé comme point de référence)
En séparant
wholePositionX
etreferencePositionX
, nous pouvons initialiser les paramètresprops
nécessaires pour créer un type spécifique de touche (par exemple, C) dans n’importe quel registre, puis ajouterregister
etreferencePositionX
àprops
au moment de la création de cette touche dans un registre spécifique (par exemple, C4, C5).De même, nous pouvons écrire une fonction générique pour créer une touche noire. Développons la fonction
buildKey()
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 paramètre
props
contient les éléments suivants pour une touche noire :- type : "black"
- name : nom de la note représentée par la touche
- wholePositionX : position x de la touche entière par rapport au point d’extrémité du registre (bord droit de la touche B)
- register : registre auquel appartient la touche (nombre compris entre 0 et 8)
- referencePositionX : coordonnée x du point d’extrémité du registre (utilisé comme point de référence)
Le paramètre
props
nécessaire pour créer une touche noire est beaucoup plus simple. En effet, la création d’une touche noire implique uniquement la création d’une boîte, et la largeur et la position z de chaque touche noire sont identiques.Maintenant que nous disposons d’une méthode plus efficace pour créer les touches, initialisons un tableau qui stocke le paramètre
props
pour chaque touche correspondant à une note dans un registre, puis appelons la fonctionbuildKey()
avec chaque touche pour créer un clavier simple dans le 4e registre.Nous allons également créer un TransformNode nommé
keyboard
pour agir en tant que parent de toutes les touches du piano. Étant donné que toute modification de position ou de mise à l’échelle appliquée au parent est également appliquée aux enfants, le fait de regrouper les touches de cette manière nous permet de les mettre à l’échelle ou de les déplacer en même temps.Ajoutez les lignes de code suivantes à la fonction
createScene()
: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’aurez probablement remarqué, toutes les touches sont placées en fonction de l’origine de l’espace dans ce bloc de code.
Voici le code contenu dans scene.js 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; }
Voici à quoi ressemble le clavier résultant :
Extension à un clavier de piano de 88 touches
Dans cette section, nous allons étendre l’utilisation des fonctions de création de touche pour générer un clavier de piano complet de 88 touches.
Comme nous l’avons vu précédemment, un clavier de piano complet de 88 touches contient 7 registres répétés et 4 autres notes. 3 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).
Pour créer les 7 répétitions complètes, nous allons tout d’abord ajouter une boucle supplémentaire autour de celle écrite précédemment. Remplacez la boucle précédente pour la fonction
buildKey()
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 touches pour les registres 1 à 7 et incrémentons la position de référence chaque fois que nous passons au registre suivant.
Nous pouvons ensuite créer le reste des touches. Ajoutez l’extrait de code suivant à la fonction
createScene()
:// 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 à l’extrémité gauche et celle à l’extrémité droite du clavier du piano ne tiennent pas dans les dimensions du paramètre props défini dans
keyParams
(parce qu’elles ne sont pas à côté d’une touche noire à la périphérie). Nous devons donc définir un nouvel objetprops
pour chacune d’elles afin de spécifier leur forme spéciale.Une fois les modifications apportées, le clavier doit ressembler à ceci :
Ajout d’une structure de piano
Cette scène d’un clavier qui flotte dans l’air est un peu étrange. Nous allons ajouter une structure de piano autour du clavier pour créer l’apparence d’un piano droit.
De la même manière que nous avons créé les touches, nous pouvons créer la structure en positionnant et en combinant un groupe de maillages de boîte.
Cependant, nous allons vous laisser le soin d’accomplir cette tâche avec BABYLON.SceneLoader.ImportMesh pour importer le maillage prédéfini d’une structure de piano droit. Ajoutez ce segment 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; });
Là encore, nous créons un parent
TransformNode
nommépiano
pour regrouper le clavier et la structure du piano. Nous pourrons ainsi déplacer ou mettre à l’échelle le piano complet beaucoup plus facilement en cas de besoin.Une fois la structure importée, notez que le clavier se trouve en bas de la structure (puisque les coordonnées y des touches sont par défaut égales à 0). Déplaçons le clavier vers le haut pour le placer dans la structure du piano droit :
// Lift piano keys keyboard.position.y += 80;
Comme
keyboard
est le parent de toutes les touches du piano, nous pouvons déplacer vers le haut toutes les touches du piano en modifiant simplement la position y dekeyboard
.Le code final de scene.js doit ressembler à ce qui suit :
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; }
Notre piano droit doit maintenant ressembler à ceci :