按上回繼續,上節知道了如何用 『方塊+三棱柱+貼圖』結合起來,畫一個簡單的小房子,實際應用中可以把這3個打包在一起,組成1個house對象,這樣更方便一些
const buildHouse = () => { const box1 = buildBox(); const roof1 = buildRoof(); const house1 = BABYLON.Mesh.MergeMeshes([box1, roof1]); house1.position.x = -0.4; const box2 = buildBox(); const roof2 = buildRoof(); const house2 = BABYLON.Mesh.MergeMeshes([roof2, box2]); house2.position.x = 0.4; return [house1, house2]; }
關鍵在於BABYLON.Mesh.MergeMeshes 這個方法,可以把幾個mesh對象組合成1個新mesh對象,來看看效果:
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/01.html
貼圖效果並不符合預期,[obj1, obj2...] 最終排在第1個位置的對象,其貼圖應用到了整個對象上。好在MergeMeshes方法,還有其它擴展參數,其完整方法簽名如下:
改成這樣就可以了:
const buildHouse = () => { const box = buildBox(); const roof = buildRoof(); //將box與roof組合 // MergeMeshes(meshes: Mesh[], disposeSource?: boolean, allow32BitsIndices?: boolean, meshSubclass?: Mesh, subdivideWithSubMeshes?: boolean, multiMultiMaterials?: boolean): Nullable<Mesh> return BABYLON.Mesh.MergeMeshes([box, roof], true, false, null, true, true); }
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/02.html
在進入下面的內容前,先把代碼再整理下:
//創建屋頂 const buildRoof = (width) => { const roofMat = new BABYLON.StandardMaterial("roofMat"); roofMat.diffuseTexture = new BABYLON.Texture("../assets/img/roof.jpg"); const roof = BABYLON.MeshBuilder.CreateCylinder("roof", { diameter: 0.7, height: 0.6, tessellation: 3 }); roof.scaling.x = 0.75; roof.scaling.y = width; roof.rotation.z = Math.PI / 2; roof.position.y = 0.63; roof.material = roofMat; return roof; } //創建屋身 const buildBox = (width) => { const boxMat = new BABYLON.StandardMaterial("boxMat"); const faceUV = []; if (width == 1) { boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/cubehouse.png") faceUV[0] = new BABYLON.Vector4(0.5, 0.0, 0.75, 1.0); //後面 faceUV[1] = new BABYLON.Vector4(0.0, 0.0, 0.25, 1.0); //前面 faceUV[2] = new BABYLON.Vector4(0.25, 0, 0.5, 1.0); //右面 faceUV[3] = new BABYLON.Vector4(0.75, 0, 1.0, 1.0); //左面 } else { boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/semihouse.png") faceUV[0] = new BABYLON.Vector4(0.6, 0.0, 1.0, 1.0); //後面 faceUV[1] = new BABYLON.Vector4(0.0, 0.0, 0.4, 1.0); //前面 faceUV[2] = new BABYLON.Vector4(0.4, 0, 0.6, 1.0); //右面 faceUV[3] = new BABYLON.Vector4(0.4, 0, 0.6, 1.0); //左面 } const box = BABYLON.MeshBuilder.CreateBox("box", { size: 0.5, width: 0.5 * width, faceUV: faceUV, wrap: true }); box.material = boxMat; box.position.y = 0.25; return box; } //根據傳入的參數width,生成2種不同風格的房屋 const buildHouse = (width) => { const box = buildBox(width); const roof = buildRoof(width); return BABYLON.Mesh.MergeMeshes([box, roof], true, false, null, true, true); } //在這裏添加自己的核心代碼 const createScene = function () { const scene = new BABYLON.Scene(engine); const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 3, new BABYLON.Vector3(0, 0, 0)); camera.attachControl(canvas, true); const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0.5, 0.5, 0)); const ground = buildGround(); //創建房子 const house1 = buildHouse(1); const house2 = buildHouse(2); house1.position.x = -0.5 house2.position.x = 0.5 return scene; };
這樣buildHouse(width)方法,根據width值的不同,可以生成2種不同風格的房屋
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/03.html
接下來,我們畫1片住宅區(也就是要有一堆房屋),這裏就要用到createInstance 這個方法:
//創建一片住宅區 const buildDwellings = () => { const ground = buildGround(); const detached_house = buildHouse(1); detached_house.rotation.y = -Math.PI / 16; detached_house.position.x = -6.8; detached_house.position.z = 2.5; const semi_house = buildHouse(2); semi_house.rotation.y = -Math.PI / 16; semi_house.position.x = -4.5; semi_house.position.z = 3; //定義房子的[風格/位置]列表 [house type, rotation, x, z] const places = []; places.push([1, -Math.PI / 16, -6.8, 2.5]); places.push([2, -Math.PI / 16, -4.5, 3]); places.push([2, -Math.PI / 16, -1.5, 4]); places.push([2, -Math.PI / 3, 1.5, 6]); places.push([2, 15 * Math.PI / 16, -6.4, -1.5]); places.push([1, 15 * Math.PI / 16, -4.1, -1]); places.push([2, 15 * Math.PI / 16, -2.1, -0.5]); places.push([1, 5 * Math.PI / 4, 0, -1]); places.push([1, Math.PI + Math.PI / 2.5, 0.5, -3]); places.push([2, Math.PI + Math.PI / 2.1, 0.75, -5]); places.push([1, Math.PI + Math.PI / 2.25, 0.75, -7]); places.push([2, Math.PI / 1.9, 4.75, -1]); places.push([1, Math.PI / 1.95, 4.5, -3]); places.push([2, Math.PI / 1.9, 4.75, -5]); places.push([1, Math.PI / 1.9, 4.75, -7]); places.push([2, -Math.PI / 3, 5.25, 2]); places.push([1, -Math.PI / 3, 6, 4]); //根據places建一堆房子 const houses = []; for (let i = 0; i < places.length; i++) { if (places[i][0] === 1) { houses[i] = detached_house.createInstance("house" + i); } else { houses[i] = semi_house.createInstance("house" + i); } houses[i].rotation.y = places[i][1]; houses[i].position.x = places[i][2]; houses[i].position.z = places[i][3]; } }
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/04.html
可以藉助playground把這片住宅區的所有對象都導出,方便後續複用,也能簡化代碼,參考下圖:
代碼可以簡化爲:
BABYLON.SceneLoader.ImportMeshAsync("", "../assets/glb/", "village.glb");
注意glb的目錄位置,參考下圖:
前面我們還學習過,可以直接用<babylon />將model嵌入網頁:
<div id="renderCanvas"> <h1>Village(import glb to page)</h1> <babylon model="../assets/glb/village.glb"></babylon> </div>
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/06.html
發現1個問題:綠色的ground一直在不停閃爍。要解決這個問題,可以加上extends="minimal"
<babylon model="../assets/glb/village.glb" extends="minimal"></babylon>
這回到是不閃了,但是頁面剛打開時,攝像機的視角比較奇怪,參考下圖:
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/07.html
可以再加一段腳本校正:
<div id="renderCanvas"> <h1>Village(import glb to page)</h1> <babylon extends="minimal" id="myViewer"></babylon> </div> <script> BabylonViewer.viewerManager.getViewerPromiseById('myViewer').then((viewer) => { viewer.onSceneInitObservable.add(() => { viewer.sceneManager.camera.radius = 15; viewer.sceneManager.camera.beta = Math.PI / 2.2; }); viewer.onEngineInitObservable.add((scene) => { viewer.loadModel({ url: "../assets/glb/village.glb" }); }); }); </script>
效果如下:
在線地址:https://yjmyzz.github.io/babylon_js_study/day04/08.html
參考文檔:
https://doc.babylonjs.com/features/introductionToFeatures/chap2/copies
https://doc.babylonjs.com/features/introductionToFeatures/chap2/viewer2