Öğretici: 3B piyano modeli oluşturma

Serideki önceki öğreticide, kamera ve hafif Babylon.js sahne içeren bir Web sayfası kurduk. Bu öğreticide, sahneye bir piyano modeli oluşturacak ve ekleyeceğiz.

Standsu Piano kafesi

Bu öğreticide şunların nasıl yapıldığını öğrenirsiniz:

  • Kafesler oluşturun, konumlandırın ve birleştirin
  • Box kafeslerden piyano klavyesi oluşturma
  • Bir piyano çerçevesinin 3B modelini içeri aktarma

Başlamadan önce

Serideki önceki öğreticiden gittiğinden ve koda eklenmeye devam etmek için hazırtığınızdan emin olun.

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

Başlarken

Bu yapıya sahip basit bir piyano klavyesi yaparak başlayalım:

Piano kayıt açıklaması

Bu görüntüde, her biri Not adı ile etiketlenmiş 7 beyaz anahtar ve 5 siyah tuş vardır. Tam 88 anahtar piyano klavyesi, bu anahtar seçiminin (kayıt olarak da adlandırılır) ve 4 ek anahtarın 7 tam tekrarlarını içerir. Her kayıt, önceki yazmacın sıklığının katına sahiptir. Örneğin, C5 'in sıklık sıklığı (yani, beşinci kayıttaki C notunun) C4's, D5's sıklık sıklığı D4's ve bu şekilde devam eder.

Görsel olarak, her kayıt birbirleriyle tamamen aynı şekilde görünür. bu sayede, bu anahtar seçimiyle basit bir piyano klavyesi oluşturmayı araştırmaya başlayabiliriz. Daha sonra, kapsamı 88 anahtar tam piyano klavyesine genişletmenin bir yolunu bulabiliriz.

Basit bir piyano klavyesi oluşturma

Not

