在Unity遊戲中使用Live2D
將進酒
君不見,黃河之水天上來,奔流到海不復回。君不見,高堂明鏡悲白髮,朝如青絲暮成雪。人生得意須盡歡,莫使金樽空對月。天生我材必有用,千金散盡還復來。烹羊宰牛且為樂,會須一飲三百杯。
岑夫子,丹丘生,將進酒,杯莫停。與君歌一曲,請君為我傾耳聽。鐘鼓饌玉不足貴,但願長醉不復醒。古來聖賢皆寂寞,惟有飲者留其名。陳王昔時宴平樂,斗酒十千恣歡謔。主人何為言少錢,徑須沽取對君酌。五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。
本文首發於Lohanrys Blog,轉載請註明。
實在沒辦法貼圖,只能上傳一張網路圖,侵權立刪。
什麼是Live2D
- Live2D是日本Cybernoids公司開發。
- Live2D現階段有兩個主要的版本是2.1的版本和3.0的版本。
- 國內2.1版本用的比較多(ps.此為自己的感覺,並沒有數據支持,只是感覺國內討論的比較多的就是2.1了)。
- 大家可以到官網去下載2.1版本,由於3.0版本的無法支持當前項目的Unity版本,所以暫時沒有使用。
Unity中的Live2D
Live2D已經增加的了對Unity的支持,所以只需要將SDK下載下來後倒入就可以使用了,裡面也有幾個簡單的例子可以直接跑。
本文討論的是Unity中使用Live2D,對Live2D的製作不做任何討論。
我們可以從Live2D導出的文件中看到如下標準格式:
Live2D資源包
- model.1024文件夾中放的是人物的模型貼圖,由於多貼圖導致DrawCall升高的,所以在遊戲中盡量只使用一張貼圖。
- motions文件夾是所有的動作文件.mtn
- expressions文件夾是所有表情動作.mtn
- model.moc是Live2D的模型文件
- physics是物理演算文件
- pose.json 可以用於動態的切換部件以實現特定需求
Live2D的Model.json文件
這裡主要講解下model.json這個文件
{n "version":"Sample 1.0.0",n "model":"model.moc",n "textures":[n "model.1024/texture_00.png"n ],n "motions":{n "idle":[n {"file":"motions/idle_01.mtn"}n ],n "":[n {"file":"motions/x1.mtn"}n ]n },n "physics":"physics.json",n "hit_areas":[ n {"name":"face","id":"D_REF.FACE"},n {"name":"body","id":"D_REF.BODY"},n {"name":"arm_l","id":"D_REF.ARM_L"}n ]n}n
事實上這個Json文件都可以不存在的,只要你手工調用方法載入上MOC文件和貼圖文件,Live2D的基本就已經顯示出來了。
但是我這邊使用了model.json是因為方便資源的統一管理,方便可以看出來一個L2D模型中有多少資源包含。
在代碼中雖然可以直接進行載入,但是我們更加希望有一份json作為引導文件告訴我們,現在需要載入哪些資源,然後引用哪些資源,以方便調用。
在遊戲中中我們參考了SDK其中包含的Live2D的Demo,載入框架作為基礎,然後修改,做出項目能用的框架。
此Model.json的key-value值參考的是Demo中的框架,大家閑得蛋疼可以搞一套屬於自己的,但是也可以直接使用已經存在的。
Unity中Live2D的問題
在Unity中使用Live2D需要注意許多問題,我在使用中也踩到了很多坑,雖然現在是有給出了解決的方案,但是這些有可能都不是最終最好的解決方案,希望大家能幫我指出。
1.Live2D的RenderMode。
可能很多人一開始使用的時候都沒有注意到這個參數的設置,默認是L2D_RENDER_DRAW_MESH_NOW。
這個參數有兩個變數L2D_RENDER_DRAW_MESH_NOW和L2D_RENDER_DRAW_MESH。
主要區分為L2D_RENDER_DRAW_MESH_NOW是在OnRenderObject時候調用Draw()函數。
在OnRenderObject中調用Draw()會造成其Live2D一直處於最後渲染,而不會被其他物體而覆蓋。而L2D_RENDER_DRAW_MESH是在Update()中調用Draw()函數,可以進行半透明物體的渲染。
2.Live2D中圖形層級的問題
在Unity中使用L2DSDK2.1時候,你會發現一個很痛苦的問題,他沒辦法改變圖層。
本人在Ugui與Live2D結合中現在已經使用過這幾個方案:
- 採用Unity的RT技術。
- 採用專門的一個攝像機進行拍攝,然後渲染到UI上。
- 實際使用時候需要進行矩陣的換算。
- 而且比較吃性能和內存,沒有特別比必要就沒有使用。
- 採用sortorder進行層級控制。
- 調整其他非Live2D的UI的sortorder。
- Ugui中可以使用sortorder來指定渲染層級。
- 但是由於項目一開始並沒有考慮到會有live2D,所以Layer的定義都在同一個Deaflut中。
- 我猜測L2d在渲染時候是全部渲染到了order為0的層上了。
- 所以假設情況允許可以考慮將需要分層的下層物體的order分別設置為負數,需要在上層的物體的order設置為正數可以解決圖層分層的問題。
- 使用L2D_RENDER_DRAW_MESH_NOW直接疊加。
- 如果兩個Live2D模型需要疊加的話推薦使用L2D_RENDER_DRAW_MESH_NOW。
- 那有人會說那這樣誰會渲染在誰上面?
- 經過測試這樣的情況下,誰後實例化誰會最後進行渲染。
- 所以如果採用此方案進行最好自己創建一個Live2D生成隊列進行管理。來維護渲染順序。
- 使用L2D_RENDER_DRAW_MESH進行疊加。
- 假設遇到了情況是兩個Live2D疊加而且需要使用L2D_RENDER_DRAW_MESH作為渲染模式時候。
- 兩個Live2D的疊加順序符合場景中的排序。
- 但是要注意的是在某些情況下會出現兩個Live2D的部分部件相互穿透的問題。
- 這個問題的出現我猜測是在Live2D製作中圖層的穿透問題。
- 但是在某些情況下並沒有復現,而且美術最近比較忙,沒有來得及詳細測試找出原因。
- 使用RenderQueue。
- 如果你的方案是Unity+NGUI+Live2D,可以考慮使用RenderQueue來進行排序。
- 在Live2D自帶的Shader中為3000,你可以根據層級來設置你自己的UI的RenderQueue,同樣他不支持設置Live2D的RenderQueue。
- 同時即使採用UGUI也可以使用RnederQueue,比如疊加粒子時候。
Live2D動作管理
- 在Live2D中動作的文件均是以mtn後綴的文件
- 在model.json中可以使用motions這個字典來管理
- 通過key來管理多個不同種類的動作文件。
Live2D代碼解析(以Demo中SampleApp1這個項目作為例子):
1.資源載入入口函數
LAppModel.LoadFromResource(String dir,String filename);n
2.Model.Init函數(修改支持DrawMode切換)
public void Init(String modelJson,int DrawMode)n{n updating = true;n initialized = false;n modelSetting = new ModelSettingJson(modelJson);n if (LAppDefine.DEBUG_LOG) Debug.Log("Start to load model");n // Live2D Modeln if (modelSetting.GetModelFile() != null)n {n loadModelData(modelHomeDir + modelSetting.GetModelFile());n //setRenderMode必須要在載入Moc文件後,載入貼圖前。n GetLive2DModelUnity().setRenderMode(DrawMode);n var len = modelSetting.GetTextureNum();n for (int i = 0; i < len; i++)n {n loadTexture(i, modelHomeDir + modelSetting.GetTextureFile(i));n }n }n}n
3.Model.Json 解析引導
//事實上所有的動作等資源均是類似管理,如果需要提高性能可以單獨實現數組n//通過ModelSettingJson來解析model.jsonnmodelSetting = new ModelSettingJson(modelJson);n//通過函數跟蹤可以發現其實是直接返回json而已nlen = modelSetting.GetTextureNum();n
4.動作播放
遊戲中動作被分為:
- 待機動作,
- 特殊待機動作,
- 觸摸事件動作,
- 震動事件動作。
除了待機動作,所有動作均可以相互交換。
特殊待機動作,觸摸動作,震動動作,被維護成一個字典,有唯一索引,進行調用。//此方法已經是被我修改過的方法,原始方法可以在例子中找到,原始方法是支持以索引號去播放,我修改為可以根據name播放,大家可以根據代碼自行修改一下比較簡單。nLAppModel.StartMotion(string group,string motionName,int priority);n
Live2D表情管理
- 遊戲中沒有太多的使用表情,所以也不展開討論。
- 標籤文件為json格式。
- 使用方法與動作類似 。
- 表情使用時候要注意覆蓋的問題。
LAppModel.SetExpression(string name);n
Live2D口型管理
在Live2D的動畫播放時候有時候希望能使語音與嘴型對上可以有如下幾個方法:
- 通過控制PARAM_MOUTH_OPEN_Y。
- 使用系統級API獲得當前的設備的播放音量
- 量化到0-1之間去
- 然後設置PARAM_MOUTH_OPEN_Y來控制最新的張口。
- 使用單獨mtn嘴型文件
- 單獨做出關於嘴型參數的mtn動作
- 創建不同的MotionQueueManager來管理嘴型和一般動畫
- 需要同時播放才可以對上。
Live2D的Pose文件
- 我們可以在遊戲中使用Pose.json文件來實現某些特性
- 其實主體的方法就是切換部件來實現某些特性。
- 在需要的時候會讀取Pose.json文件然後載入上需要的組件
LAppModel.loadPose(String path);n
- 然後大家會發現自從切換上Pose文件後就不管樣都無法恢復到一開始的樣子了。
- 後來通過測試發現通過重新初始化來恢復。代碼如下:
//非常簡單,pose變數是L2DPose類型,是LAppModel上的變數。n//live2DModel就是當前的ALive2DModel。n//這樣就可以恢復到載入pose文件之前的。npose.initParam(live2DModel);n
Live2D觸摸事件的管理
- 在遊戲中Live2D觸摸事件在每個場景中是不一樣的,為了提高整個組件的復用。
- 組件中的觸摸事件是一個事件鏈
- 在不同場景中的控制器可以使用委託來事件觸摸事件的反應,而且在做出反應後可以通過函數的返回值來確定下一級時候繼續要處理整個事件,增加了這個的靈活性。
寫在尾巴上的
- 事實上Live2D的更多功能還並沒有完全的被探索使用出來,
- 本文由於本人自己的能力有限只是簡單探索,作為拋磚引玉作用。
- 國內資料暫時還比較缺少,本人斗膽分享了出來,希望各位大牛不要恥笑。
Joker
最後做個小廣告~
喜歡的可以轉載下我的小文章Blog:http://www.hailantown.com
推薦閱讀:
※我想請問一下你們玩開心消消樂是一種什麼感覺?
※專訪《仙劍幻璃鏡》《仙3》《仙4》製作人張孝全:22年後,領銜第一款自研仙劍手游
※[卡組分享] 主播卡組掃描#1
※渠道力挺,大廠布局:都說這是2017年的風口,但獨立遊戲到底賺了多少錢?