Stories

Detail Return Return

vue3中實現live2D技術的應用虛擬角色數字人live2d-render、pixi-live2d-display - Stories Detail

什麼是live2D技術?可以用來做什麼?

請點擊看效果:http://ashuai.work:8890/#/16

簡而言之:

  • 可以用來創建虛擬角色、數字人的技術
  • 達到類似於動漫、插畫、遊戲中的人物效果
  • 可動作交互、語音發聲
  • 可以用到的平台很多,比如Web、Native、Unity、遊戲引擎、JAVA等平台
  • 就前端而言,3D項目使用threejs,2D項目使用pixijs
  • 所以,pixijs搭配live2D就可以在我們的頁面上實現一個虛擬角色、數字人、或者説看板娘技術
附上維基百科的介紹:https://zh.wikipedia.org/wiki/Live2D

如下圖:

或(類似博客園的看板娘)

live2d的應用之live2d-render插件

  • live2d技術實現的一個個人物、動物模型
  • 所以,首先,我們要搞到一些人物的模型數據文件

關於live2d的模型數據文件

  • live2d模型數據就是由繪畫師提前通過live2d的官方製作建模軟件搞出來的
  • 繪畫師提前製作出的人物、動物
  • 給人物添加外型、輪廓、衣服
  • 再把人物數據導出一個文件夾,文件夾中主要是一個個文件(JSON文件為主)
  • github或者嗶哩嗶哩上有不少以往的模型文件
  • 當然,官方也提供了一些模型文件給我們學習使用
  • 這裏,要注意他們的Licence 的使用範圍
  • 官方模型免費下載:https://www.live2d.com/zh-CHS/learn/sample/
  • 如下圖:

  • 模型下載解壓以後,得到對應文件夾中的模型數據

上述文件夾文件,分別是代表人物模型的數據意思為:

  • kei\_basic\_free.2048 人物衣服材質素材
  • motions 預設的人物動作等
  • sounds 人物自帶默認音效
  • .moc3文件是核心模型數據(二進制)
  • .motionsync3.json是動態同步設定文件
  • 等...
  • 我們要關注kei\_basic\_free.model3.json這個文件
  • 這個是引入此模型文件的入口文件
這個模型文件比較少一些,有些豐富人物的模型,還有expressions表情文件夾(存放的預設好的喜怒哀樂等數據...)

live2d-render插件

官方的live2d相關的api比較繁雜,上手成本高一些,筆者簡單調研後,找到了兩個還不錯的封裝庫

先説簡單一些的live2d-render插件的使用

第0步,下載live2d的sdk

  • 下載地址:https://www.live2d.com/zh-CHS/sdk/download/web/
  • 因為是web項目,所以下載這個版本
  • 打開頁面,滑動到最底下
  • 下載圖示

第1步,把下載好的live2d的sdk存放在public文件夾中,再在index.html文件中使用script引入

第2步,下載live2d-render插件

  • npm install live2d-render --save
  • 筆者用的是這個版本 "live2d-render": "^0.0.5"

第3步,搞一個.vue文件,把下列代碼複製粘貼進去

<template>
  <div>
    <h1>live2d-render</h1>
    <button @click="ccc">表情切換</button>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
import * as live2d from "live2d-render"; // 引入插件

onMounted(() => {
  init();
});

const init = async () => {
  await live2d.initializeLive2D({
    // live2d 所在區域的背景顏色
    BackgroundRGBA: [0.0, 0.0, 0.0, 0.0],

    // live2d 的 model3.json 文件的相對 根目錄 的路徑
    // ResourcesPath: "/live2d/Haru/Haru.model3.json", // 成熟御姐
    // ResourcesPath: "/live2d/Hiyori/Hiyori.model3.json", // 可愛蘿莉
    ResourcesPath: "/live2d/Mao/Mao.model3.json", // 魔法女巫
    // ResourcesPath: "/live2d/Mark/Mark.model3.json", // 大眼睛呆萌男孩
    // ResourcesPath: "/live2d/Natori/Natori.model3.json", // 高挑帥氣西裝男
    // ResourcesPath: "/live2d/Rice/Rice.model3.json", // 白裙水手服女
    // ResourcesPath: "/live2d/Wanko/Wanko.model3.json", // 碗裏面有小狗

    // live2d 的大小
    CanvasSize: {
      height: 600,
      width: 400,
    },

    // 展示工具箱(可以控制 live2d 的展出隱藏,使用特定表情)
    ShowToolBox: false,

    // 是否使用 indexDB 進行緩存優化,這樣下一次載入就不會再發起網絡請求了
    LoadFromCache: true,
  });
};

const ccc = () => {
  live2d.setRandomExpression(); // 隨機切換表情
};
</script>

第4步,效果出來了哦

效果圖:

插件文檔地址:https://document.kirigaya.cn/docs/live2d-render/vue-install.html

上述代碼中,筆者提到了一些模型,包括code,都在筆者的github中。屆時直接去github上pull代碼即可,github倉庫地址在文末

