Öğretici: 3B piyano modeli oluşturma
Serinin önceki öğreticisinde, kamera ve ışık içeren bir Babylon.js sahnesi içeren bir web sayfası ayarladık. Bu öğreticide, sahneye bir piyano modeli oluşturacak ve ekleyeceğiz.
Bu öğreticide şunların nasıl yapıldığını öğrenirsiniz:
- Tire oluşturma, konumlandırma ve birleştirme
- Kutu kafeslerinden piyano klavyesi oluşturma
- Piyano çerçevesinin 3B modelini içeri aktarma
Başlamadan önce
Serinin önceki öğreticisini tamamladığınızdan ve koda eklemeye devam etmeye hazır olduğunuzdan 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:
Bu görüntüde, her biri not adıyla etiketlenmiş 7 beyaz ve 5 siyah tuş vardır. Tam 88 tuşlu piyano klavyesi, bu tuş seçiminin 7 tam tekrarını (yazmaç olarak da adlandırılır) ve 4 ekstra tuş içerir. Her yazmaç, önceki yazmaç sıklığının iki katıdır. Örneğin, C5'in perde sıklığı (beşinci yazmaçtaki C notu) C4'ün iki katı, D5'in perde sıklığı D4'ün iki katı, vb. olur.
Görsel olarak, her yazmaç aynı şekilde görünür, bu nedenle bu tuş seçimiyle basit bir piyano klavyesinin nasıl oluşturulacağını araştırmakla başlayabiliriz. Daha sonra kapsamı 88 tuşlu tam piyano klavyesine genişletmenin bir yolunu bulabiliriz.
Basit bir piyano klavyesi oluşturma
Not
Piyano klavyelerinin önceden hazırlanmış 3B modellerini çevrimiçi kaynaklardan bulup web sayfamıza aktarmak mümkün olsa da, en fazla özelleştirilebilirliğe izin vermek ve Babylon.js aracılığıyla 3B modellerin nasıl oluşturulabileceğini göstermek için bu öğreticide klavyeyi sıfırdan oluşturacağız.
Klavyeyi oluşturmak için herhangi bir tire oluşturmaya başlamadan önce, her siyah tuşun çevresindeki iki beyaz tuşlarına mükemmel bir şekilde hizalanmadığını ve her tuşun aynı genişliğe sahip olmadığını fark edin. Bu, her anahtar için ağı ayrı ayrı oluşturmamız ve konumlandırmamız gerektiği anlamına gelir.
Beyaz tuşlar için, her beyaz anahtarın iki bölümden oluştuğunu gözlemleyebiliriz: (1) siyah tuşların altındaki alt kısım ve (2) siyah tuşların yanındaki üst kısım. İki parçanın farklı boyutları vardır, ancak tam bir beyaz anahtar girebilmek için birlikte yığılır.
C notu için tek bir beyaz anahtar oluşturma kodu aşağıdadır (bunu henüzscene.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 kısım, diğeri de beyaz anahtarın üst kısmı için iki Kutu tire oluşturduk. Daha sonra üst kısmın konumunu değiştirerek alt kısmın üstüne yığacağız ve komşu siyah tuşa (C#) yer bırakmak üzere sola doğru hareket ettireceğiz.
Son olarak, bu iki bölüm MergeMeshes işlevi kullanılarak birleştirilerek tam bir beyaz anahtar haline geldi. Bu kodun üreteceği sonuçta elde edilen ağ budur:
Siyah anahtar oluşturmak daha kolaydır. Tüm siyah tuşlar bir kutu şeklinde olduğundan, siyah renkli StandardMaterial ile bir kutu ağı oluşturarak siyah bir anahtar oluşturabiliriz.
Not
Varsayılan mesh rengi beyaza benzeyen açık gri olduğundan, bu öğreticide beyaz tuşlara beyaz renk malzemesi ekleme adımları yer almaz. Ancak, beyaz tuşlara gerçek, parlak beyaz bir renk istiyorsanız malzemeyi kendiniz ekleyebilirsiniz.
Siyah anahtar C# oluşturmak için kod aşağıdadır (bunu dascene.js 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:
Gördüğünüz gibi, her anahtarın oluşturulması birçok benzer koda neden olabilir çünkü bunların boyutlarını ve konumlarını belirtmemiz gerekir. Bir sonraki bölümde oluşturma işlemini daha verimli hale getirmeye çalışalım.
Basit bir piyano klavyeyi verimli bir şekilde oluşturun
Her beyaz tuş birbirinden biraz farklı bir şekle sahip olsa da, bunların tümü üst kısım ve alt kısım birleştirilerek oluşturulabilir. Şimdi herhangi bir beyaz anahtar oluşturmak ve konumlandırmak için genel bir işlev uygulayalım.
aşağıdaki işlevi işlevinin dışına
createScene()
scene.jsekleyin: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, ise
props.type
"white"
beyaz anahtar oluşturan ve döndüren adlıbuildKey()
bir işlev oluşturduk. parametresindekiprops
anahtarın türünü tanımlayarak, if-deyimini kullanarak dallanarak aynı işlevde hem siyah hem de beyaz anahtarlar oluşturabiliriz.parametreleri
buildKey()
şunlardır:- sahne: anahtarın içinde olduğu sahne
- parent: ağın üst öğesi (bu, tüm anahtarları tek bir üst öğe olarak gruplandırmamızı sağlar)
- props: oluşturulacak anahtarın özellikleri
props
Beyaz anahtar için aşağıdaki öğeleri içerir:- type: "white"
- name: anahtarın temsil ettiği notun adı
- topWidth: üst kısmın genişliği
- bottomWidth: alt kısmın genişliği
- topPositionX: Üst kısmın alt bölüme göre x konumu
- wholePositionX: Yazmaç bitiş noktasına göre tüm anahtarın x konumu (B anahtarının sağ kenarı).
- register: anahtarın ait olduğunu kaydedin (0 ile 8 arasında bir sayı)
- referencePositionX: Yazmaç uç noktasının x koordinatı (başvuru noktası olarak kullanılır).
ve değerlerini ayırarak
wholePositionX
, herhangi bir yazmaç içinde belirli bir anahtar türü (örn. C) oluşturmak için gereken parametreleri başlatabiliyorprops
ve bu anahtarı belirli bir yazmaçta oluştururken (örn. C4, C5) üzerine veprops
referencePositionX
ekliyoruzregister
.referencePositionX
Benzer şekilde, siyah anahtar oluşturmak için genel bir işlev de yazabiliriz. Şimdi işlevi bu mantığı içerecek şekilde genişletelim
buildKey()
: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; } }
props
Siyah anahtar için aşağıdaki öğeleri içerir:- type: "black"
- name: anahtarın temsil ettiği notun adı
- wholePositionX: Yazmaç bitiş noktasına göre tüm anahtarın x konumu (B anahtarının sağ kenarı)
- register: anahtarın ait olduğunu kaydedin (0 ile 8 arasında bir sayı)
- referencePositionX: Yazmaç uç noktasının x koordinatı (başvuru noktası olarak kullanılır).
props
Siyah anahtar oluşturma işlemi çok daha basittir çünkü siyah anahtar oluşturmak yalnızca bir kutu oluşturmayı içerir ve her siyah anahtarın genişliği ve z konumu aynıdır.Artık anahtarları oluşturmanın daha verimli bir yoluna sahip olduğumuza göre, yazmaçtaki bir nota karşılık gelen her tuş için öğesini depolayan
props
bir dizi başlatalım ve ardından 4. yazmacında basit bir klavye oluşturmak için her biriyle işlevini çağıralımbuildKey()
.Ayrıca, tüm piyano tuşlarının ebeveyni olarak hareket etmek için adlı
keyboard
bir TransformNode oluşturacağız. Üst öğeye uygulanan herhangi bir konum veya ölçeklendirme değişikliği de çocuklara uygulanacağı için anahtarları bu şekilde gruplandırmak, anahtarları bir bütün olarak ölçeklendirmemize veya taşımamıza olanak sağlar.İşleve aşağıdaki kod satırlarını
createScene()
ekleyin: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)); })
Muhtemelen fark ettiğiniz gibi, bu kod bloğunda tüm anahtarları alanın kaynağına göre yerleştiriyoruz.
scene.jsşu ana kadar içerdiği kod aşağıdadır:
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; }
Sonuçta elde edilen klavye şöyle görünür:
88 tuşlu piyanoya genişletiliyor
Bu bölümde, tam 88 tuşlu bir piyano klavyesi oluşturmak için tuş oluşturma işlevlerinin kullanımını genişletelim.
Daha önce belirtildiği gibi, tam, 88 tuşlu bir piyano klavyesi 7 tekrarlı yazmaç ve 4 nota daha içerir. Bu ek notların 3'ünün yazmaç 0'da (klavyenin sol ucu) ve 1'i yazmaç 8'de (klavyenin sağ ucu) bulunur.
İlk olarak daha önce yazdığımız döngüye ek bir döngü ekleyerek 7 tam yinelemeyi oluşturmaya çalışacağız. işlevinin ö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 yazmaç anahtarlarını derleyeceğiz ve bir sonraki yazmaçta her geçişte başvuru konumunu artıracağız.
Şimdi diğer anahtarları oluşturalım. İşleve aşağıdaki kod parçacığını
createScene()
ekleyin:// 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 klavyesinin en sol ve en sağdaki tuşunun içinde tanımlanan props boyutlarına uymadığını unutmayın (kenarda
keyParams
siyah bir tuşun yanında olmadıkları için), bu nedenle her biri için özel şekillerini belirtmek üzere yeniprops
bir nesne tanımlamamız gerekir.Oluşturulan klavye, değişiklikler yapıldıktan sonra aşağıdaki gibi görünmelidir:
Piyano çerçevesi ekleme
Alanda yalnızca bir klavyenin dolaştığınız sahne biraz garip görünüyor. Şimdi bir standup piyano görünümü oluşturmak için klavyenin çevresine bir piyano çerçevesi ekleyelim.
Anahtarları nasıl oluşturduğumuza benzer şekilde, bir grup kutu kısa çizgisini konumlandırıp birleştirerek çerçeveyi de oluşturabiliriz.
Ancak, bu sınamayı kendi başınıza denemeniz ve BABYLON kullanmanız için bırakacağız . SahneYükleyici.ImportMesh standup piyano çerçevesi önceden yapılmış bir örgü içeri aktarmak için. Bu kod parçasını sonuna
createScene()
ekleyin:// 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; });
Yine klavyeyi ve çerçeveyi bir bütün olarak gruplandırmak için adlı
piano
bir üstTransformNode
öğe oluşturduğumuza dikkat edin. Bu, gerekirse piyanonun tamamını taşımayı veya ölçeklendirmeyi çok daha kolay hale getirir.Çerçeve içeri aktarıldıktan sonra, klavyenin çerçevenin en altında olduğuna dikkat edin (tuşların y koordinatları varsayılan olarak 0'dır). Şimdi klavyeyi, standup piyano çerçevesine sığacak şekilde kaldıralım:
// Lift piano keys keyboard.position.y += 80;
Tüm piyano tuşlarının ebeveyni olduğundan
keyboard
, sadece y konumunu değiştirerek tüm piyano tuşlarınıkeyboard
kaldırabiliriz.scene.js son kodu şu şekilde 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://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; }
Şimdi şuna benzeyen bir standup piyanomuz olmalı: