Unity动画系统笔记

本文详细讲述了如何在Blender中制作手部动画以适应UnityAvatar系统,涉及骨骼轴向调整、UnityAvatar配置、动画Rig问题、RootTransformRotation设置以及动画事件处理等内容,同时讨论了动画在实际应用中遇到的问题和解决方案。
摘要由CSDN通过智能技术生成

Avatar系统

配置方法

 如果使用Avatar,就要在Animator的Avatar填入一个Avatar:

8a76dfc389b205490743429204b517f2.png

状态机的所有动画记录的都要是Avatar数据:

29ef3640f663c710ff1f576417c35826.png

不用Avatar则动画记录的是这个人物的骨骼节点的位置旋转和缩放:

6ddb6390b2acac39e6c171df6caf91bc.png

否则人物就是这样:

0bca19711b516d23e5c3ffb7dab8a936.png

如果不用Avatar会出现的问题

不使用Avatar,还想给骨骼名称相同的不同人物复用同一个动画,会出现的问题有:1.同一个部位的骨骼长度不同发生动画错位:

85026d4d37897df39d1ee59f3be1c150.png

一个可能的解决方法是在blender里关键帧只记录旋转不记录位置:

670a833e0bea6619a22d2849f3a9d68e.png

试了一下,这个方法没用。做了一个只记录右臂旋转的动画:

89f5c54a842caa982ea1982cd4217721.png

da7327bacceff68992ff4a03a9e12d09.png

复用给其他人,严重错位:

7e3d9d2891c3f65aa310ea857e687ef8.png

因为导入到Unity的动画,不管blender里那个骨骼有没有关键帧,都会被记录位置旋转缩放:

e8c500782986741b551a45de02b0ce59.png

Configure Avatar

背景:应用Avatar动作会出现变形的问题

在blender里做一个举起右手的动画:

9a4d26fdaf26dbe662c8929196d2bac2.png

到Unity里应用Avatar后变成了手掌朝下的举手:

276551a8a05ff5e0bb403ab9f0ad445a.png

研究发现,使用Avatar重定向后的动画效果和Avatar的配置有关系。要把一个人物的动画精确复用给另一个人物,必须保证

1.人物在T pose,包括手掌向下,大拇指向前。上面的问题就是手掌没向下。

2.Configure Avatar界面里每个骨骼的世界旋转一致(但不代表每个骨骼的轴向和局部旋转要一致。比如两个骨架手部骨骼的轴向不一样,但它们在Configure Avatar里都是手掌向下,大拇指向前,此时它们手骨的局部旋转不一样,但复用也没问题)。但是做游戏人物时还是务必保证不同人物的骨骼轴向、Avatar配置里的骨骼的局部旋转都一致。

为此需要制定一套骨骼轴向和Avatar配置的标准。一种简单的标准是保证Avatar配置里T Pose里尽量多的骨骼和世界坐标轴平行。Hips、Spine、Chest、Neck、Head、Leg、Knee竖直,Shoulder、Arm、Elbow、Wrist左右水平。其他的手指、脚还没有标准,先由Enforce T pose自动摆。这样大部分骨骼在Avatar配置的旋转都是90度的整数倍。

下图就没有遵循这套标准,Chest向后倾斜,Shoulder向下倾斜。

25f14f5ce5b2d45301e98bb507bfe2f6.png

如果不对可以选中骨骼调整旋转。

8ec0794370bf51ff10ded8d1d874c723.png

 动画Rig选择Copy From Other Avatar时报错的解决

看报错信息,是已有的Avatar里的Jaw对应的节点+ToothBone_D_A01没有找到。因为Jaw不是一个很重要的骨骼,可以把已有Avatar里配置的Jaw删掉。

c1f3f87ab453de99579804c3098e6b8f.png9c3ea595c6d4e09274dc3902bfd5a390.pngf89284da2c4d7d4acb2f9e5551af5064.png

动画复用变形的问题