接下來,我們使用pixi-live2d-display來做一個可以根據音頻説話的虛擬數字人角色

live2d的應用之pixi-live2d-display插件

關於pixi-live2d-display

  • github: https://github.com/guansss/pixi-live2d-display
  • 可惜少了點中文文檔,不過問題不大
  • 相對而言,這個庫的使用量還可以,更加推薦
  • 需要搭配pixi.js

需要注意版本:pixi.js 不能超過6

如下安裝:

npm i pixi-live2d-display@0.4.0 --save

npm i pixi.js@6.5.10 --save
關於pixi.js的中文文檔,可以看這裏:https://pixijs.huashengweilai.com/

簡單版代碼

不贅述,很簡單

<template>
  <div class="canvasWrap">
    <canvas id="myCanvas" />
  </div>
</template>

<script setup>
import { onMounted, onBeforeUnmount } from "vue";

import * as PIXI from "pixi.js";
import { Live2DModel } from "pixi-live2d-display/cubism4"; // 只需要 Cubism 4

window.PIXI = PIXI; // 為了pixi-live2d-display內部調用

let app; // 為了存儲pixi實例
let model; // 為了存儲live2d實例

onMounted(() => {
  init();
});

onBeforeUnmount(() => {
  app = null;
  model = null;
});

const init = async () => {
  // 創建PIXI實例
  app = new PIXI.Application({
    // 指定PixiJS渲染器使用的HTML <canvas> 元素
    view: document.querySelector("#myCanvas"),
    // 響應式設計
    resizeTo: document.querySelector("#myCanvas"),
    // 設置渲染器背景的透明度 0(完全透明)到1(完全不透明)
    backgroundAlpha: 0,
  });
  // 引入live2d模型文件
  model = await Live2DModel.from("/live2d/Haru/Haru.model3.json", {
    autoInteract: false, // 關閉眼睛自動跟隨功能
  });
  // 調整live2d模型文件縮放比例(文件過大,需要縮小)
  model.scale.set(0.12);
  // 調整x軸和y軸座標使模型文件居中
  model.y = 0;
  model.x = -24;
  // 把模型添加到舞台上
  app.stage.addChild(model);
};
</script>

<style lang="less" scoped>
#myCanvas {
  width: 240px;
  height: 360px;
}
</style>

效果圖:

讓人物説話——嘴唇動彈

  • 使用庫提供的api
  • model.internalModel.coreModel.setParameterValueById("ParamMouthOpenY", n)
  • 這裏的n介於0\~1之間,表示嘴唇開合的幅度
  • 所以我們可以這樣寫:
  • 點擊按鈕後,讓人物嘴唇不斷變化
<button @click="mouthFn">嘴型變換</button>

const mouthFn = () => {
  setInterval(() => {
    let n = Math.random();
    console.log("隨機數0~1控制嘴巴Y軸高度-->", n);
    model.internalModel.coreModel.setParameterValueById("ParamMouthOpenY", n);
  }, 100);
};

效果圖:

踩坑之模型嘴唇不變化

  • 官方提供的第一個模型,是不會出現這個問題的

  • 但是,有些模型有原本預設的嘴唇變化幅度邏輯,或其他情況,導致會出現這個語句不生效的情況
  • model.internalModel.coreModel.setParameterValueById("ParamMouthOpenY", n)
  • 以haru模型為例:
  • 這個時候,我們需要在motions/haru\_g\_idle.motion3.json文件中做如下更改

  • 這樣就能夠解決問題了
至此,數字人已經可以張嘴説話了,不過還沒有聲音,接下來讓聲音播放即可。筆者翻閲資料,找到了一個方案如下

使用AudioContext播放聲音,並轉成音頻頻譜做分析,再轉成音量大小,從而控制嘴唇的開合大小

如下代碼:

<button @click="speakFn">人物説話</button>

