前言
之前只是花个周末复读了一篇育碧的演讲,讲到一些周边系统,程序化镜头,口型匹配,角色补光,景深,Lookat,我都玩过一点,很多在2U引擎里都算是标配;本以为投靠Unreal可以缓解大部分周边系统开发的压力,结果原生方案的对接使用工作还是费了一番功夫;而鉴于一些历史遗留问题,Unity的原生方案一般都有些暗坑,加上开发环境不同,项目的需求也不会在乎什么叫标准方案,大部分方案我们都改过.项目里的代码没有脱敏不能拿出来看,这次把在家里码的 Lookat拿来当例子讲一下.
IK
反向动力学(Inverse Kinematics),简称IK,泛指一系列在骨骼动画里不依赖结构树顺序的计算方案.概念上与之相对应的是正向动力学(Forward Kinematics),但它俩只是字面上相反,实际关系并没有那么工整对仗.
IK的难点主要是需求困难而且和一般骨骼动画方案的设计冲突.一般骨骼动画的解算流程,计算代码独立计算完成当前节点的数据,每个节点的数据依附于父节点的计算结果,像Unity这样的,解算流程都在追求内存紧密,层级信息都在外层逻辑里.比如Biped人形骨架方案的骨骼树根节点是屁股,腰腿等骨骼节点的TRS(位置,旋转,缩放)都是基于屁股的TRS的相对数据.依照这个流程,屁股的TRS传递到最后影响了脑袋的TRS,理所当然的,脑袋无论怎么摇摆,都不会改变屁股的TRS.
如果想让脑袋决定屁股要怎么办呢?方法有很多,最简单的方法就是让脑袋成为屁股层级树结构里的父节点就行了,不过这个方法有很多问题,一来程序解算骨骼树倾向于一套稳定的结构,二来所有需求都新建一套骨架树维护更新工作令人绝望,况且如果同时出现四肢都有控制需求的时候,这套框架也不能满足.那么是否可以新增一个无视骨架结构树的流程,让脑袋决定屁股呢?这就是IK了.
一般IK计算流程都会安排在动画计算流程之后,我们假定动画采样赋值执行完成后,骨架树结构处于一个"符合预期"的状态,而在IK就是在这个状态的基础上执行,保持状态"符合预期"的同时,去修改部分骨骼的TRS,从而满足一些特定的需求.比如游戏<ICO>围绕着男孩拉着女孩的手这个主题,全篇幅都在计算如何让双方的手拉在一起(当然有时候会松开).
即使在项目成品里没有使用动画IK相关的技术,如今的动画制作软件里,已经集成了许多IK功能,来帮助美术工作者提高效果和效率.层出不穷的工具很多都是加入了更大成分的程序解算去替代人肉机械式劳动.
Lookat
就是人脑袋和眼睛看向一个目标,一般是相机和其他角色.
Unity中实现Lookat功能
首先,Lookat有很多方案,比如八方向动画混合,和最简单的,只重新计算头部节点旋转.在Lookat功能里使用IK功能的目标有如下几条.
- 更多可看向角度
- 更少美术资源需求
- 影响到更多骨骼从而更自然的控制转向
- 控制单个节点的旋转强度避免过强的视觉冲击效果
- 特殊应用场景偶尔奢侈一下追求效果
技术上的几个重点
- 逆层级传递解算目标
- 做好插值避免动画突变
- 演示出"令人满意"的效果
- 暴露变量可以调整出"令人满意"的效果
因为Unity本身已经封装了比较通用的四元数操作函数,大部分的基础计算都不用额外写计算代码,只需要着重设计方案即可.不过,代码计算过程中还是要注意到可能会造成的三角函数,矩阵计算,还有在操作Transform对象时可能造成的脏标记清理和同步等待问题.
关于IK相关的流程代码,在Monobehaviour里面主要是Update,OnAnimatorIK,LateUpdate三个触发函数.
- OnAnimatorIK: 依附于Animator模块,需要状态机层上勾选IK才会广播的消息,鉴于内部暗坑不明,不敢用
- Update: 初学者函数,不过写上去的数据会被动画模块覆盖,等于没用
- LateUpdate: 动画模块结束,渲染还没开始,规划上算逻辑业务层,放这写差不多
先看看在Unity里最简单的 Lookat怎么写.