一个动画对安柏把手和头调正,复用给刻晴,手和头歪了。配置Avatar的时候我是保证从Hips到双手的轴向两个人是一致的,但是动画里根骨骼Hips的旋转都有明显的区别

93f68b62bf04377d2763c45187a8e993.pngd5d7bb29a962d9c963216fca91ceeea1.png

Hips骨骼的旋转值:差别明显

安柏c6a804357a4ab74c4c35a64b322c5c2a.png

刻晴e04bbc45714717b95cd33b1cde23e03f.png

后来观察发现这个刻晴的Chest明显比安柏靠下,Spine骨骼短

调整过之后刻晴的手和头也摆正了:

这件事的结论是:骨骼长度会影响动画复用的效果,具体机制不清楚,但应该尽量保证各骨骼的长度比例相近。

把一个动画的Root Q复制给另一个,预览时两个动画人物的Hips的旋转不一样

研究发现,人物的Hips的旋转不单受Root Q影响,Spine、Chest、Upper Chest都会影响。在Animation窗口动一下这几个部位的参数,发现上下身都变化了。

关于Root Transform Rotation

60448febea91318deb89b0ceaffe2e0b.png

Bake Into Pose勾选则动画里的旋转不会影响人物在世界里的旋转。

Based Upon:选择Body Orientation就把人物胸口的朝向作为人物的正前方。如果人物的姿势是侧身或斜侧身(如持枪),就不应该选这个选项。如下图,选择Body Orientation,人物胸口朝向前方,头和枪就朝向侧前方。

d1f3c27193f797bdecc00f7fec0df6b2.png

Original:把人物的根节点z轴作为人物前方。持枪状态应该选此选项。且可以发现,地上的红箭头指向的就是人物胸口的朝向。

a1da348a1e06fd334f1bbad17fcc43b4.png

人物向左、右走的动画同理。

如果选Body Orientation,则人物的胸口对准正前方,人物向左前方移动:

c1702dece3e1e66b279bd29d89eb732b.png

侧向走路应该的效果是,人物的胸口对向侧前方,人物向正侧方移动:

5cebb8c6ff76eb69aa57342256d31974.png

故应该选Original。

状态脚本的OnStateEnter()和OnStateExit()执行先后的问题

在一个状态的OnStateExit()打印退出了,下一个状态的OnStateEnter()打印进入了,执行:

ef72c8d4e05f85249582ce5fa573ed36.png

说明是先执行下一个状态的OnStateEnter(),可能在过渡开始时就执行了,过渡结束时才执行上一个状态的OnStateExit()

关于动画事件

动画事件没有执行

1.在一个动画事件里设置一个transform的父节点,然后设置了这个transform的position和localEulerAngles,设置父节点生效了,设置position和localEulerAngles无效,transform的位置和旋转是在之前父节点坐标系里的值。设置旋转后打印了localEulerAngles,和设置的一样,但是检查器里是在之前父节点里的旋转值,场景里看也不对。

5faa1985423d5e95a4e189d33880a9ff.png

 Unity有两种类型的动画事件

1.选中动画片段,再点Animation

fb015acd8619f91bd44f1630d305605a.png

此时动画参数前面没有物体名称:

e5b1b80403a2418faa2e079617a7007d.png

此时点动画事件,需要输入回调函数的名字,并允许给4个参数:

f94630e5a1343af04406ab656aba573c.png

2.选中物体,再点Animation

动画参数前面有物体名称:

6aefaa519f5d42a3f9fcf8bcb62b8207.png

选中动画事件,需要指定物体的一个组件脚本里的一个方法:

8665226ae5fab6b3d5e1f7a9de561ac7.png

同一帧有多个动画事件

第一个标记为一个竖线,后面的标记为越来越短的竖线。

两个版本的动画片段:非Legacy和Legacy

 之前做了一把枪的回膛动画,没问题,去看那把枪的Animation Clip的检查面板,是这样的:ef4dab58f64a1d8e946a7f35882b82d4.png

这次做的出问题的Animation Clip的检查面板是这样的:2d6ce2a243c1901d1a17f5a0e9c0153b.png

