Live2D模型在Unity中的使用
Live2D是日本Cybernoids公司开发的绘图渲染技术,在2D中能实现类似2.5D效果的人物动画,在电子游戏中可能会用得到。
前一阵子公司游戏客户端想要导入Live2D模型,将游戏里剧情人物替换,让剧情看起来更加的好看,中间走了很多坑,下面我就记录下Live2D导入Unity的过程。
先放官方链接:Live2D官网。
在官网里下载Live2D Unity SDK然后导入Unity,然后Live2D官网有几个Demo可以直接下载使用。
看完Demo之后可能会一脸蒙蔽,什么鬼东西,动来动去的怎么动的。
作为程序员的我们可能不需要了解动画人物制作的详细过程,但是使用过UI动画编辑器之类的应该知道类似的原理,人物的动作其实就类似网格图,然后通过这些点来拉动人物的动作;动画大概就是设置一些关键点之类的差不多都那样;live2D有自己的物理系统,大概是设置一些重量,偏移值之类的。
当美术做完Live2D模型之后,这个文件夹包括了moc3模型信息、动作json文件,physics文件等等;然后我们为每一个模型创建一个文件夹,把每个模型相关的motion文件放在一起,然后直接导入Unity工程目录下;unity因为提前导入了sdk,它会自动识别模型文件信息,然后自动把文件编译成unity可用的Prefab和AnimationClip。
接下来工作就简单啦,创建Animator Controller来控制这些AnimationClip,这部分内容就自己去学习吧~
这里有几点:
1.最好将嘴部动画和肢体动作分开管理,animation controller增加parramator即可,然后设置
blendingMode = AnimatorLayerBlendingMode.Override;
代码写好的animator,通过unity直接查看就长这样,通过AnyState?各个状态就能使用unity的动作融合啦
2.为了动作融合,Aninator只能通过对应的transaction Index来切换状态。我是把Transation和动作名之间的关系写了个对应关系脚本存储为程序可读的数组,那样就能通过动作名直接获取链接名啦~~
//Animator可以直接创建Controller在指定路径
CreateAnimatorControllerAtPath
3.为了更好的控制模型,在创建Prefab的时候就要添加几个Component用来控制模型的位置,动画,渲染等
4.有时候会遇到Live2D在Scene界面有轮廓,但是没有贴图的情况,
我直接上代码啦:
local shaderName = "Live2D Cubism/Unlit"
local shader = CS.UnityEngine.Shader.Find(shaderName)
local trans = self.obj.transform:Find("Drawables")
local renders = CS.LuaMgr.getCubismRendersInChildren(trans)
for i=0, renders.Length - 1 do
renders[i].Material.shader = shader
end
这段是Lua代码,大概就是找到Unlit这个shader然后把它指定下就好啦,不知道新版sdk还有没有这个问题。
再说一点Live2D比较坑的几个问题:
1.物理效果非常容易跟项目代码进行冲突,这个自己阅读SDK找问题吧~
2.Live2D脚本自带的控制Alpha的Component跟Unity的Animator不能兼容,两者只能同时有一个运行……是我傻逼了么,没想到别的解决方案。
3.如果遇到经常创建销毁模型的情况,最好是创建资源池进行管理,
并且频繁移除的时候,不要频繁的setActive,这样会导致各种未知情况的发生 。
最后说一点动画播放结束之后的回掉函数和几个动作自动进行联合播放的问题,一般情况下可以在动画后面添加关键帧或者监听动画机的状态,最简单的方法就是计算动画的长度,然后使用计时器……
public static float GetClipLength(Animator animator, string clip)
{
if (null == animator || string.IsNullOrEmpty(clip) || null == animator.runtimeAnimatorController)
return 0;
RuntimeAnimatorController ac = animator.runtimeAnimatorController;
AnimationClip[] tAnimationClips = ac.animationClips;
if (null == tAnimationClips || tAnimationClips.Length <= 0) return 0;
AnimationClip tAnimationClip;
for (int tCounter = 0, tLen = tAnimationClips.Length; tCounter < tLen; tCounter++)
{
tAnimationClip = ac.animationClips[tCounter];
if (null != tAnimationClip && tAnimationClip.name == clip)
return tAnimationClip.length;
}
return 0F;
}
上边这个直接给了计算的代码~~
别忘了最后释放内存……