將進(jìn)酒
君不見(jiàn),黃河之水天上來(lái),奔流到海不復(fù)回。
君不見(jiàn),高堂明鏡悲白發(fā),朝如青絲暮成雪。
人生得意須盡歡,莫使金樽空對(duì)月。
天生我材必有用,千金散盡還復(fù)來(lái)。
烹羊宰牛且為樂(lè),會(huì)須一飲三百杯。
岑夫子,丹丘生,將進(jìn)酒,杯莫停。
與君歌一曲,請(qǐng)君為我傾耳聽(tīng)。
鐘鼓饌玉不足貴,但愿長(zhǎng)醉不復(fù)醒。
古來(lái)圣賢皆寂寞,惟有飲者留其名。
陳王昔時(shí)宴平樂(lè),斗酒十千恣歡謔。
主人何為言少錢,徑須沽取對(duì)君酌。
五花馬,千金裘,呼兒將出換美酒,與爾同銷萬(wàn)古愁。
本文首發(fā)于Lohanry's Blog,轉(zhuǎn)載請(qǐng)注明。
什么是Live2D
- Live2D是日本Cybernoids公司開(kāi)發(fā)。
- Live2D現(xiàn)階段有兩個(gè)主要的版本是2.1的版本和3.0的版本。
- 國(guó)內(nèi)2.1版本用的比較多(ps.此為自己的感覺(jué),并沒(méi)有數(shù)據(jù)支持,只是感覺(jué)國(guó)內(nèi)討論的比較多的就是2.1了)。
- 大家可以到官網(wǎng)去下載2.1版本,由于3.0版本的無(wú)法支持當(dāng)前項(xiàng)目的Unity版本,所以暫時(shí)沒(méi)有使用。
Unity中的Live2D
Live2D已經(jīng)增加的了對(duì)Unity的支持,所以只需要將SDK下載下來(lái)后倒入就可以使用了,里面也有幾個(gè)簡(jiǎn)單的例子可以直接跑。
本文討論的是Unity中使用Live2D,對(duì)Live2D的制作不做任何討論。
我們可以從Live2D導(dǎo)出的文件中看到如下標(biāo)準(zhǔn)格式:

- model.1024文件夾中放的是人物的模型貼圖,由于多貼圖導(dǎo)致DrawCall升高的,所以在游戲中盡量只使用一張貼圖。
- motions文件夾是所有的動(dòng)作文件.mtn
- expressions文件夾是所有表情動(dòng)作.mtn
- model.moc是Live2D的模型文件
- physics是物理演算文件
- pose.json 可以用于動(dòng)態(tài)的切換部件以實(shí)現(xiàn)特定需求
Live2D的Model.json文件
這里主要講解下model.json這個(gè)文件
{
"version":"Sample 1.0.0",
"model":"model.moc",
"textures":[
"model.1024/texture_00.png"
],
"motions":{
"idle":[
{"file":"motions/idle_01.mtn"}
],
"":[
{"file":"motions/x1.mtn"}
]
},
"physics":"physics.json",
"hit_areas":[
{"name":"face","id":"D_REF.FACE"},
{"name":"body","id":"D_REF.BODY"},
{"name":"arm_l","id":"D_REF.ARM_L"}
]
}
事實(shí)上這個(gè)Json文件都可以不存在的,只要你手工調(diào)用方法加載上MOC文件和貼圖文件,Live2D的基本就已經(jīng)顯示出來(lái)了。
但是我這邊使用了model.json是因?yàn)榉奖阗Y源的統(tǒng)一管理,方便可以看出來(lái)一個(gè)L2D模型中有多少資源包含。
在代碼中雖然可以直接進(jìn)行加載,但是我們更加希望有一份json作為引導(dǎo)文件告訴我們,現(xiàn)在需要加載哪些資源,然后引用哪些資源,以方便調(diào)用。
在游戲中中我們參考了SDK其中包含的Live2D的Demo,加載框架作為基礎(chǔ),然后修改,做出項(xiàng)目能用的框架。
此Model.json的key-value值參考的是Demo中的框架,大家閑得蛋疼可以搞一套屬于自己的,但是也可以直接使用已經(jīng)存在的。
Unity中Live2D的問(wèn)題
在Unity中使用Live2D需要注意許多問(wèn)題,我在使用中也踩到了很多坑,雖然現(xiàn)在是有給出了解決的方案,但是這些有可能都不是最終最好的解決方案,希望大家能幫我指出。
1.Live2D的RenderMode。
可能很多人一開(kāi)始使用的時(shí)候都沒(méi)有注意到這個(gè)參數(shù)的設(shè)置,默認(rèn)是L2D_RENDER_DRAW_MESH_NOW。
這個(gè)參數(shù)有兩個(gè)變量L2D_RENDER_DRAW_MESH_NOW和L2D_RENDER_DRAW_MESH。
主要區(qū)分為L(zhǎng)2D_RENDER_DRAW_MESH_NOW是在OnRenderObject時(shí)候調(diào)用Draw()函數(shù)。
在OnRenderObject中調(diào)用Draw()會(huì)造成其Live2D一直處于最后渲染,而不會(huì)被其他物體而覆蓋。
而L2D_RENDER_DRAW_MESH是在Update()中調(diào)用Draw()函數(shù),可以進(jìn)行半透明物體的渲染。
2.Live2D中圖形層級(jí)的問(wèn)題
在Unity中使用L2DSDK2.1時(shí)候,你會(huì)發(fā)現(xiàn)一個(gè)很痛苦的問(wèn)題,他沒(méi)辦法改變圖層。
本人在Ugui與Live2D結(jié)合中現(xiàn)在已經(jīng)使用過(guò)這幾個(gè)方案:
- 采用Unity的RT技術(shù)。
- 采用專門的一個(gè)攝像機(jī)進(jìn)行拍攝,然后渲染到UI上。
- 實(shí)際使用時(shí)候需要進(jìn)行矩陣的換算。
- 而且比較吃性能和內(nèi)存,沒(méi)有特別比必要就沒(méi)有使用。
- 采用sortorder進(jìn)行層級(jí)控制。
- 調(diào)整其他非Live2D的UI的sortorder。
- Ugui中可以使用sortorder來(lái)指定渲染層級(jí)。
- 但是由于項(xiàng)目一開(kāi)始并沒(méi)有考慮到會(huì)有l(wèi)ive2D,所以Layer的定義都在同一個(gè)Deaflut中。
- 我猜測(cè)L2d在渲染時(shí)候是全部渲染到了order為0的層上了。
- 所以假設(shè)情況允許可以考慮將需要分層的下層物體的order分別設(shè)置為負(fù)數(shù),需要在上層的物體的order設(shè)置為正數(shù)可以解決圖層分層的問(wèn)題。
- 使用L2D_RENDER_DRAW_MESH_NOW直接疊加。
- 如果兩個(gè)Live2D模型需要疊加的話推薦使用L2D_RENDER_DRAW_MESH_NOW。
- 那有人會(huì)說(shuō)那這樣誰(shuí)會(huì)渲染在誰(shuí)上面?
- 經(jīng)過(guò)測(cè)試這樣的情況下,誰(shuí)后實(shí)例化誰(shuí)會(huì)最后進(jìn)行渲染。
- 所以如果采用此方案進(jìn)行最好自己創(chuàng)建一個(gè)Live2D生成隊(duì)列進(jìn)行管理。來(lái)維護(hù)渲染順序。
- 使用L2D_RENDER_DRAW_MESH進(jìn)行疊加。
- 假設(shè)遇到了情況是兩個(gè)Live2D疊加而且需要使用L2D_RENDER_DRAW_MESH作為渲染模式時(shí)候。
- 兩個(gè)Live2D的疊加順序符合場(chǎng)景中的排序。
- 但是要注意的是在某些情況下會(huì)出現(xiàn)兩個(gè)Live2D的部分部件相互穿透的問(wèn)題。
- 這個(gè)問(wèn)題的出現(xiàn)我猜測(cè)是在Live2D制作中圖層的穿透問(wèn)題。
- 但是在某些情況下并沒(méi)有復(fù)現(xiàn),而且美術(shù)最近比較忙,沒(méi)有來(lái)得及詳細(xì)測(cè)試找出原因。
- 使用RenderQueue。
- 如果你的方案是Unity+NGUI+Live2D,可以考慮使用RenderQueue來(lái)進(jìn)行排序。
- 在Live2D自帶的Shader中為3000,你可以根據(jù)層級(jí)來(lái)設(shè)置你自己的UI的RenderQueue,同樣他不支持設(shè)置Live2D的RenderQueue。
- 同時(shí)即使采用UGUI也可以使用RnederQueue,比如疊加粒子時(shí)候。
Live2D動(dòng)作管理
- 在Live2D中動(dòng)作的文件均是以mtn后綴的文件
- 在model.json中可以使用motions這個(gè)字典來(lái)管理
- 通過(guò)key來(lái)管理多個(gè)不同種類的動(dòng)作文件。
Live2D代碼解析(以Demo中SampleApp1這個(gè)項(xiàng)目作為例子):
1.資源加載入口函數(shù)
LAppModel.LoadFromResource(String dir,String filename);
2.Model.Init函數(shù)(修改支持DrawMode切換)
public void Init(String modelJson,int DrawMode)
{
updating = true;
initialized = false;
modelSetting = new ModelSettingJson(modelJson);
if (LAppDefine.DEBUG_LOG) Debug.Log("Start to load model");
// Live2D Model
if (modelSetting.GetModelFile() != null)
{
loadModelData(modelHomeDir + modelSetting.GetModelFile());
//setRenderMode必須要在加載Moc文件后,加載貼圖前。
GetLive2DModelUnity().setRenderMode(DrawMode);
var len = modelSetting.GetTextureNum();
for (int i = 0; i < len; i++)
{
loadTexture(i, modelHomeDir + modelSetting.GetTextureFile(i));
}
}
}
3.Model.Json 解析引導(dǎo)
//事實(shí)上所有的動(dòng)作等資源均是類似管理,如果需要提高性能可以單獨(dú)實(shí)現(xiàn)數(shù)組
//通過(guò)ModelSettingJson來(lái)解析model.json
modelSetting = new ModelSettingJson(modelJson);
//通過(guò)函數(shù)跟蹤可以發(fā)現(xiàn)其實(shí)是直接返回json而已
len = modelSetting.GetTextureNum();
4.動(dòng)作播放
游戲中動(dòng)作被分為:
- 待機(jī)動(dòng)作,
- 特殊待機(jī)動(dòng)作,
- 觸摸事件動(dòng)作,
- 震動(dòng)事件動(dòng)作。
除了待機(jī)動(dòng)作,所有動(dòng)作均可以相互交換。
特殊待機(jī)動(dòng)作,觸摸動(dòng)作,震動(dòng)動(dòng)作,被維護(hù)成一個(gè)字典,有唯一索引,進(jìn)行調(diào)用。
//此方法已經(jīng)是被我修改過(guò)的方法,原始方法可以在例子中找到,原始方法是支持以索引號(hào)去播放,我修改為可以根據(jù)name播放,大家可以根據(jù)代碼自行修改一下比較簡(jiǎn)單。
LAppModel.StartMotion(string group,string motionName,int priority);
Live2D表情管理
- 游戲中沒(méi)有太多的使用表情,所以也不展開(kāi)討論。
- 標(biāo)簽文件為json格式。
- 使用方法與動(dòng)作類似 。
- 表情使用時(shí)候要注意覆蓋的問(wèn)題。
LAppModel.SetExpression(string name);
Live2D口型管理
在Live2D的動(dòng)畫播放時(shí)候有時(shí)候希望能使語(yǔ)音與嘴型對(duì)上可以有如下幾個(gè)方法:
-
通過(guò)控制PARAM_MOUTH_OPEN_Y。
- 使用系統(tǒng)級(jí)API獲得當(dāng)前的設(shè)備的播放音量
- 量化到0-1之間去
- 然后設(shè)置PARAM_MOUTH_OPEN_Y來(lái)控制最新的張口。
-
使用單獨(dú)mtn嘴型文件
- 單獨(dú)做出關(guān)于嘴型參數(shù)的mtn動(dòng)作
- 創(chuàng)建不同的MotionQueueManager來(lái)管理嘴型和一般動(dòng)畫
- 需要同時(shí)播放才可以對(duì)上。
Live2D的Pose文件
- 我們可以在游戲中使用Pose.json文件來(lái)實(shí)現(xiàn)某些特性
- 其實(shí)主體的方法就是切換部件來(lái)實(shí)現(xiàn)某些特性。
- 在需要的時(shí)候會(huì)讀取Pose.json文件然后加載上需要的組件
LAppModel.loadPose(String path);
- 然后大家會(huì)發(fā)現(xiàn)自從切換上Pose文件后就不管樣都無(wú)法恢復(fù)到一開(kāi)始的樣子了。
- 后來(lái)通過(guò)測(cè)試發(fā)現(xiàn)通過(guò)重新初始化來(lái)恢復(fù)。代碼如下:
//非常簡(jiǎn)單,pose變量是L2DPose類型,是LAppModel上的變量。
//live2DModel就是當(dāng)前的ALive2DModel。
//這樣就可以恢復(fù)到加載pose文件之前的。
pose.initParam(live2DModel);
Live2D觸摸事件的管理
- 在游戲中Live2D觸摸事件在每個(gè)場(chǎng)景中是不一樣的,為了提高整個(gè)組件的復(fù)用。
- 組件中的觸摸事件是一個(gè)事件鏈
- 在不同場(chǎng)景中的控制器可以使用委托來(lái)事件觸摸事件的反應(yīng),而且在做出反應(yīng)后可以通過(guò)函數(shù)的返回值來(lái)確定下一級(jí)時(shí)候繼續(xù)要處理整個(gè)事件,增加了這個(gè)的靈活性。
寫在尾巴上的
- 事實(shí)上Live2D的更多功能還并沒(méi)有完全的被探索使用出來(lái),
- 本文由于本人自己的能力有限只是簡(jiǎn)單探索,作為拋磚引玉作用。
- 國(guó)內(nèi)資料暫時(shí)還比較缺少,本人斗膽分享了出來(lái),希望各位大牛不要恥笑。

最后做個(gè)小廣告~
喜歡的可以轉(zhuǎn)載下我的小文章
Blog:http://www.hailantown.com