所謂動畫我們知道是由一幀幀(frame)所組成:
Babylon.js 也像定格動畫一樣,需要設定每一幀,並設定如何變化、時間和循環。以下列出一些在關於動畫的文件中會提到的用語:
在上篇有練習過基礎模型模型組裝。在這個單元中,官網教學的前半部分其是有示範如何組裝一台車子的一些組裝技巧。但我想本篇重點應該放在如何讓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
因此在上方加上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個參數-
宣告動畫後要記得加到對象中,並執行動畫。
補充還可以這樣操作:
var newAnimation = scene.beginAnimation(car, 0, 200, true);
newAnimation.pause();暫停
newAnimation.restart();重新開始
newAnimation.stop();停止
newAnimation.reset();重製