找回密码
 立即注册
查看: 265|回复: 0

Unity3d FootIK With Final IK(3)

[复制链接]
发表于 2022-7-4 16:14 | 显示全部楼层 |阅读模式
前言:

研究近一个月的IK,人都搞麻了,是时候给来个总结跑路了。
一、IK究竟是什么

首先,我们来一个灵魂拷问:
【当我们在讨论一个IK问题的时候,本质是在讨论什么问题?】
一个IK问题,实际上,是包含了2个子问题:
IK Solver的问题,关乎解的平滑度与运算效率; IK Goal/Weight Solver 的问题,这关乎实际表现。
二、IK Solver 问题

我想,IK Solver问题其实是所有问题中最简单的问题了。他就是最本源的“逆向运动学”问题——“给定末端影响器坐标,计算骨骼旋转的角度”[1]



本源IK问题

现在有非常多的成熟的IK解算算法,广为人熟知的就有“循环坐标下降法(CCD)”[2]“前向后向抵达(FABR IK)”[3]等。
而对于FootIK,HandleIK这种具有明显特征的“TwoBoneIK”,使用三角函数解析算法[4]也是简单易懂。



Two Bone IK示例

只不过,似乎这种IK解算器,在UE中已经成为了一个蓝图节点,使用非常方便。



UE 内置IK解算器

而Unity却没有这种现成的工具,姑且在AnimationRigging中,有几处Util解算代码能供使用。
在UnityEngine.Animations.Rigging命名空间中,有一个静态类: AnimationRuntimeUtils,其中内置了两个静态工具函数【SolveTwoBoneIK】与【SolveFABRIK】 ,算是正儿八经的IK解算器。



TwoBoneIK三角函数解析算法



FABRIK算法

只不过,这两个函数是用于【AnimationRigging】自己使用的,而【AnimationRigging】又使用了JobSystem进行多线程加速,故函数的入参显得如此奇怪:xxxHandle。
幸好,参与IK解算的实际参数无非是Transform的position与rotation,自己把函数逻辑抽离出来,把入参改成Transform,也算是能白嫖这两个算法了。
顺便说一句,由于AnimationRigging是混合计算,会污染动画数据(详见上一节),之前笔者在尝试抽离逻辑修改入参时,又想使用结构体,利用JobSystem加速计算,但是由于没有Transform的访问(利用Transform获取物体的WorldPosition时,会自动计算FK(正向运动学)),在算法逻辑修改父节点的Rotation时,必须手动计算FK更新子节点坐标。还好只是个TwoBoneIK,只有3个节点,强行手写也不算难事。
当然,你想要自己造轮子,重新自己写一遍CCD, FARBIK也确实不难,因为这两个都是启发式算法,通过多次迭代来实现收敛,确实简单。三角函数解析式虽然写法复杂了一些,但是核心思想就是“余弦定理”而已。
三、IK Goal Solver问题

这个名称纯粹是笔者自己瞎编的,借用了Unity内置IK系统的IK Goal概念,而这个概念,在插件【Final IK】中,叫做【IKEffector】。
实际上,有了基本的IK Solver之后,我们更想知道:目标的Position在哪儿?在哪个位置进行IK Solve?
比如Foot IK, IK Goal的位置应该是脚部与地面射线相交的点;
比如Aim IK,IK Goal的位置应该是目标对象(比如玩家、某个NPC);
比如Hand IK,IK Goal就是武器的握把位置等等。
看上去很简单,当真如此?
1. OnAnimatorIK With AnimationCurve

在我们利用Unity Humanoid实现的第一版FootIK[5]中,决定IK Goal的手段有两个:【射线检测】+【动画曲线】。
【射线检测】是决定了脚部应该贴地的地方,而【动画曲线】是使用权重来决定脚部是否向IK Goal靠拢,基本思想写成公式就是:
finalIKGoalPosition = RayCastHitPosition * WeightFromCurve
射线检测似乎没什么操作空间,而这个AnimationCurve的操作空间可就大了,权重曲线没有弄好,穿模那是分分钟的事情:



上坡就是会穿模

如果要精修曲线,那么一个动画片段就要精修一个曲线,这种工作量真的值得吗?
2. Final IK

用上我们宇宙无敌的插件《Final IK》,看看他的表现如何?



使用插件Final IK,究极丝滑

