一、理解babylon.js 座標系
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(1, 1, 0)); //方塊1(靠左,靠下,靠前) const box1 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); //Vector(x,y,z) 表示x,y,z三軸的座標值 box1.position = new BABYLON.Vector3(-1, -0.199, -0.4); //方塊2(放在正中央) const box2 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box2.position = new BABYLON.Vector3(0, 0, 0); //方塊3(靠右,靠上,靠後) const box3 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box3.position = new BABYLON.Vector3(1, 0.2, 0.4); var ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 3, height: 1.5 }, scene); let groundMaterial = new BABYLON.StandardMaterial("Ground Material", scene); ground.material = groundMaterial; ground.material.diffuseColor = BABYLON.Color3.Black(); return scene; };
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/01.html
//方塊1(靠左,靠下,靠前) const box1 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); //Vector(x,y,z) 表示x,y,z三軸的座標值 box1.position = new BABYLON.Vector3(-1, -0.199, -0.4); box1.scaling = new BABYLON.Vector3(0.5, 1, 1); //方塊2(放在正中央) const box2 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box2.position = new BABYLON.Vector3(0, 0, 0); box2.scaling = new BABYLON.Vector3(1, 0.5, 1); //繞y軸轉45度 box2.rotation = new BABYLON.Vector3(0,Math.PI/4,0); //方塊3(靠右,靠上,靠後) const box3 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box3.position = new BABYLON.Vector3(1, 0.2, 0.4); box3.scaling = new BABYLON.Vector3(1, 1, 0.5); box3.rotation = new BABYLON.Vector3(-Math.PI/4,0,0);
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/02.html
二、畫1個簡單的小房子
如上圖,畫1個三棱柱,以及1個立方體,組合起來即可。但babylon.js中並沒有創建三棱柱的api,只能創建圓柱體,還記得前面學過的嗎?任何複雜的對象(即mesh),都是一堆小三角形及各種切面的組合,三角形數越多,最終的對象越逼真。當圓柱體的邊數設置爲3時,即退化成三棱柱。
//Cylinder的邊tessellation足夠大時,即爲圓柱形 const roof0 = BABYLON.MeshBuilder.CreateCylinder("roof0", {diameter: 1.3, height: 1.2, tessellation: 32},scene); roof0.position = new BABYLON.Vector3(-1,0.26,0); roof0.scaling = new BABYLON.Vector3(0.25,0.25,0.25); const roof1 = BABYLON.MeshBuilder.CreateCylinder("roof1", {diameter: 1.3, height: 1.2, tessellation: 32},scene); roof1.position = new BABYLON.Vector3(-0.5,0.26,0); roof1.scaling = new BABYLON.Vector3(0.25,0.25,0.25); //繞x軸轉90度 roof1.rotation = new BABYLON.Vector3(Math.PI / 2,0,0); //Cylinder的邊tessellation=3時,即爲三棱柱 const roof2 = BABYLON.MeshBuilder.CreateCylinder("roof2", {diameter: 1.3, height: 1.2, tessellation: 3},scene); roof2.position = new BABYLON.Vector3(0,0.24,0); roof2.scaling = new BABYLON.Vector3(0.4,0.4,0.4); roof2.rotation = new BABYLON.Vector3(0,Math.PI / 2,Math.PI / 2); //三棱柱+方塊,組合成1個簡單的房子 const roof = BABYLON.MeshBuilder.CreateCylinder("roof", {diameter: 1.3, height: 1.2, tessellation: 3},scene); roof.position = new BABYLON.Vector3(0.9,0.6,0); roof.scaling = new BABYLON.Vector3(0.4,0.4,0.4); roof.rotation = new BABYLON.Vector3(0,Math.PI / 2,Math.PI / 2); const box = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box.position = new BABYLON.Vector3(0.9, 0.24, 0); box.scaling = new BABYLON.Vector3(0.95, 1.2, 0.95);
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/03.html
樣子是有了,但是光禿禿的,比較難看,可以給它貼上壁紙,先找二張壁紙圖片:
//設置屋頂及屋身的貼圖材質 const roofMat = new BABYLON.StandardMaterial("roofMat"); roofMat.diffuseTexture = new BABYLON.Texture("../assets/img/roof.jpg", scene); const boxMat = new BABYLON.StandardMaterial("boxMat"); boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/floor.png"); roof.material = roofMat; box.material = boxMat;
在線地址: https://yjmyzz.github.io/babylon_js_study/day03/04.html
房子是有窗戶的,再來看看如何解決窗戶的問題,答案仍然是在貼圖上做文章,比如將下面這張帶窗戶的貼紙,在整個屋身上貼一圈即可
象不象某些地方的形象工程,哈
嘗試用這個新貼圖試一下:
//對比,畫1個方塊,用cubehouse貼圖 const box2 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4 }, scene); box2.position = new BABYLON.Vector3(1, 0.24, 0); box2.scaling = new BABYLON.Vector3(0.95, 1.2, 0.95); const boxMat2 = new BABYLON.StandardMaterial("boxMat2"); boxMat2.diffuseTexture = new BABYLON.Texture("../assets/img/cubehouse.png"); box2.material = boxMat2;
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/05.html
好象有哪裏不對,這看上去,象個快遞包裹^_~,讓我們想一想:
一般情況下,不用看屋身的底部和頂部(注:底部是綠色的大地,頂部被屋頂擋住了),所以可以將這張貼圖切爲4份,分別貼在屋身的前後左右。從CreateBox的API文檔知,有1個參數faceUV可以指定box每個面的貼圖:
faceUV可以使用Vector4對象做爲參數:
vector (lower left x, lower left y, upper right x, upper right y)
//屋身四面的貼圖座標 const faceUV = []; 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); //左面 ... const box2 = BABYLON.MeshBuilder.CreateBox("box", { size: 0.4,faceUV:faceUV }, scene); ...
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/06.html
爲了方便後面代碼複用,我們把創建地面、屋頂、屋身 這些基本邏輯,封裝一下:
//調整地面/屋頂/屋身的大小及位置 const adjust = (ground, roof, box) => { const scaling = new BABYLON.Vector3(0.5, 0.5, 0.5); ground.scaling = scaling; roof.scaling = scaling; box.scaling = scaling; box.position.y = ground.position.y + 0.25; roof.position.y = box.position.y + 0.4; box.position.x = -1; roof.position.x = box.position.x; } //創建地面 const buildGround = () => { const groundMat = new BABYLON.StandardMaterial("groundMat"); groundMat.diffuseColor = new BABYLON.Color3(0, 1, 0); const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 3 }); ground.material = groundMat; return ground; } //創建屋頂 const buildRoof = () => { const roofMat = new BABYLON.StandardMaterial("roofMat"); roofMat.diffuseTexture = new BABYLON.Texture("../assets/img/roof.jpg"); const roof = BABYLON.MeshBuilder.CreateCylinder("roof", { diameter: 1.3, height: 1.2, tessellation: 3 }); roof.material = roofMat; roof.scaling.x = 0.75; roof.rotation.z = Math.PI / 2; roof.position.y = 1.22; return roof; } //創建屋身 const buildBox = () => { const boxMat = new BABYLON.StandardMaterial("boxMat"); boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/cubehouse.png") const faceUV = []; 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); //左面 const box = BABYLON.MeshBuilder.CreateBox("box", { faceUV: faceUV, wrap: true }); box.material = boxMat; box.position.y = 0.5; return box; } //在這裏添加自己的核心代碼 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 roof = buildRoof(); const box = buildBox(); adjust(ground, roof, box); return scene; };
最後,再添加1種風格的房屋做爲本篇收場:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>A Basic House</title> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 50%; height: 50%; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; touch-action: none; } #canvasZone { width: 100%; height: 100%; } </style> <!-- 導入babylon核心功能 --> <script src="../js/babylon.js"></script> <!-- 允許scene中導入model --> <script src="../js/babylonjs.loaders.min.js"></script> <!-- 允許使用觸屏 --> <script src="../js/pep.js"></script> </head> <body> <canvas id="renderCanvas" touch-action="none"></canvas> <script> const canvas = document.getElementById("renderCanvas"); const engine = new BABYLON.Engine(canvas, true); //調整地面/屋頂/屋身的大小及位置 const adjust = (ground, roof, box) => { const scaling = new BABYLON.Vector3(0.5, 0.5, 0.5); ground.scaling = scaling; roof.scaling = scaling; box.scaling = scaling; box.position.y = ground.position.y + 0.25; roof.position.y = box.position.y + 0.4; box.position.x = -0.8; roof.position.x = box.position.x; } //調整-聯體別墅-地面/屋頂/屋身的大小及位置 const adjustSemiHouse = (ground, roof, box) => { const scaling = new BABYLON.Vector3(0.5, 0.5, 0.5); roof.scaling = scaling; box.scaling = scaling; box.position.y = ground.position.y + 0.25; roof.position.y = box.position.y + 0.4; box.position.x = 0.5; roof.position.x = box.position.x; } //創建地面 const buildGround = () => { const groundMat = new BABYLON.StandardMaterial("groundMat"); groundMat.diffuseColor = new BABYLON.Color3(0, 1, 0); const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 3 }); ground.material = groundMat; return ground; } //創建屋頂 const buildRoof = () => { const roofMat = new BABYLON.StandardMaterial("roofMat"); roofMat.diffuseTexture = new BABYLON.Texture("../assets/img/roof.jpg"); const roof = BABYLON.MeshBuilder.CreateCylinder("roof", { diameter: 1.3, height: 1.2, tessellation: 3 }); roof.material = roofMat; roof.scaling.x = 0.75; roof.rotation.z = Math.PI / 2; roof.position.y = 1.22; return roof; } //創建-聯體別墅-屋頂 const buildSemiHouseRoof = () => { const roof = BABYLON.MeshBuilder.CreateCylinder("roof", { diameter: 1.3, height: 2.2, tessellation: 3 }); roof.scaling.y = 0.75; roof.rotation.z = Math.PI / 2; roof.position.y = 1.22; const roofMat = new BABYLON.StandardMaterial("roofMat"); roofMat.diffuseTexture = new BABYLON.Texture("../assets/img/roof.jpg"); roof.material = roofMat; return roof; } //創建屋身 const buildBox = () => { const boxMat = new BABYLON.StandardMaterial("boxMat"); boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/cubehouse.png") const faceUV = []; 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); //左面 const box = BABYLON.MeshBuilder.CreateBox("box", { faceUV: faceUV, wrap: true }); box.material = boxMat; box.position.y = 0.5; return box; } //創建-聯體別墅-屋身 const buildSemiHouseBox = () => { const boxMat = new BABYLON.StandardMaterial("boxMat"); boxMat.diffuseTexture = new BABYLON.Texture("../assets/img/semihouse.png") const faceUV = []; faceUV[0] = new BABYLON.Vector4(0.6, 0.0, 1.0, 1.0); //rear face faceUV[1] = new BABYLON.Vector4(0.0, 0.0, 0.4, 1.0); //front face faceUV[2] = new BABYLON.Vector4(0.4, 0, 0.6, 1.0); //right side faceUV[3] = new BABYLON.Vector4(0.4, 0, 0.6, 1.0); //left side const box = BABYLON.MeshBuilder.CreateBox("box", { width: 2, height: 1, faceUV: faceUV, wrap: true }); box.material = boxMat; box.position.y = 0.5; return box; } //在這裏添加自己的核心代碼 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 roof = buildRoof(); const box = buildBox(); adjust(ground, roof, box); const roof2 = buildSemiHouseRoof(); const box2 = buildSemiHouseBox(); adjustSemiHouse(ground, roof2, box2); return scene; }; const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script> </body> </html>
在線地址:https://yjmyzz.github.io/babylon_js_study/day03/07.html
參考文檔:
https://doc.babylonjs.com/features/introductionToFeatures/chap2/variation