捏动作初尝试
现在游戏里大多都能“捏脸”。玩家用自己喜欢的脸来进入游戏,会更有沉浸感吧~捏动作也是受这个启发。之前跟同事提起过,进击的巨人里各式各样的“奇行种”的跑步姿势,猜想或许玩家喜欢的跑步姿势也不一样。有人希望自己跑得器宇轩昂,某些玩家希望自己跑得gay里gay气。如果能让玩家拥有千奇百怪的跑步姿势(或者其他动作),感觉或许有点意思呢。
这几天把几个想法的雏形做了一点,先记录一下 =。=~
几个想法
核心肯定是通过简单的数据,来修改动作的表现,令人感觉动作有所变化,但是依然很自然。
- 用单个数值控制几个动作之间的插值来生成新的动作:这种不考虑了~需要的新动作太多,而且新动作也没有太多自由度;
- 用单个数值控制动作的幅度:修改关节的动作曲线的振幅,显得人物“运动幅度更大”;
- 用单个数值控制动作的偏移:对于关节的动作曲线,增加一个固定大小的旋转偏移。
出现的问题以及解决方法
转一整圈的问题
如果把每个关节动作幅度都同步增大或减小,势必引起某些转一整圈的情况下,动作转圈并非一整圈,那么循环的时候就会有突变的点
解决方法
维持两个关键帧之间的四元数旋转为较小角,来捋一遍整个曲线。如果在某一关键帧时和最初的关键帧之间的四元数差别为较大角,说明这个曲线转了超过一圈。
那么在整体缩放四元数的时候,跳过这个曲线。
(其实所有关节都缩放的这个操作十分鸡肋,会导致第2个问题无法解决,所以现在代码里已经去掉它了,改为局部的调整。)
对父亲关节的角度调整,不希望影响孩子关节的角度
例如希望膝盖向内收的同时,还希望足部保持原来的方向踏在地上;手向前拿东西的动画,虽然胳膊肘更直了,但是手依然需要朝前。亦即只改变某一部分关节的旋转方向,而不影响孩子。
解决方法
对父关节进行修改后,记录其修改的量,然后将这些量执以一定权重,分配到其孩子及孩子的孩子等上。
注意这个“修改的量”是世界空间中的。
暂时只支持同一层级同一权重,不支持不同分支不同权重列表的情况。
关键帧之间的Merge
不同关节的关键帧的时间点可能不一样。
解决方法
如果父亲关节有需要“分配”给孩子的变化,那么孩子重新Merge一下关键帧,将父亲的关键帧的所有时间也加入自己的曲线。
注意进行适当的sample。
关键帧曲线的切线方向要尽可能保持之前的方向
美术制作动作的时候会通过关键帧的切线方向来控制动作的细节,如果丢失了切线数据,可能造成动作不平滑,或者该不平滑的地方被平滑了。
解决方法
记录父亲“修改的量”时,也记录其斜率数据。其斜率数值,按照scale的值来进行分配,父亲分配 scale 部分,修改的量分配 (1-scale) 部分;
关键帧合并的时候,将两个斜率相加。
如何用简单的动作微调,来形成一种“动作风格”?
例如两个男生,一个gaygay的,一个manman的,他们之间的差别可能不仅仅是“胳膊肘向内收小手向外甩”这么简单……
解决方法还没有
能否不生成整个动作,直接在播放时得到结果?
现在做的时候是根据当前动作预先计算出新的动作,再播放这个动作文件。是否能够节省掉这个计算过程,直接使用原动作和微调的数值来播放动作?或者仅仅用一些固定的预计算的结果来达到这一目的?
解决方法还没有
是否可以使用傅里叶变换或者小波变换等手段,在频域修改动作曲线,来获得更精致的效果?
解决方法还没有
这是最初遇到“幅度是基于什么的幅度”的时候考虑过的问题。将某个动作幅度减小,一定是在“整体上的位置”的基础上减小的,亦即,四元数的平均值不能被缩放。所以自然而然考虑到傅里叶变换,然后保持低频部分不变之类的……
但是考虑到曲线的出入斜率、计算复杂度的问题,感觉这条路前途灰暗……
所以现在的做的是直接算个平均值 = =……
效果示例
- 缩小大腿的运动幅度为0:
正常应该不会缩小到0,为了演示方便所以设置了0;将其修改以1的权重分配到小腿上;
可以看到足部基本上还是能够踩到地面的,只是位移方面可能需要求助于ik了。 - 平移胳膊的运动角度:
左右两边分别对肩膀位置进行了固定角度的平移。没有给孩子分配修改权重。 - 为了更方便的看到调整的结果,贴一个简单的曲线……
啊哈!两个人有什么区别!看不粗来了对嘛!
其实左边的那个人,脖子(Neck)的幅度调整到了0,由一级孩子(Head)弥补所有变化。所以Head的朝向依然可以保持不变。
修改前的Neck曲线:
修改前的Head曲线:
修改后的Neck曲线(只剩下平均值了~):
修改后的Head曲线(加上了Neck的部分):
曲线的tangent也并没有乱呀噶哈哈!~嗨森~
下一步可能会做的
- 考虑下效率问题
现在的复杂度包括,对每个曲线整体计算平均值,对每个关键帧进行修改,应该说是O(n)的。可能看看能不能减小常数,或者不预计算,直接使用之类的。
讲真,暂时想不到方法…… - 稀疏动作的某些骨骼点被跳过的情况
稀疏的动作,可能一个父亲的一级孩子并没有曲线,这种情况下就不会遍历到这个关节。
——毕竟用的是Unity自己的traverse……
——但是终究还是要用Unity的traverse……
可能预先缓存下会比较好吧……
还可能解决有些情况下动作曲线遍历的次序不是先序遍历的问题……
不过话说,现在居然其实也能用…… - 动作风格是怎样形成怎样形成怎样形成的呢???