发现在Project点右键建的Animation Clip的检查面板和图二一样:

39f79e0b2e14d1b4418a07c6348ac71c.png

在Animation窗口点Create New Clip建的Animation Clip的检查面板和图一一样:

686be204459e2d8d3e125db776285214.png

执行时报了警告:Animation组件使用的Animation Clip必须被标为Legacy,也就是说上面图一检查面板的就是Legacy的Animation Clip。

8971eb0b4a35acae36e28a1966bfc44c.png

把Legacy动画片段赋给Animator则会报如下警告:

结论:创建给Animation组件使用的Animation Clip必须使用Animation窗口的Create New Clip,创建的动画片段属于legacy动画片段。686be204459e2d8d3e125db776285214.png

另一个分辨Legacy动画片段的方法:

打开动画片段的.anim文件,m_Legacy:1的是Legacy动画片段:

关于Root Transform

如果没有勾选某个Bake Into Pose:

e69df8d74cd6c08f7557c573308d7c45.png

那么预览时人物相应的位移或旋转就不会显示,但是运行时人物的根节点会位移和旋转。Animation窗口Avatar里相应的Root T和Root Q只有第一帧能修改,后面不能修改。比如Root Transform Position(XZ)不勾选,Root T.x和Root T.z就只有第一帧能修改,后面都保持第一帧的值。

4a808146e484978770bc888092e3bd69.png

勾选了某种运动的Bake Into Pose,如XZ,Root T里的x和z任意帧都能修改,且在预览里能看到人物相应的位移或旋转,而运行时人物的根节点不会有相应的位移或旋转。

结论:不勾选Bake Into Pose时,1.只能修改第一帧相应的Root T和Root Q;2.预览里没有相应的位移、旋转效果;3.运行时人物根节点有相应的位移、旋转效果。勾选Bake Into Pose时,1.可以在任意帧修改相应的Root T和Root Q;2.预览时显示Root T和Root Q;3.运行时人物根节点没有相应的位移、旋转效果。

应用

那么如果想给一个动画加xz平面内的运动效果,方法就是1.不勾选Root Transform Position XZ;2.在Animation窗口调整Root T.x和Root T.z给一个位移;3.勾选Root Transform Position XZ

关于IK

遇到的问题:在Animation窗口里预览的和运行时的效果不一样

想把跳跃的动画的弯的腿调直,动画预览窗口效果:

041e50e935bc31d47c137cf70a012b95.png

运行效果:

00fce0efd7ad1375eb7a105c0be20bcd.png

另一个动画在动画窗口预览和运行时的效果:

fd2c21d6e9dc98240a96947cc3eb010a.png89b43ff8ce3d0d959803f6cc2be4b6e8.png

经过实验:

运行的效果是之前的一个版本,好像对动画的修改没有保存下来。

其他动画没问题

新建一个动画片段文件,从出问题的动画复制全部关键帧,有问题

从fbx的动画里复制全部关键帧,运行和fbx动画的效果一样;

从出问题的动画把Right Upper Leg的3个参数的关键帧覆盖,没有生效;

把Root T的关键帧覆盖,生效了;

从没问题的动画把右腿右脚的参数的关键帧覆盖,没有生效;

把Right Foot T覆盖,,右腿生效了;之前在预览里调Foot T,没有效果;试着把Left Foot T关键帧全删除,预览里没有任何不同,但是运行时变成了这样:91fea302c4e208c4107d1ccb397c78e3.png

说明:

1.Foot T这个参数在预览里看不出效果,在运行时才能看出来。

2.但是它影响了整个腿部的效果,它没有调好,只调好Upper Leg、Lower Leg、Foot的参数在运行时是无效的

使用脚本关闭脚的IK权重,可以消除Foot T、Foot Q的影响:

c61260e288d4510981794c09f0633bc9.png

查资料:

Animator-leftFeetBottomHeight - Unity 脚本 API (unity3d.com)