const speakFn = async () => {

  // 請求加載一個音頻文件
  const response = await fetch(audioFile);
  // 將音頻讀取為原始的二進制數據緩衝區(ArrayBuffer)。音頻本身是二進制格式,要先將其加載為 ArrayBuffer 才能進一步處理
  const audioData = await response.arrayBuffer();
  // 將 ArrayBuffer 格式的音頻數據解碼成 AudioBuffer 對象,可以直接用於播放或處理音頻數據。
  const audioBuffer = await audioContext.decodeAudioData(audioData);
  // 創建一個音頻源節點(AudioBufferSourceNode),該節點用於播放音頻數據
  const source = audioContext.createBufferSource();
  // 創建一個音頻分析節點。這個節點用於實時分析音頻數據,提供諸如頻譜分析、波形分析等功能
  const analyser = audioContext.createAnalyser();
  // 將之前解碼得到的 audioBuffer(即音頻數據)賦值給 source 節點的 buffer 屬性。這樣就將加載的音頻文件與 source 節點綁定,準備播放。
  source.buffer = audioBuffer;
  //  將 音頻分析節點 連接到音頻上下文的最終目標(即揚聲器)
  analyser.connect(audioContext.destination);
  // 音頻分析節點 將能夠分析通過音頻源流動的音頻數據,並提供頻譜或其他音頻信息。
  source.connect(analyser);

  // 監聽音頻播放完畢
  let requestId = null;
  source.onended = function () {
    cancelAnimationFrame(requestId); // 清除請求動畫幀
    model.internalModel.coreModel.setParameterValueById("ParamMouthOpenY", 0); // 閉上嘴巴
  };
  /**
   * 啓動音頻源的播放,從頭開始(這樣的話,頁面就能夠聽到聲音了)
   * 接下來需要讓人物嘴巴更新動彈,即有聲音的同時,且能夠説話
   * 即為:updateMouth函數
   * */
  source.start(0);

  /**
   * 這個 updateMouth 函數通過從 analyser 獲取音頻數據並計算音量,動態地更新一個模型的嘴巴張開程度。它的實現方式是每幀都更新一次,
   * 通過音頻的音量強度來決定嘴巴的開合程度,從而實現與音頻的實時互動。
   * */
  const updateMouth = () => {
    // analyser.frequencyBinCount 表示音頻頻譜的 bin(頻率段)的數量。它是一個整數,表示從頻率數據中可以獲取多少個頻率段的值
    // 使用 analyser 對象的 getByteFrequencyData 方法填充 dataArray 數組。
    // getByteFrequencyData 將音頻的頻率數據轉化為 0-255 範圍內的字節值,並存儲在 dataArray 中。這個數據表示了音頻信號在不同頻率範圍內的強度。
    // 該方法會將頻譜分析的結果填充到 dataArray 數組中,每個元素代表一個頻率段的音量強度。
    // 使用 reduce 方法計算 dataArray 數組的所有值的總和,並通過除以數組長度來求得平均值。這個平均值表示音頻信號的總體“強度”或“音量”。
    // 這裏的 a + b 累加所有音頻頻段的強度值,最終計算出一個平均值。
    // dataArray.length 是頻率數據的總數,通常它等於 analyser.frequencyBinCount。
    // 將計算出的 volume 除以 50,以縮放它到一個合適的範圍,得到一個表示“嘴巴張開程度”的值。volume 越大,mouthOpen 越大。
    // 使用 Math.min(1, volume / 50) 保證 mouthOpen 的值不會超過 1,也就是説嘴巴張開程度的最大值是 1。
    // 這意味着,如果音量足夠大,mouthOpen 會接近 1,表示嘴巴完全張開;如果音量較小,mouthOpen 會接近 0,表示嘴巴幾乎沒張開。
    const dataArray = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(dataArray);
    const volume = dataArray.reduce((a, b) => a + b) / dataArray.length;
    const mouthOpen = Math.min(1, volume / 50);

    // 通過調用 setParameterValueById 方法,將 mouthOpen 的值傳遞給 model 的內部模型(控制嘴巴大小張開幅度)
    model.internalModel.coreModel.setParameterValueById("ParamMouthOpenY", mouthOpen);
    requestId = requestAnimationFrame(updateMouth);
  };

  requestId = requestAnimationFrame(updateMouth);
};
這樣的話,數字人就能夠張口説話了,話説完,再讓數字人閉嘴即可

踩坑之數字人動作自動切換導致人物不張嘴説話了

  • 筆者的理解是:
  • 數字人有的預設好幾個動作
  • 在一段時間內自動循環播放動作切換
  • 當A動作切換到B動作時候
  • 會導致處於A動作開口動作被覆蓋
  • 這裏需要設置動作的權重(pixi-live2d-display文檔中也有,需要自行探索)
  • 筆者是直接刪除那個多餘的動作,只保留一個動作
  • 就不會出現這個問題了😅😅😅
  • 如下圖示,修改.model3.json文件即可

github倉庫

  • 倉庫代碼:https://github.com/shuirongshuifu/vue3-echarts5-example
  • 此倉庫會寫一些實用性高點的demo,歡迎大家給個star哦😄

參考資料文檔博客

  • 二次元live2d看板娘效果中的web前端技術:https://www.zhangxinxu.com/wordpress/2018/05/live2d-web-webgl...
  • 視頻資源:https://www.bilibili.com/opus/829185827836788806
  • 語音口型同步:https://github.com/itorr/itorr/issues/7
  • 模型下載方式:https://blog.csdn.net/qq_36303853/article/details/142284330
  • 一個模型很多的庫:https://imuncle.github.io/live2d/live2d_3/
user avatar hushuosha Avatar minnanitkong Avatar windseek Avatar gssggssg Avatar viggoz Avatar ddup365 Avatar ethanprocess Avatar nut Avatar ohaha Avatar changqingdeyema_cy7lds Avatar daishuyunshuzhanqianduan Avatar cafehaus Avatar
Favorites 18 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.