iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Modern Web

WebXR未來新視界:Babylon.js打造Web的VR/AR/XR體驗系列 第 12

[Day12] 讓世界動起來:Babylon.js 的基本動畫,讓車子動起來(Feature - 單元三)

  • 分享至 

  • xImage
  •  

Feature單元三 Village Animation:讓3D世界動起來

所謂動畫我們知道是由一幀幀(frame)所組成:

https://ithelp.ithome.com.tw/upload/images/20250922/2010399066BndfXxts.png

Babylon.js 也像定格動畫一樣,需要設定每一幀,並設定如何變化、時間和循環。以下列出一些在關於動畫的文件中會提到的用語:

  • Performer - 一個可以進行動畫處理的物體。
  • Frame - 動畫的幀,不是渲染的幀。
  • Animation - 如何運動的劇本,但只適用於Performer 的一個屬性像是:
    • 要改變的屬性,例如位置、強度或旋轉
    • 屬性的變化率(以每秒幀數為單位)
    • 被改變的屬性的類型,例如向量、浮點數或矩陣
    • 循環條件
    • 關鍵影格處的屬性的關鍵值。
  • Scripted Performer - performer加上所有附加在他身上的動畫.
  • Performance - 一個活化物件,指可進行動畫的整體動畫物件,包含Scripted Performer以及所有依照腳本的動作。
  • Clip - 從一段較長的動畫中截取出的一小片段。
  • Cartoon - 一個由多個Clips,編排剪輯在一起,最終呈現給觀眾的一個連貫的片段。

在上篇有練習過基礎模型模型組裝。在這個單元中,官網教學的前半部分其是有示範如何組裝一台車子的一些組裝技巧。但我想本篇重點應該放在如何讓3D 世界動起來。所以我們直接從做好的車子模型,要讓輪子動起來開始。

讓輪子轉

首先,先來看單顆輪子,輪子是一個扁扁的圓柱體,並在圓形那面貼上車輪的圖片;柱面則是運用兩個座標在同一點來使用該點的顏色(wheelUV[1]的部分):

    //wheel face UVs
    const wheelUV = [];
    wheelUV[0] = new BABYLON.Vector4(0, 0, 1, 1);
    wheelUV[1] = new BABYLON.Vector4(0.5, 0, 0.5, 0);
    wheelUV[2] = new BABYLON.Vector4(0, 0, 1, 1);

    const wheelMat = new BABYLON.StandardMaterial("wheelMat");
    wheelMat.diffuseTexture = new BABYLON.Texture("https://assets.babylonjs.com/environments/wheel.png");

    wheelRB = BABYLON.MeshBuilder.CreateCylinder("wheelRB", {diameter: 0.125, height: 0.05, faceUV: wheelUV})
    wheelRB.material = wheelMat;

接下來要宣告動畫,用Animation並帶上參數-名稱、動畫屬性、每秒動畫幀數、動畫類型屬性、循環模式。

const animWheel = new BABYLON.Animation("wheelAnimation", "rotation.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

接著宣告一個變數來裝關鍵影格Array,並與上面的宣告的動畫變數animWheel連結起來,並告訴她開始動畫效果,讓這一顆輪子就會轉起來:

const wheelKeys = [];

// At the animation key 0, the value of rotation.y is 0
wheelKeys.push({
  frame: 0,
  value: 0,
});

// At the animation key 30, (after 1 sec since animation fps = 30) the value of rotation.y is 2PI for a complete rotation
wheelKeys.push({
  frame: 30,
  value: 2 * Math.PI,
});

  // set the keys 
  animWheel.setKeys(wheelKeys);

  // Link this animation to a wheel
  wheelRB.animations = [];
  wheelRB.animations.push(animWheel);

  scene.beginAnimation(wheelRB, 0, 30, true);

接著我們來設定把車子的輪子轉起來

這是一個組裝好但還不會動的車子模型

把剛剛上方把輪子動起來相關的東西都放進去之後,按下執行會跳出錯誤訊息提示我們沒宣告wheelRB

image.png

因此在上方加上wheelRB

     const wheelRB = scene.getMeshByName("wheelRB");
    

就能順利看到一顆輪子在轉動了。舉一反三,所以另外三個輪子也要與宣告的動畫連結起來,也個別告訴他們要跑起來。

 // 宣告在wheelRB 的下方,
  const wheelRF = scene.getMeshByName("wheelRF");
  const wheelLB = scene.getMeshByName("wheelLB");
  const wheelLF = scene.getMeshByName("wheelLF");

	// 個別也都要加上
  wheelRF.animations.push(animWheel);
  wheelLB.animations.push(animWheel);   
  wheelLF.animations.push(animWheel);

  scene.beginAnimation(wheelRF, 0, 30, true);
  scene.beginAnimation(wheelLB, 0, 30, true);
  scene.beginAnimation(wheelLF, 0, 30, true);

到這邊由於又有汽車模型又有動畫,所以先將汽車儲存為模型並將其作為專案導入和製作動畫。變成簡化版的:

BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "car.babylon").then(() =>  {
      const wheelRB = scene.getMeshByName("wheelRB");
      const wheelRF = scene.getMeshByName("wheelRF");
      const wheelLB = scene.getMeshByName("wheelLB");
      const wheelLF = scene.getMeshByName("wheelLF");
      console.log(wheelRB.animations)
      scene.beginAnimation(wheelRB, 0, 30, true);
      scene.beginAnimation(wheelRF, 0, 30, true);
      scene.beginAnimation(wheelLB, 0, 30, true);
      scene.beginAnimation(wheelLF, 0, 30, true);
    });