天啦噜,如此的流畅丝滑,他是怎么做到的?
实际上Final IK的结构虽然复杂,但是也算得上精炼,层级分明,耦合度低。实现这种效果的核心组件是Grounder Biped——他专注于解决FootIK的“IK Goal Solver”问题。
而FootIK问题,本质又是3个问题:RightFootIK,LeftFootIK,PelvisIK。加之最开始说的,一个IK有2个子问题,FootIK的总问题数是2x3=6个。
其中,Pelvis(骨盆)的IK Solver问题非常简单,就是纯粹的上下坐标偏移就行了,PelvisIK退化成一个“IK Goal Solver”问题;而这个“IK Goal Solver”问题,无非是计算Root坐标与两脚的偏移坐标,几乎可以看做是一个常量消耗——Const Cost。
然后一个足部IK的“IK Solver”,基本上使用TwoBoneIK的三角函数解算器,便宜好用;而“IK Goal Solver”,那就是重中之重了。
【Final IK】的解决方案是,基于【速度(Velocity)的预测】,用当前脚部与地面的HitPoint与预测胶囊体的HitPoint做混合计算,一同决定最后的IK Goal在哪个坐标。
面板上有个参数【Prediction】,他就是预测权重:


关键性的代码是:               
velocity = (transformPosition - lastPosition) / deltaTime; //计算上一帧和这一帧Foot的速度
lastPosition = transformPosition;
Vector3 prediction = velocity * grounding.prediction; //使用prediction进行预测。
......
//足部的Hit Point检测
heelHit = GetRaycastHit(invertFootCenter ? -grounding.GetFootCenterOffset() : Vector3.zero);
//预测胶囊体的 Hit Point检测
capsuleHit = GetCapsuleHit(prediction);
if (heelHit.collider != null || capsuleHit.collider != null) isGrounded = true;
//混合计算两个Hit Point的信息,决定IK Goal的位置
SetFootToPlane(capsuleHit.normal, capsuleHit.point, heelHit.point);
然后就是一些插值、插值和插值了。
值得一提的是,这种算法,IK Goal的Weight基本上恒等于1,无需AnimationCurve进行权重设置;自然的,每一帧都会重置IK Goal到对应的Foot上,只是在后处理阶段,再移动IK Goal以及重新计算Foot Position。
虽然做了这么多工作,上坡看起来丝滑无比,但是【Final IK】的当前解决方案,依然无法解决下坡的问题:



emm...抽成Gif帧率下降反而看不出问题了

额,有点扯,转成GIF之后帧率下降,腿部抽搐的表现反而不明显了,意会一下就行。
其实这都不是最扯的,在我把【Final IK】的IK Goal Solver数据结构与算法抽离出来之后,跑测试时才发现——“IK Goal Solver”的耗时是“IK Solver”的2到3倍!!!
也不知道是【Final IK】的算法有问题,还是说本来“IK Goal Solver”的计算就是这么的繁琐,从性能表现上来说,“IK Goal Solver”问题反而是更占时的那一环。
当然,显而易见的,如果对IK做优化,“IK Solver”的算法基本上已然成熟,顶多使用SIMD数学库优化(Vector3换成float3等),操作空间不大。
有且只有“IK Goal Solver”这一环,性能对算法敏感,可能成为实际生产中的重点研究对象了。
3. FootIK Based On Prediction

“基于预测”这种思想十分朴素,后人自然而然会在此基础上开展进一步的研究拓展。在一次GDC(Game Developers Conference)(游戏开发者大会)上,《刺客信条》做了一次【基于预测的FootIK】的算法分享,核心思想是【基于路径(Path)的预测】。



总体概述

咱也是拾人牙慧,具体的还是看看知乎的这篇文章[6]吧。
不过可见一斑的是,“IK Solver”问题几乎已然解决,当我们在讨论一个IK问题的时候,更多的是在讨论“IK Goal Solver”的问题。
该如何自然地、正确地、平滑地计算出IK Goal的位置、旋转?《刺客信条》给出了他的经验分享,而我们又有什么解决方案呢?
顺便吐槽下,这种【基于预测】的算法,有一种最后和“MotionMatch”殊途同归的感觉。
四、 小结

我不得不提的是,在IK这方面,UE提供的支持确实吊打Unity,现在在网上搜游戏开发IK相关的资料,80%是UE的文档,Unity几乎绝迹。
毕竟别人UE都把IK解算器内置成了节点了,Unity提供的AnimationRigging还遮遮掩掩,没有统一的解算器接口,高判立下。
当然,每到这种时候,我不得不又扪心自问一句:实现性能友好,表现完美的IK,我配吗?国内的游戏厂商配吗?还是说用【Final IK】混吃等死就行了?咱也不知道,咱也不敢问.jpg
参考


  • ^IK(Inverse kinematics)基本概念https://zhuanlan.zhihu.com/p/434238743
  • ^循环坐标下降https://zhuanlan.zhihu.com/p/469221237
  • ^FABRIK算法https://zhuanlan.zhihu.com/p/471910711
  • ^三角函数解析算法https://zhuanlan.zhihu.com/p/447895503
  • ^初版FootIKhttps://zhuanlan.zhihu.com/p/529556406
  • ^《刺客信条》FootIK概述https://zhuanlan.zhihu.com/p/380222928

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-22 06:57 , Processed in 0.089354 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表