Çevrimiçi kaynaklardan PIANO klavyelerinin önceden oluşturulmuş 3B modellerini bulmak ve bunları Web sayfanıza aktarmak mümkün olsa da, en yüksek özelleştirme izin vermek ve 3B modellerin Babylon.js aracılığıyla nasıl oluşturulabilmesini sağlamak için bu öğreticide bulunan klavye 'yi sıfırdan oluşturacağız.

  1. Klavyeyi oluşturmaya yönelik kafesler oluşturmaya başlamadan önce, her bir siyah anahtarın etrafında iki beyaz tuşun ortasında kusursuz Hizalanmadığını ve her anahtar aynı genişliğe sahip olmadığını unutmayın. Bu, her anahtar için her bir anahtarın tek tek oluşturulması ve konumlandırmalı olması gerektiği anlamına gelir.

    Siyah anahtar hizalaması

  2. Beyaz anahtarlar için, her beyaz anahtarın iki bölümden oluştuğunu gözlemliyoruz: (1) siyah anahtarların altındaki alt bölüm ve (2) siyah anahtarların yanındaki üst bölüm. İki bölüm farklı boyutlara sahiptir, ancak bir tam beyaz anahtar Crete için bir araya yığılır.

    Beyaz anahtar şekli

  3. Burada, Note C için tek bir beyaz anahtar oluşturmaya yönelik kod verilmiştir (bunu henüz scene.js ekleme konusunda endişelenmeyin):

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

    Burada, biri alt bölümü ve diğeri beyaz anahtarın en üst bölümü için olmak üzere iki Box kafesi oluşturduk. Ardından, en üstteki bölümün konumunu, alt bölümün en üstüne yığmak ve bitişik siyah anahtar (C#) için boşluk bırakmak üzere sola doğru taşımak için değiştirirsiniz.

    Son olarak, bu iki bölüm, bir bütün beyaz anahtar olmak için Mergekafesler işlevi kullanılarak birleştirildi. Bu, bu kodun üretebilecek elde edilen kafesdir:

    Beyaz tuşu C

  4. Siyah bir anahtar oluşturmak daha basittir. Tüm siyah tuşları bir kutu şekli olduğundan, siyah renkli bir Standart malzemeylebir kutu ağı oluşturarak yalnızca siyah bir anahtar oluşturabilirsiniz.

    Not

    Varsayılan kafes rengi beyaza benzer bir açık gri olduğundan, bu öğreticide beyaz tuşlara beyaz renkli malzemeler ekleme adımları dahil değildir. Ancak, beyaz tuşlara doğru, parlak bir beyaz renk istiyorsanız, malzemeyi kendiniz ekleyebilirsiniz.

    Siyah anahtar C# oluşturmak için kod aşağıda verilmiştir ( scene.js buna ekleme konusunda endişelenmeyin):

    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;
    

    Bu kod tarafından üretilen siyah anahtar (önceki beyaz anahtarla birlikte) şöyle görünür:

    Siyah anahtar C #

  5. Görebileceğiniz gibi, her bir anahtarın oluşturulması, boyutlarının ve konumlarından her birini belirttiğimiz için birçok benzer kodla sonuçlanabilir. Sonraki bölümde oluşturma işlemini daha verimli hale getirmek için deneyelim.

Basit bir piyano klavyeyi verimli bir şekilde oluşturun

  1. Her beyaz anahtarın birbirinden biraz farklı bir şekli olsa da, bunların hepsi bir üst bölümü ve alt bölümü birleştirerek oluşturulabilir. Beyaz anahtar oluşturmak ve konumlandırmak için genel bir işlev uygulayalim.

    Aşağıdaki işlevi, işlevin dışında scene.js ekleyin 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;
        }
    }
    

    Bu kod bloğunda adında bir beyaz anahtar oluşturup döndüren adlı bir işlev oluşturduk buildKey() props.type "white" . Parametresindeki anahtarın türünü tanımlayarak props , aynı işlevde bir if-ifadesiyle dallandırma yaparak hem siyah anahtarlar hem de beyaz anahtarlar oluşturuyoruz.

    Parametreleri buildKey() şunlardır:

    • sahne: anahtarın bulunduğu sahne
    • Parent: kafesin üst öğesi (Bu, tüm anahtarları tek bir üst öğeye gruplandırmamızı sağlar)
    • props: oluşturulacak anahtarın özellikleri

    propsBeyaz anahtar için aşağıdaki öğeler yer alacak:

    • yazın: "beyaz"
    • ad: anahtarın gösterdiği notun adı
    • Topwidth: üst bölümün genişliği
    • Bottomwidth: alt bölümün genişliği
    • Toppositionx: en üstteki bölümün alt kısma göre x-konumu
    • wholePositionX: tüm anahtarın, kaydın bitiş noktasına göre konumu (B tuşunun sağ kenarı).
    • Kaydol: anahtarın ait olduğu kayıt (0 ile 8 arasında bir sayı)
    • Referencepositionx: yazmacın bitiş noktasının x-koordinatı (bir başvuru noktası olarak kullanılır).

    wholePositionXVe referencePositionX ' yi ayırarak, props herhangi bir yazmaç içinde belirli bir anahtar türü (ör. C) oluşturmak için gereken parametreleri başlatabiliriz ve ardından register referencePositionX props belirli bir kayıttaki bu anahtarı oluştururken ve öğesine ekleyebilirsiniz (örneğin, C4, C5).

  2. Benzer şekilde, bir siyah anahtar oluşturmak için genel bir işlev de yazabilirsiniz. buildKey()Bu mantığı eklemek için işlevi genişletelim:

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

    propsBir siyah anahtar için aşağıdaki öğeleri içerir:

    • yazın: "siyah"
    • ad: anahtarın gösterdiği notun adı
    • wholePositionX: tüm anahtarın, kaydın bitiş noktasına göreli konumu (B tuşunun sağ kenarı)
    • Kaydol: anahtarın ait olduğu kayıt (0 ile 8 arasında bir sayı)
    • Referencepositionx: yazmacın bitiş noktasının x-koordinatı (bir başvuru noktası olarak kullanılır).

    Siyah anahtar oluşturmak props için, yalnızca bir kutu oluşturmak ve her siyah anahtarın Width ve z konumu aynı olduğunda bir siyah anahtar oluşturmak çok daha basittir.

  3. Anahtarları oluşturmanın daha verimli bir yolu olduğuna göre, props bir kayıttaki nota karşılık gelen her anahtar için öğesini depolayan bir dizi başlatalım ve ardından buildKey() 4 kayıt içinde basit bir klavye oluşturmak için bu her biri ile birlikte işlevini çağırabiliriz.

    Ayrıca, keyboard tüm piyano anahtarlarının üst öğesi olarak görev yapacak adlı bir transformNode oluşturacağız. Üst öğeye uygulanan herhangi bir konum veya ölçeklendirme değişikliği alt öğelere de uygulandığından, anahtarları bu şekilde gruplandırmak, bunları bir bütün olarak ölçeklendirmemizi veya taşımamızı sağlar.

    İşleve aşağıdaki kod satırlarını ekleyin 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));
    })
    

    Büyük olasılıkla fark ettiğimiz gibi, bu kod bloğunda alanın kaynağına göre tüm anahtarları yerleştiriyoruz.

  4. scene.js şu ana kadar içeren kod aşağıda verilmiştir:

    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;
    
        // Transform Node that acts as the parent of all piano keys
        const keyboard = new BABYLON.TransformNode("keyboard");
    
        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. Elde edilen klavye şöyle görünür:

    Tek bir yazmaç ile Piano klavyesi

