babylon.js 學習筆記(3)

一、理解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

 

BABYLON.Vector3(x,y,z) 是一個很重要的對象,不僅能用於設置對象的位置,還能控制縮放大小,以及旋轉角度。
//方塊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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章