得知Foot T、Foot Q、Hand T、Hand Q就是足部和手部IKGoal的位置和旋转,这4个参数在预览里是无效的,在运行时有效,会导致运行时的动画和预览时效果不一样。可以在脚本的OnAnimatorIK()里设置SetIKxxxWeight控制是否启用。还需要搞清楚位置和旋转是相对谁的。

animator.SetBoneLocalRotation()的问题

使用animator.SetBoneLocalRotation()写入骨骼的localRotation,骨骼的旋转也会改变。

void OnAnimatorIK(){
        //旋转手臂改变仰角
        if(rotateArm){
            Quaternion leftArmRot=Quaternion.AngleAxis(angleX,
            leftArm.InverseTransformDirection(transform.right));
            animator.SetBoneLocalRotation(HumanBodyBones.LeftUpperArm,leftArm.localRotation);
            Quaternion rightArmRot=Quaternion.AngleAxis(angleX,
            rightArm.InverseTransformDirection(transform.right));
            animator.SetBoneLocalRotation(HumanBodyBones.RightUpperArm,rightArm.localRotation);
        }
    }

对运动动画腿部穿模的调整

为了排除调动画时IKGoal的影响,选择不启用IK,导致IK对腿部穿模的调整作用也没了,只能手动调整防止穿模。

找出一条腿走路循环的五个关键帧:迈出、离地、两次两腿交错和用于循环的,把其他关键帧删除,可以防止插有原来的关键帧造成的抖动。

关于Animation组件

使用Animation组件就是为了方便给不同枪指定不同动画,但是没找到任何方法得到检视器里的Animations数组,Animation.Play()是通过动画片段名字的字符串控制播放哪个片段的。就是说想要不同枪播放各自的后座动画,要么

1.在脚本里写死片段的名字,给不同枪的后座动画起相同的名字;

2.再声明几个字符串字段记录使用的动画片段的名字;

3.再或者声明几个AnimationClip字段,执行animation.clip=clip1;

这个设计很脑残。我预想的是直接能访问Animations数组,animation.Play()输入一个数字指定播放第几个动画片段。

又试了一下animation.AddClip()这个方法,能把一个AnimationClip加到Animations数组里,并给它取个别名。又是让人匪夷所思的操作,这个AnimationClip本身没有名字吗。我突然想到这个别名可能演变成了后来状态机里的状态名。

经过以上的实验,我决定枪的动作动画也由Animator来做,给每种枪做一个AnimatorController,里面三四个状态,也不会太复杂。

Animator组件有Root position or rotation are controlled by curves

动画状态机里包含的动画含有Position或Rotation的关键帧时,会出现这段话。即使没有勾选Apply Root Motion,物体的位置旋转还是会被影响。

运行中动态修改动画状态机使用的动画片段

这需要用到另外两个类,RuntimeAnimatorController和AnimatorOverrideController。

RuntimeAnimatorController - Unity 脚本 API

AnimatorOverrideController - Unity 脚本 API

为什么需要这两个类?根据我的理解,Animator Controller出现在Assets窗口,和模型、动画片段、脚本、预制体一样,是一种资源,所有的资源运行时都不能修改。要动态修改动画状态机,必须定义一个它在运行时的对应类型,就像预制体运行时不能修改,但是预制体实例可以修改,这就是RuntimeAnimatorController。RuntimeAnimatorController拥有animationClips字段,能获得状态机里所有动画片段的名字,但是还没有改变里面动画片段的方法。

而AnimatorOverrideController包含了一个RuntimeAnimatorController,拥有一个索引器字段,可以根据动画片段名字读取动画片段、指定要替换的动画片段名字。知道了它们的区别,我还是不明白有什么必要定义两个类,好像完全可以用一个类的一个字段读写。

AnimatorController的官方文档也暗示了这一点,AnimatorController是UnityEditor里的类,使用UnityEditor的脚本都不许打包导出,否则报错,就是不允许运行时脚本修改AnimatorController。

Animations.AnimatorController - Unity 脚本 API