https://playground.babylonjs.com/#KDPAQ9#15

讓車子行駛在剛剛的村莊中吧

車子輪子在轉動了,現在來幫他加上位移,讓他看起來能像真的跑起來,並在村莊裡移動。這次我們改先從playground看程式碼,再來解析做法了。

!注意: frame必須是升序的

https://playground.babylonjs.com/#KDPAQ9#17

        const car = scene.getMeshByName("car");
        car.rotation = new BABYLON.Vector3(Math.PI / 2, 0, -Math.PI / 2);
        car.position.y = 0.16;
        car.position.x = -3;
        car.position.z = 8;

        const animCar = new BABYLON.Animation("carAnimation", "position.z", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

        const carKeys = []; 

        carKeys.push({
            frame: 0,
            value: 8
        });

        carKeys.push({
            frame: 150,
            value: -7
        });

        carKeys.push({
            frame: 200,
            value: -7
        });

        animCar.setKeys(carKeys);

        car.animations = [];
        car.animations.push(animCar);

        scene.beginAnimation(car, 0, 200, true);

大多數的時候,我們不會從頭組裝建立模型,大多會用匯入的方式,而動畫效果也會在skeleton中,像是這樣用法,方法很單純如下:

    BABYLON.ImportMeshAsync("/scenes/Dude/Dude.babylon", scene).then((result) => {
        var dude = result.meshes[0];
        dude.scaling = new BABYLON.Vector3(0.25, 0.25, 0.25);
                
        scene.beginAnimation(result.skeletons[0], 0, 100, true, 1.0);
    });

https://playground.babylonjs.com/#SFW46K#1371

最後一節是演示一個迴圈的劇本,讓剛剛載入的路人模型,可以在村莊裡走動並轉彎。目前只要知道可以這麼使用就可以了:

https://playground.babylonjs.com/#KBS9I5#81

總結與補充這單元幾個新語法

動畫是由一幀幀的畫面連結而成,所以在設定畫面的數組的時候,frame必須是升序的。

Animation 會帶上4個參數-

  1. 名稱
  2. 動畫屬性-物體屬性,要更新的內容
  3. 每秒動畫幀數
  4. 動畫類型屬性、循環模式。可能的數值有:
    • 浮點數BABYLON.Animation.ANIMATIONTYPE_FLOAT
    • 二維向量BABYLON.Animation.ANIMATIONTYPE_VECTOR2
    • 三維向量BABYLON.Animation.ANIMATIONTYPE_VECTOR3
    • 四元數BABYLON.Animation.ANIMATIONTYPE_QUATERNION
    • 矩陣BABYLON.Animation.ANIMATIONTYPE_MATRIX
    • 顏色 BABYLON.Animation.ANIMATIONTYPE_COLOR3

宣告動畫後要記得加到對象中,並執行動畫。

補充還可以這樣操作:

var newAnimation = scene.beginAnimation(car, 0, 200, true);
newAnimation.pause();暫停
newAnimation.restart();重新開始
newAnimation.stop();停止
newAnimation.reset();重製

更多詳細Animation文件


上一篇
[Day11] 用Babylon.js基礎模型組裝模型時常用的操作(Feature - 單元二)
系列文
WebXR未來新視界:Babylon.js打造Web的VR/AR/XR體驗12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言