88 anahtar piyano 'e genişletme

Bu bölümde, anahtar oluşturma işlevlerinin kullanımını, tam, 88-anahtar piyano klavyesi oluşturmak için genişletelim.

  1. Daha önce belirtildiği gibi, tam, 88 anahtar piyano klavyesi 7 yinelenen kayıt ve 4 diğer Not içerir. 3 ' ün kayıt defteri 0 ' dır (klavyenin sol ucu) ve 1, YAZMAÇ 8 ' de (klavyenin sağ ucunda).

    88-anahtar piyano düzeni

  2. Daha önce yazdığımız döngüden sonra ek bir döngü ekleyerek ilk olarak 7 tam tekrarları oluşturmaya çalışacağız. İşlevin önceki döngüsünü buildKey() aşağıdaki kodla değiştirin:

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

    Bu döngüde, 1 ile 7 arasında kaydetme için anahtarlar oluşturacağız ve sonraki kayda her geçiş yaptığımız her seferinde başvuru konumunu artırdık.

  3. Sonra, anahtarların geri kalanını oluşturalım. İşlevine aşağıdaki kod parçacığını ekleyin 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});
    

    Piyano klavyesi 'nin en sol üst anahtarının ve en sağ anahtarının, ' de tanımlanan props boyutlarına sığmıyor keyParams (kenarda bir siyah bir anahtarın yanında olmadığı için), props her biri için özel şeklini belirtmemiz gerekir.

  4. Oluşturulan klavye, değişiklikler yapıldıktan sonra şöyle görünmelidir:

    Tam Piano klavye ağı

Piyano çerçevesi ekleme

  1. Sahne, yalnızca alana bir klavye ile biraz daha görünür. Daha sonra, bir en hızlı piyano görünümünü oluşturmak için klavyenin çevresine bir piyano çerçevesi ekleyelim.

  2. Anahtarları oluşturma ile aynı şekilde, bir grup kutusu kafesleri konumlandırarak ve birleştirerek çerçeve de oluşturabilirsiniz.

    Bununla birlikte, size kendi kendinize denemenize ve Babylon ' i kullanmanıza yönelik bu sınamayı bırakacağız . Bir standsu piyano çerçevesinin önceden oluşturulmuş bir kafesi içeri aktarmak için, manzara. ımportkafes. Bu kod parçasını buraya ekleyin 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://docs.microsoft.com/windows/mixed-reality/develop/javascript/tutorials/babylonjs-webxr-piano/files", "pianoFrame.babylon", scene, function(meshes) {
        const frame = meshes[0];
        frame.parent = piano;
    });
    

    Bir kez daha olduğunu TransformNode piano ve klavyeyi ve çerçeveyi bir bütün olarak gruplamak için adlı bir üst öğe oluşturmayı unutmayın. Bu, bunu yapdığımızda, tüm piyano 'in tamamını çok daha kolay hareket ettirmeye veya ölçeklendirmeye devam edecektir.

  3. Çerçeve içe aktarıldıktan sonra, klavyenin çerçevenin en altında olduğuna dikkat edin (anahtarların y koordinatları varsayılan olarak 0 ' dır). Klavyeyi, en uygun piyano çerçevesine sığacak şekilde kaldıralım:

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

    keyboardTüm piyano anahtarlarının üst öğesi olduğundan, tüm piyano anahtarlarını yalnızca y konumunu değiştirerek kaldırabilirsiniz keyboard .

  4. scene.js nihai kodu şöyle görünmelidir:

    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://docs.microsoft.com/windows/mixed-reality/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. Şimdi şu şekilde görünen bir standsu sunuyoruz:  Standsu piyano kafesi

Sonraki adımlar