具体操作看这篇文章。

Unity中Animator动态添加AnimationClip - 炘恪 - 博客园 (cnblogs.com)

这段代码新建了一个AnimatorOverrideController,让里面的RuntimeAnimatorController等于AnimatorController里的RuntimeAnimatorController,然后修改里面的动画片段,再把自己赋给Animator的RuntimeAnimatorController。看起来操作有点多余。

我试了简化成下面的代码:

没有生效。

我试了试删除那一句animator.runtimeAnimatorController=null,报了这个错:

超出了我的理解能力。

替换哪个动画片段是通过动画片段名字字符串指定的,这个也不太好用。希望能通过状态名指定替换哪个动画片段。

总结一下这4个类的特点:

Animator

相当于动画播放器。

Animator Controller

继承自RuntimeAnimatorController,记录多个动画片段和转换关系的文件,是一种Asset,运行时不能修改。

RuntimeAnimatorController

Animator Controller在运行时的形式,和Animator Controller的关系类似类和实例。

AnimatorOverrideController

继承自RuntimeAnimatorController,用于修改RuntimeAnimatorController的类。不知道为什么非要定义它。

它们的关系:

.overrideController文件

又看到了这篇文章

Unity Runtime创建和编辑AnimationClip - 弹吉他的小刘鸭 - 博客园 (cnblogs.com)

学到了更好用的方法:.overrideController文件。可以在一个AnimatorController的基础上对不同人替换一些动画片段,但还不能解决对话时动态修改同一个状态的动画片段的需要。

然后我知道了.overrideController其实就是AnimatorOverrideController类型的文件格式,上面那一段代码对应到编辑器操作,分别是:

对应

对应

对应

对应在按Backspace把Controller变成None

对应

那么这一套代码无效的原因也就清楚了,这里创建了一个.overrideController,把它的源.controller指定成新动画片段,但是没有改animator.runtimeAnimatorController。

然后其实那句animator.runtimeAnimatorController=null是可以删掉的,报错是因为initialAnimatorController是空的。

.overrideController文件和RuntimeAnimatorController代码联合使用的问题

把.overrideController文件交给animator使用:

执行下面代码的时候:

报错:

这里是试图把一个.overrideController赋给另一个.overrideController的Controller:

很明显这是不行的。

我又发明了一种写法,如果人物用的本来就是.overrideController,即重写的状态机,就不再新建AnimatorOverrideController;如果是.controller,完整的状态机,再新建AnimatorOverrideController。

可以看到,对于原本使用.controller的人物,这么操作后变成了:

Controller是运行时创建的无名.overrideController。

问题记录

Broken text PPTr in file(Assets/Resources/Animators/Animator Controller1.controller). Local file identifier (-6880487854150155466) doesn't exist!

保存Animator Controller时出现此错误。暂时没什么影响。

bd8410852a6971cf0f305571ff824bc7.png

人物挂有RigidBody,运行时人物缓慢上升

55258686737f0f812fc2b08cc6029c08.png

原因:动画设置里没有选择Root Transform Position(Y)的Bake Into Pose,具体原因不清楚。推测是动画改变了人物的y方向位置,RigidBody保持了这个速度。但是试了y方向没有位移的动画和y方向向下移动的动画,都会向上移动。另外,人物1.不挂RigidBody;2.不选Use Gravity;3.不挂Animator;4.不选Apply Root Motion都不会有此现象。

e68685121142cec6761ce125adf03e38.png

解决方法:没有打算让动画改变位置或旋转一定要Bake Into Pose。

Animation窗口点击Preview后有的人物会到世界原点,有的人物不会

4b326913f66f770bbe549e33bba06928.pnga15f0ec883dad20b7cce2b3d256f2565.png

对于脚本里没有OnAnimatorMove(),也就是Apply Root Motion没有变成Handled by Script的人物,勾选Apply Root Motion时,预览动画人物回回到世界原点,没有勾选时,在原地。

