由頭部開始
由於很多現時的 Vtuber 並不能像四大天王那樣投入這麼多錢到全身追蹤的 捕捉技術,所以很大部分現在的 Vtuber 都只是依賴臉部表情捕捉 + 手動更改臉部表情而成的半 3D Vtuber 系統。當然,這種東西要做的話很簡單,隨便買一個 Face Tracking 的 SDK 來用就好。然而,基於開源計劃的原則,這方法行不通。這個時候我們就要自已幹一套出來了。
Face-api.js
https://github.com/justadudewhohacks/face-api.js/
FaceAPI.js 是一個使用 Neural Network (神經網絡)而編寫的臉部捕捉 API。話雖如此,它卻內置了很多不同的 Network Model (模型)來做同一件事情。而在這個開源計劃中我看上了這個功能:Face Landmark Detection
動態捕捉及 VRM 模型動作 映射演算法
簡單來說,這功能把捕捉到的臉部一些重要的點找出來,之後我們便可以對這些點進行後處理。當然,這模型只會回傳平面的位置或(x, y)值,因此,我們需要把它轉成 3D 位置,這就需要一點演算法了。
首先,我們先看看 FaceLandmarks68 模型的回傳值
然後對比一下臉部移動的時候的捕捉位置,我們很容易會發現幾個特點
- 第 1點跟第 17點之間的距離除了前後移動之外基本上不會改變
- 第 1點跟第 9點之間的垂直距離會跟據你頭部上下望而產生線性變化
- 第在第 3跟 15點間畫一條直線,在頭部旋轉的時候第 31點會按比例的在這條直線上滑動
就是這樣,基本上我們就能確定怎樣判斷頭部移動和旋轉的方向了。
我們在取得比較點在最高及最低值的位置之後把其 歸一化 (Normalize),就能得出頭部的 變換/旋轉矩陣 (Transformation / Rotation Matrix)。
所牌結合上述多個計算方法,頭部的 3D移動及旋轉就被計算出來了。根據捕捉到的頭部動態,使 VRM 模型的頭部骨架也跟隨著移動,最後便形成以下的效果。
自動眨眼
以 FaceAPI 的準確率來說要檢測到貶眼實在不太可能了。所以這裡就使用了自動眨眼功能。然而你可能想,這要寫應該不難吧?就這樣加個 setInterval() 就好了?不,你太少看 VRM 的麻煩程度了。
我這裡給大家看一下只是控制一個 VRM 模型眨眼的部分
function createEyeBlinkBlendValueFromCycle(s){
//Eclipse time to sin function
const scaleRatio = 2;
const eyeCloseIntervalScale = 0.18;
if (eyeBlinking){
if (eyeBlinkingTimer[0] == 0){
//Start to blink
eyeBlinkingTimer[0] = s;
return 0;
}else{
//Blinking in progress
eyeBlinkingTimer[1] += s - eyeBlinkingTimer[0]
eyeBlinkingTimer[0] = s;
}
s = Math.sin( Math.PI * eyeBlinkingTimer[1] * scaleRatio);
s = s * 3;
var baseFormula = Math.min(s, 1);
//console.log([baseFormula,s, eyeBlinkingTimer[1]]);
if (baseFormula < 0){
eyeBlinking = false;
eyeBlinkingTimer = [0,0];
}else if (s > 1){
//Eye closed. Give it a blink interval skip
eyeBlinkingTimer[1] += eyeCloseIntervalScale;
}
return baseFormula;
}else{
return 0;
}
}
然後人類一般眨眼時間間距為 2 – 10秒,為了做到讓 VRM 模型眨眼更真實,這個隨機眨眼的功能也是必須的。
function blinkEye(){
eyeBlinking = true;
setTimeout(function(){
blinkEye();
},getRandomInt(2000,10000));
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
沒錯,要做到真實的眨眼是一點都不容易的。就只是要眨個眼而已就已經碰到好幾個 timer 跟 radian 角度的運算,真是少一點數學根基都不行。
小結
怎樣,是不是開始有一點像真呢?
然而,這可是有一個問題:運算需求太大了。
沒錯,一塊筆電的 i7 處理器的顯卡居然被吃到 100% 使用率,散熱口噴著快要能把雞蛋煮熟的熱風,實在太恐怖了啦!
那頭部的控制部分就先到裡了,之後就是更困難的身體捕捉部分喔~