Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Im vorherigen Tutorial der Reihe haben Sie eine Webseite eingerichtet, die eine Babylon.js Szene mit einer Kamera und einer Led enthält. In diesem Tutorial erstellen Sie ein Klaviermodell und fügen es der Szene hinzu.
In diesem Tutorial wird Folgendes vermittelt:
- Erstellen, Positionieren und Zusammenführen von Gittern
- Erstellen einer Klaviertastatur aus Boxgittern
- Importieren eines 3D-Modells eines Klavierrahmens
Bevor Sie beginnen
Stellen Sie sicher, dass Sie das vorherige Tutorial in der Reihe abgeschlossen haben und bereit sind, das Hinzufügen zum Code fortzusetzen.
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;
}
Erste Schritte
Beginnen wir mit der Erstellung einer einfachen Klaviertastatur mit dieser Struktur:
In dieser Abbildung gibt es sieben weiße und fünf schwarze Tasten, die jeweils mit dem Namen der Notiz beschriftet sind. Eine volle 88-Tasten-Klaviertastaturen enthält sieben vollständige Wiederholungen dieser Tastenauswahl (auch Register genannt) und vier zusätzliche Tasten. Jedes Register hat die doppelte Häufigkeit seines vorherigen Registers. Beispielsweise ist die Tonhöhenfrequenz von C5 (d. h. die C-Note im fünften Register) doppelt so hoch wie die von C4, die Tonhöhenfrequenz von D5 ist doppelt so hoch wie die von D4 usw.
Visuell sieht jedes Register genau wie ein anderes aus, sodass wir mit der Erstellung einer einfachen Klaviertastaturen mit dieser Tastenauswahl beginnen können. Später finden wir eine Möglichkeit, den Bereich auf eine 88-Tasten-Voll-Klaviertastaturen zu erweitern.
Erstellen einer einfachen Klaviertastatatur
Hinweis
Obwohl es möglich ist, vorgefertigte 3D-Modelle von Klaviertastaturen aus Onlinequellen zu finden und in unsere Webseite zu importieren, erstellen wir die Tastatur in diesem Tutorial von Grund auf neu, um maximale Anpassbarkeit zu ermöglichen und zu zeigen, wie 3D-Modelle über Babylon.js erstellt werden können.
Bevor wir mit dem Erstellen von Gittern für die Tastatur beginnen, beachten Sie, dass jede schwarze Taste nicht perfekt in der Mitte der beiden weißen Tasten um sie herum ausgerichtet ist und nicht jede Taste die gleiche Breite hat. Das bedeutet, dass wir das Gitter für jeden Schlüssel einzeln erstellen und positionieren müssen.
Bei weißen Tasten können wir beobachten, dass jede weiße Taste aus zwei Teilen besteht: (1) dem unteren Teil unterhalb der schwarzen Taste(n) und (2) dem oberen Teil neben den schwarzen Schlüsseln. Die beiden Teile weisen unterschiedliche Dimensionen auf, werden jedoch zusammen gestapelt, um eine vollständige weiße Taste zu erstellen.
Hier ist der Code zum Erstellen einer einzelnen weißen Taste für die Notiz C (machen Sie sich noch keine Gedanken über das Hinzufügen zu 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";Hier haben wir zwei Box-Gitter erstellt, eines für den unteren Teil und eines für den oberen Teil der weißen Taste. Anschließend ändern wir die Position des oberen Teils so, dass er über dem unteren Teil gestapelt und nach links verschoben wird, um Platz für die benachbarte schwarze Taste (C#) zu lassen.
Schließlich wurden diese beiden Teile mithilfe der MergeMeshes-Funktion zusammengeführt, um eine vollständige weiße Taste zu werden. Dies ist das resultierende Gitter, das dieser Code erzeugen würde:
Das Erstellen einer schwarzen Taste ist einfacher. Da alle schwarzen Tasten die Form eines Kästchens haben, können wir eine schwarze Taste erstellen, indem wir einfach ein Box-Gitter mit einem schwarz gefärbten StandardMaterial erstellen.
Hinweis
Da die Standardnetzfarbe hellgrau ist, die weiß ähnelt, enthält dieses Tutorial keine Schritte zum Hinzufügen eines weißen Farbmaterials zu den weißen Tasten. Sie können das Material jedoch selbst hinzufügen, wenn Sie eine echte, hellweiße Farbe auf den weißen Tasten haben möchten.
Hier sehen Sie den Code zum Erstellen der schwarzen Taste C# (machen Sie sich auch keine Gedanken über das Hinzufügen zu 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;Die von diesem Code erzeugte schwarze Taste (zusammen mit der vorherigen weißen Taste) sieht wie folgt aus:
Wie Sie sehen können, kann das Erstellen der einzelnen Schlüssel zu vielen ähnlichen Codes führen, da wir jede ihrer Dimensionen und Positionen angeben müssen. Versuchen wir im nächsten Abschnitt, den Erstellungsprozess effizienter zu gestalten.
Effizientes Erstellen einer einfachen Klaviertastatatur
Obwohl jede weiße Taste eine etwas andere Form hat als jede andere, können sie alle durch Kombination eines oberen und eines unteren Teils erstellt werden. Lassen Sie uns eine generische Funktion implementieren, um eine beliebige weiße Taste zu erstellen und zu positionieren.
Fügen Sie die folgende Funktion scene.jsaußerhalb der
createScene()Funktion hinzu: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; } }In diesem Codeblock haben wir eine Funktion namens
buildKey()erstellt, die eine weiße Taste erstellt und zurückgibt, wennprops.typeist"white". Durch Die Identifizierung des Schlüsseltyps im -Parameterpropskönnen wir sowohl schwarze als auch weiße Schlüssel in derselben Funktion erstellen, indem wir mit einer if-Anweisung verzweigen.Die Parameter von
buildKey()sind:- scene: Szene, in der sich der Schlüssel befindet
- parent: übergeordnetes Element des Gitters (damit können wir alle Schlüssel zu einem einzelnen übergeordneten Element gruppieren)
- Props: Eigenschaften des Schlüssels, der erstellt wird
Die
propsfür eine weiße Taste enthält die folgenden Elemente:- type: "white"
- name: Der Name der Notiz, die der Schlüssel darstellt.
- topWidth: Breite des oberen Teils
- bottomWidth: Breite des unteren Teils
- topPositionX: x-Position des oberen Teils relativ zum unteren Teil
- wholePositionX: x-Position des gesamten Schlüssels relativ zum Endpunkt des Registers (der rechte Rand von Taste B).
- register: Registrieren, dass der Schlüssel gehört (eine Zahl zwischen 0 und 8)
- referencePositionX: x-Koordinate des Endpunkts des Registers (wird als Bezugspunkt verwendet).
Durch Trennen von und
referencePositionXkönnen wir die Parameter initialisieren, diepropszum Erstellen eines bestimmten Schlüsseltyps (z. B. C) in einem beliebigen Register erforderlich sind, und dann beim Erstellen diesesreferencePositionXpropsSchlüssels in einem bestimmten Register (z. B. C4, C5) und hinzufügenregister.wholePositionXEbenso können wir auch eine generische Funktion schreiben, um eine schwarze Taste zu erstellen. Erweitern wir die
buildKey()Funktion, um diese Logik einzuschließen: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; } }Die
propsfür eine schwarze Taste enthält die folgenden Elemente:- type: "black"
- name: Der Name der Notiz, die der Schlüssel darstellt.
- wholePositionX: x-Position des gesamten Schlüssels relativ zum Endpunkt des Registers (der rechte Rand von Taste B)
- register: Registrieren, dass der Schlüssel gehört (eine Zahl zwischen 0 und 8)
- referencePositionX: x-Koordinate des Endpunkts des Registers (wird als Bezugspunkt verwendet).
Die
propszum Erstellen einer schwarzen Taste ist viel einfacher, da das Erstellen einer schwarzen Taste nur das Erstellen eines Felds umfasst und die Breite und Z-Position jeder schwarzen Taste identisch sind.Nachdem wir nun eine effizientere Möglichkeit zum Erstellen der Tasten haben, initialisieren wir ein Array, das die für jede Taste speichert, die
propseiner Notiz in einem Register entspricht, und rufen dann diebuildKey()Funktion mit jeder von ihnen auf, um eine einfache Tastatur im vierten Register zu erstellen.Außerdem wird ein TransformNode mit dem Namen
keyboarderstellt, der als übergeordnetes Element aller Klaviertasten fungiert. Da jede Position oder Skalierungsänderung, die auf das übergeordnete Element angewendet wird, auch auf die untergeordneten Elemente angewendet würde, können wir die Schlüssel auf diese Weise gruppieren, um sie als Ganzes zu skalieren oder zu verschieben.Fügen Sie die folgenden Codezeilen in der
createScene()Funktion an: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)); })Wie Sie wahrscheinlich bemerkt haben, platzieren wir in diesem Codeblock alle Schlüssel relativ zum Ursprung des Leerzeichens.
Hier ist der Code, der scene.js bisher enthält:
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; }Die resultierende Tastatur würde wie folgt aussehen:
Erweiterung auf ein 88-Tasten-Klavier
In diesem Abschnitt erweitern wir die Verwendung der Tastenerstellungsfunktionen, um eine vollständige Klaviertastatur mit 88 Tasten zu generieren.
Wie bereits erwähnt, enthält eine volle, 88-Tasten-Klaviertastaturen sieben wiederholte Register und vier weitere Noten. Drei dieser zusätzlichen Notizen befinden sich im Register 0 (linkes Ende der Tastatur), und 1 befindet sich im Register 8 (rechtes Ende der Tastatur).
Wir arbeiten zunächst daran, die sieben vollständigen Wiederholungen zu erstellen, indem wir eine zusätzliche Schleife um die zuvor geschriebene Schleife hinzufügen. Ersetzen Sie die vorherige Schleife für die
buildKey()Funktion durch den folgenden Code:// 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; }In dieser Schleife erstellen wir die Schlüssel für register 1 bis 7 und erhöhen die Referenzposition jedes Mal, wenn wir mit dem nächsten Register fortfahren.
Als Nächstes erstellen wir die restlichen Schlüssel. Fügen Sie der Funktion den
createScene()folgenden Codeausschnitt hinzu:// 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});Beachten Sie, dass die taste ganz links und die taste ganz rechts der Klaviertastatur nicht in die Abmessungen der in
keyParamsdefinierten Requisiten passen (da sie sich nicht neben einer schwarzen Taste am Rand befinden). Daher müssen wir ein neuesprops-Objekt für jede der Tastaturen definieren, um ihre spezielle Form anzugeben.Die erstellte Tastatur sollte wie folgt aussehen, nachdem die Änderungen vorgenommen wurden:
Hinzufügen eines Klavierrahmens
Die Szene sieht ein wenig seltsam aus, wenn nur eine Tastatur im Raum schwebt. Fügen Sie einen Klavierrahmen um die Tastatur hinzu, um das Aussehen eines Standup-Pianos zu schaffen.
Ähnlich wie bei der Erstellung der Tasten können wir auch den Rahmen erstellen, indem wir eine Gruppe von Box-Gittern positionieren und kombinieren.
Wir überlassen Ihnen jedoch diese Herausforderung, um es selbst zu versuchen und BABYLON zu verwenden . SceneLoader.ImportMesh zum Importieren eines vorgefertigten Gitters eines Standup-Klavierrahmens. Fügen Sie diesen Codeabschnitt an an
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; });Beachten Sie, dass wir erneut ein übergeordnetes
TransformNodeElement mit dem Namenpianoerstellen, um die Tastatur und den Rahmen als Ganzes zu gruppieren. Dies wird das Bewegen oder Skalieren des gesamten Klaviers viel einfacher machen, wenn wir dies jemals tun müssen.Nachdem der Frame importiert wurde, beachten Sie, dass die Tastatur am unteren Rand des Frames liegt (da die y-Koordinaten der Tasten standardmäßig bei 0 liegen). Lassen Sie uns die Tastatur anheben, damit sie in den Standup-Klavierrahmen passt:
// Lift piano keys keyboard.position.y += 80;Da
keyboarddas Übergeordnete aller Klaviertasten ist, können wir alle Klaviertasten anheben, indem wir einfach die y-Position vonkeyboardändern.Der endgültige Code von scene.js sollte wie folgt aussehen:
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; }Nun sollten wir ein Standup-Piano haben, das wie folgt aussieht:
