关注我博客的同学应该知道,这个星期都在做一些MMD动作相关的,刚好做到动作这快
十分惭愧!工作多年,还没好好系统地分析过动作这块
今天带来网易大咖(可能只是工作室内的小小员工,网易还有分大的产品组,下面才是各小小工作室,然后其中里面的一个员工,可以吊打市面80%游戏从业人员)的分享
(当然,以下内容和公司真正工作内容还是有些出入,各公司之间人员,做法等也会有很大差别,不能盲目相信或者模仿某一种做法,这里仅仅是转载一些基础知识,请按自身需要挑选食用)
关键还是大量的相关知识阅读,“内化”,举一反三,能快速解决自身当前的问题
一文搞懂 Unity 布娃娃(Ragdoll)系统 让角色更加真实 (附实用Ragdoll插件详解)
布娃娃(Ragdoll)系统
布娃娃系统,相信很多玩家已经在大部分游戏中遇到过。作为一个已经成熟并且普及的系统,Ragdoll被广泛应用于各种游戏,来提供一定程度上的物理模拟。
图中是一个典型的Ragdoll应用场景,敌人在被一拳打飞后,在地面翻滚倒地,整个过程显得非常自然流畅。而且,在整个过程中,并没有用到任何传统“动画”,一切基于物理模拟效果。因而布娃娃系统,也是“程序生成动画”的一个重要手段。
模型与骨骼
模型
要理解Ragdoll系统为什么能实现物理模拟动画的效果,我们首先需要简单了解一下,传统3D游戏中动画的实现方式。(已经了解的同学可以直接跳到下一部分)
模型作为我们最常接触的美术资源,其本身是由一系列顶点(坐标)信息组成的数据集,因而显然,单纯的模型是纯静态的,我们在Unity->Gizoms中勾选Selection Wire就可以看到模型的线框图。 在Unity中可以看到Mesh Renderer系列组件,其中Mesh就是模型的网格。
那么让模型动起来,要做的就是让模型的各个顶点,按照一定规律运动起来,实现“动画”效果,这也是经典的“顶点动画”原理。
但是现代游戏,稍微复杂的一个模型常常有几千上万的顶点,让美术人员去手动设置每个顶点的运动情况显然不现实,也很难实现合理的效果。
于是人们想到现实中,人类靠骨骼带动肌肉运动,我们很少去直接控制身体上某块肌肉运动,更多是去驱动骨骼。只要骨骼按照一定规律运动,骨骼附带的肌肉也会随之运动,骨骼动画的概念应运而生。
骨骼
“骨骼”其实是一个抽象概念,它参考了人体利用骨骼带动肌肉运动的规律,为模型创建一个类似的、抽象的“骨骼”,如图所示。
图中就是一个包含骨骼的模型,这里利用了AnimationRigging插件中的BoneRenderer将骨骼以可视化的形式显示了出来(不然骨骼是一个抽象概念,并不对应某些可见实体)。可以看出,模型骨骼与人体骨骼非常相似,只是进行了一定程度上的简化。
那么实际上, Unity 中的骨骼,只是一系列具有父子层级关系的空物体,其层级结构一定程度上参考现实,父骨骼可以带动子骨骼运动(例如我们抬起大腿,小腿会跟随大腿运动),Unity的父子结构能够很好的表达这一特点。从父骨骼向子骨骼连线,就得到了上图中可视化的骨骼形状,更易于表现出骨骼的形态。
图中Armature表示的就是层级结构的骨骼,body则是人物模型,再次说明模型与骨骼是分离的。
蒙皮
所谓蒙皮,就是将模型的顶点附加到骨骼上的过程,也就是决定哪些“肌肉”受到哪些“骨骼”控制。建立好这样的绑定关系后,当我们驱动手臂“骨骼”时,手臂部分的顶点也会随之运动,从而将动画制作中的控制“顶点”运动简化为了控制“骨骼”运动。
而顶点的蒙皮信息中,包含了该顶点受到哪些骨骼影响(可以有多个),及每根骨骼的权重,这样在一些复杂运动的过程中,顶点跟随变化的轨迹会更加细腻真实,同时能消除关节连接处的一些撕裂情况。
Unity 中使用 Skinned Mesh Renderer(带蒙皮的网格渲染器)来实现这一效果。
骨骼动画
在拿到了一个蒙皮后的人物模型后,我们只需要控制骨骼运动便可以实现带动模型顶点运动。而动画数据,实际上就是记录了各个骨骼,在各个关键帧时的位置、旋转信息。同时利用一些算法实现关键帧间的插值,实现骨骼的平滑移动。(这部分一般交由动画师在专业软件中制作,俗称K动画,也就是K关键帧)
图中所示就是一个动画文件的信息,可以看到各个骨骼在每个关键帧的位置信息。 有了以上准备工作,我们的模型就可以动起来啦。
Ragdoll
搞清楚传统骨骼动画之后,Ragdoll的原理也就十分容易理解了。要想为人物添加Ragdoll效果,只需要在模型骨骼上挂载合适大小的碰撞体及刚体组件,让骨骼运动受物理模拟驱动(而非动画驱动),即可实现基于物理效果的布娃娃系统。
Unity 原生Ragdoll
Unity原生是提供Ragdoll功能的,我们可以右键模型Prefab -> 3D Object -> Ragdoll...
按提示把骨骼对应Transform拖入即可,注意的是,骨骼一般以髋关节为基础,大概在人物腰部偏下 配置好后,Unity会自动生成各肢体碰撞体,之后我们可以手动调整碰撞体形状以适应模型
这时我们再运行游戏,发现人物已经可以像布娃娃一样瘫倒了。
Unity原生的布娃娃系统功能非常简单,我们可以点进之前配置有碰撞体的骨骼节点观察一下。 可以看到肢体骨骼只是增加了一个RigidBody和Collider用于物理模拟,同时用CharacterJoint连接肢体模拟关节,剩余全部交给Unity物理系统进行模拟。
原生 Ragdoll 系统不足
看过Unity Ragdoll系统后,很明显能发现该套系统功能较为简单,有很大不足
- 碰撞体、刚体等组件直接挂载在骨骼物体上,影响骨骼结构的简单性,增加了耦合度
- 没有Animator组件,意味着该Ragdoll系统只能单纯受物理驱动,无法与动画融合(因此Unity官方也建议仅将该系统用于角色死亡时表现)
- 状态切换很困难、难以扩展,且缺乏过渡(比如需要多套ragdoll不同表现时,要修改碰撞体和刚体参数同时控制启用)
Ragdoll Mecanim Mixer
Ragdoll Mecanim Mixer 插件正是为了解决上面的这些痛点而出现的,对于这些问题,该插件都实现了很好的解决方案(该插件可在Asset Store购买,目前Unity最好的Ragdoll插件之一)
- Ragdoll碰撞体与骨骼分离,不直接关联,降低耦合度
- 基于分离结构,可以分别计算物理变换与动画变换,并实现融合
- 基于一套Ragdoll碰撞体可以预设多种状态,切换简单且可控制过渡平滑度
官方文档:assetstore.altinqiran.kz/ramecan-mix…
该插件主要由两个脚本组成
- Ragdoll Constructor
- Ramecan Mixer
Ragdoll Constructor
这个脚本主要用来为角色配置Ragdoll碰撞体及相关信息 挂载上脚本后,首先我们需要选择为哪些骨骼创建碰撞体,规则和Unity原生Ragdoll基本一致。 选好后我们可以手动创建一个Ragdoll Avatar(Scriptable Object),用来保存配置信息(选择已有配置可以避免每次重复设置)
之后我们就可以为每个骨骼设置碰撞体大小、质量、关节可活动范围等配置
配置好Create后,我们就可以看到player外出现一个容器,其中Ragdoll作为单独的物体进行管理,与角色本身解耦
Ramecan Mixer
创建好Ragdoll后,我们可以看到player身上自动添加了一个RamecanMixer组件,这个组件主要负责控制多种状态切换及动画融合功能,可以配置每个骨骼的详细参数,可以参考官方文档,较容易理解
- 当不需要Ragdoll物理效果时可以选择 Is Kinematic 和 Only Animation,完全交由动画驱动
- 当需要Ragdoll物理效果时取消勾选 Is Kinematic,可以配置每根骨骼的详细参数和角度限制
- 参数配置参考 (模拟尸体)见最后一节
配置好后,我们可以添加一个新的状态进行保存,之后可以用脚本控制切换 RamecanMixer.BeginStateTransition(Name)
就可以看到细腻的物理效果啦
RamecanMixer 原理分析
RamecanMixer 插件能够实现ragdoll与骨骼分离、实现动画融合等效果,其物理模拟依然是基于 Unity 物理引擎,主要在于其新增融合算法,并不难理解
在 Bone.cs 中我们可以看到对于Ragdoll骨骼的详细定义,其中两个参数可以留意一下
- animTransform
- physTransform
很明显,Ragdoll 骨骼分别记录了当前由动画驱动的骨骼 Transform(也就是模型骨骼),以及由物理驱动的 Ragdoll 骨骼Transform (位于Ragdoll物体下的一系列碰撞体)
在 RamecanMixer.cs 中,可以看到实现物理效果及与动画融合主要遵循以下流程
- FixedUpdate() 中进行关于 RigidBody 的物理运算,主要是在 rigidbody 与动画骨骼出现偏差时,通过对 rigidbody 施力的方式去“弥补”差距,这样可以实现物体的“惯性”效果
- Update() 中只进行简单的赋值操作,记录上一帧动画骨骼的变换信息
- LateUpdate() 中进行的是核心的动画融合运算,同时会基于前一帧刚体变换与当前帧刚体变换进行插值,实现平滑过渡
有兴趣的可以仔细阅读插件源码,配有注释比较容易理解
Ragdoll 参数配置心得
上面介绍了 Ragdoll 实现原理,但是要想实现较好的模拟效果,需要对各个骨骼进行详细配置,同时反复耐心的调试,最终才能达到想要的效果,这里可以对一些重要参数提供一些参考,主要用于模拟的角色死亡效果
质量配比
要实现较好的布娃娃效果,最重要的是各骨骼的质量分配,这里建议以实际人体的质量分配为基准
- 头部 – 7.30%
- 躯干(胸部,背部和腹部) – 50.80%
- 大腿 – 9.88%
- 小腿 – 4.65%
- 上臂 – 2.7%
- 前臂 – 1.60%
- 脚 – 1.45%
- 手 – 0.66%
大腿等四肢,均指单条质量。人体总重设置60-100KG之间较为合理
在研究了顽皮狗在 GDC2017 上关于 Ragdoll 的演讲(Physics Animation in Uncharted 4: A Thief's End)后,发现他们对于质量分布有一套经验规律
即设置 Ragdoll 骨骼质量时不要严格遵循实际人体质量分布,要在实际质量的基础上乘以对应百分比,这个系数从髋部开始向上下逐渐递减 实际测试效果确实比严格遵循实际质量分布更为符合直觉
RamecanMixer参数
- 开启self Collision
- Rotation Accuracy设为0.2或更低(保证关节灵活度)
- 角度限制开启(具体角度在Construct阶段已配置好,建议参考人体关节可动范围)
- Joint Drive 中 Spring Rotation设为较低数值,保证关节可以摆动,数值较高会导致关节较硬(会努力回弹到原始形态)
总结
Unity 实现 Ragdoll 效果还是较为容易的,尤其是在现成插件的基础上,我们要做的主要工作就是详细配置 Ragdoll 参数,使其符合我们希望的效果。 之后我会基于这套系统研究一下除死亡动画外,Ragdoll与其他动作的物理融合(如攀爬等),希望实现顽皮狗在神海4中的物理效果
顽皮狗GDC参考链接:www.youtube.com/watch?v=7S-…