经过实验发现,对于Apply Root Motion变成Handled by Script的人物,预览动画时是否回到世界原点取决于把相关脚本移除后是否勾选了Apply Root Motion。

6fc2e652dec99def95f39b8cc651b54f.png

点击预览动画,人物不见了,人物的pivot还在原地

5e1e7334eda458c4e2c480de2f1200e7.png

原因:动画里的Root T.y在-51,就是人物跑到了下面-51的地方。

4b5beffa73a7971eaefe84e8b9581fab.png

骨架放在场景里,挂载animator,Animation窗口点预览,无效

41a7ebbe3e075cc44adf8ed87cfa8666.png

原因:需要给骨架加一个父节点,animator组件加在根节点上。

03f22b2626454a419523006a73bee180.png

Animation组件执行Animation.Play()返回Default clip could not be found in attached animations list.

背景:做枪械回膛动画,因为比较简单,就用了Animation组件。

983c2f2d69eb52c296f270db55f2c0ef.pnga6bc4923c769217793749c62d8810e3b.png

XXX AnimationEvent has no function name specified!

但是动画事件的方法指定了,也执行了。

原因:注意动画事件竖线后面的短竖线!代表同一帧的其他动画事件。

人物死亡没闭眼

状态机Eyes层显示进入了死亡状态,死亡状态有闭眼动画,预览时动画有效。

从Any State进入一个状态不停反复

排查过程:因为是第一次用Any State,我很怀疑和它有关,就改成从一个状态过渡到死亡,结果人物正常播放死亡动画。难道是因为这个Dead也被算做Any State了,结果就是Dead和它自己之间不停过渡?

然后随便翻看,看到Any State到Dead的过渡有这么一个参数Can Transition To Self,感觉有关系。不勾选,解决。

又一个坑啊!

Animator窗口状态图看不见状态

解决方法:按F,聚焦到默认状态。

animatorOverrideController.ApplyOverrides()一次重写多个动画剪辑没生效

代码基本上是跟官方例子抄的。

AnimatorOverrideController - Unity 脚本 API (unity3d.com)

原因:List没有这几个键值对,需要Add(),直接用索引赋值相当于没做。应该这样写:

当初我学习Unity系统的时候,我做了一些笔记,希望能帮到你入门。下面是一些关键点: 1. Unity是一个跨平台的游戏开发引擎,可用于开发2D和3D游戏。它提供了一个可视化的编辑器,让你可以轻松地创建场景、对象、材质等。 2. 编辑器界面:Unity的编辑器界面分为场景视图、层次视图、资源视图和检视视图等。场景视图用于查看和编辑场景,层次视图显示场景中的对象层次结构,资源视图用于管理项目中的资源,检视视图则显示了当前选中对象的属性和组件。 3. 游戏对象:Unity中的一切都是游戏对象,包括角色、道具、相机等。每个游戏对象都可以附加多个组件,比如渲染器、碰撞器、脚本等,用来实现不同的功能和行为。 4. 脚本编程:Unity使用C#作为主要的编程语言。你可以编写脚本来控制游戏对象的行为。脚本可以挂载到游戏对象上,通过组件来访问和修改游戏对象的属性和方法。 5. 场景管理:通过场景管理器可以创建、编辑和切换不同的场景。你可以在场景中添加、移动、旋转和缩放游戏对象,设置摄像机视角,调整光照效果等。 6. 资源管理:Unity提供了资源视图来管理项目中的资源,包括纹理、音频、模型等。你可以导入和导出资源,并在项目中进行引用和使用。 7. 物理引擎:Unity内置了物理引擎,可以模拟物体的运动和碰撞。你可以给游戏对象添加刚体组件,设置质量、重力、碰撞检测等属性,实现真实的物理效果。 8. 动画系统Unity提供了强大的动画系统,可以创建和编辑角色的动画。你可以通过动画控制器来管理不同的动画状态,并通过脚本控制角色的动画播放和过渡。 这些仅是入门的基本知识点,希望对你有所帮助。如果你还有其他问题,可以继续提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值