Unity3D教程:动画融合、动画层、动画混合、附加动画、程序动画、动画重放和取样
2015-06-05 18:00
253 查看
原帖地址:http://www.unitymanual.com/5323.html
动画脚本AnimationScripting
Unity's动画系统允许你创建一个漂亮的动画蒙皮角色,动画系统支持动画融合,混合,添加动画,步调周期时间同步.动画层,控制动画回放的所有方面(时间,速度,混合权重)每个顶点有1.2.4个骨骼影响的mesh,基于物理系统的布娃娃系统,另外还有程序动画.为了获得最佳效果推荐您在制作模型和动画绑定前阅读一下ModelingOptimizedCharacters章节。。Unity3D教程手册
制作一个动画角色主要包括两个方面;在世界中移动和由此产生的动画。如果你想了解角色移动相关的更多内容,请参阅CharacterControllerpage.实际上角色动画是由Unity's脚本界面完成的。
你可以下载exampledemos中预设置好的动画角色.当你学完本页的基础部分你还可以看一看animationscriptinterface.
AnimationBlending动画融合
在现今的游戏中AnimationBlending是一项保证游戏动画顺畅过渡的基本的特性.动画师创建的动画例如:walk循环,run循环,idle原地空闲动画或射击动画.在游戏的任何时间点你都有可能从空闲站立转换到走动,反之亦然.当然你不希望两个不同的动作之间突然跳转,你需要动画平滑过渡.
而这个问题的解决就依赖动画融合技术.在Unity中你可以让同一个角色拥有任意数量的动画.所有这些动画融合添加成为一个总的动画.
首先我们来为一个角色添加两个动画原地空闲站立和走动并平滑的使这两个动画过渡.为了使我们在写脚本时简单些,首先我们设置动画的WrapMode为Loop.然后关闭PlayAutomatically来让我们的脚本来独占动画的播放.
我们第一个动画脚本很简单;我们需要一些方法来探查角色移动的有多快,然后在走和站立之间淡入淡出.在这个简单的测试中我们使用pre-setupinputaxes.
下面我们来让这个脚本运行:
1.创建一个js脚本Assets->CreateOther->Javascript.
2.把代码贴进去。
3.把脚本拖拽给角色character(ItneedstobethesameGameObjectastheanimation)
点击Play按钮,当你按上下键时角色会走动,松开上下键时角色站立不动、
动画层AnimationLayers
层是一个非常有用的概念它可以让你将动画片段任意成组并且区分优先顺序。在Unity's动画系统中,你可以混合任意数量的动画片段。你可以手工分配权重或者直接使用animation.CrossFade(),来自动分配权重。。Unity3D教程手册
混合权重混合权重总是在应用前被规格化normalized。
比如说我们现在有一个walkcycle和一个runcycle,权重都是1(100%).当unity计算最终动画时会规格化权重,这意味着walk占50%权重,runcycle占50%权重。
这在大多数情况下都是不错的,但当两个动画片段同时运行而其中一个权重明显大于另外一个。那么你需要手动调整权重值,但如果你使用动画层来解决这个问题过程会容易得多。
制作动画层的范例LayeringExample
例如现在你有一个射击动画,一个空闲站立,一个走动循环。你需要在走和站两个动作间持续的淡入淡出(在玩家走动速度的基础上)但当玩家射击时我们只想展示射击动画。因而射击动画此时的优先度最高。
为了达到这一目的最简单的方法是在射击时简单的保持walk和idle动画。接下来需要确定shootanimation在一个比idle和walk更高的层.这意味着shootanimation将首先收到混合权重.walk和idle只有在shootanimation不使用100%混合权重的情况下接收权重.所以当CrossFadingtheshootanimationin,权重将从0开始很短时间内到达100%.在开始阶段walk和idle层将依然可以收到混合权重
但当shootanimation完全切入时,他们就收不到权重了。这才是我们需要的!
默认情况下animation.Play()和animation.CrossFade()将停止或淡出在同一层里面的动画.这是我们在绝大多数情况下需要的.在我们shoot,idle,run范例中,播放idle和run将不会影响到shoot动画反之亦然(youcanchangethisbehavior(行为)withanoptionalparameter(任意参数)toanimation.CrossFadeifyoulike)。
动画混合AnimationMixing
动画混合可以让你缩减你必须为游戏制作的动画片断数量,方法是制作只对身体某个部分起作用的动画。这意味着这些动画可以和其他动画合并起来一起使用。
如果你想给一个动画添加animationmixingtransformtoananimationbycallingAddMixingTransform()onthegivenAnimationState.
混合范例MixingExample
例如你可能有一个挥手(hand-waving)动画.你可能需要让一个空闲站立(idle)角色或者一个走动(walking)角色来挥手.如果没有动画混合你可能需要制作两个挥手hand-waving动画:一个给idle,一个给walking.可是,如果你将挥手(hand-waving)动画作为一个mixingtransform添加到shouldertransform,挥手动画将只控制肩膀.身体余下部位不受其影响,下半身会继续播放idle或者walk动画.因而你只需要一个挥手(hand-waving)动画。
附加动画AdditiveAnimations
附加动画和动画混合可以让你缩减为游戏制作的动画片断的数量,并且对面部动画(facialanimations)来说非常重要,我们来看看如果创建一个在跑和转身时身体可以自动倾斜的角色。
你已经制作好了一个walk和run循环,现在你还要制作一个走动左倾(walk-lean-left),走动右倾(walk-lean-right),跑左倾(run-lean-left),跑右倾(run-lean-right)动画.
这意味着你需要多做4个动画片断!制作这么多数量的动画会累死人的.而附加动画(Additiveanimations)和混合(Mixing)可以大大减少这些工作量!
附加动画范例AdditiveAnimationExample
附加动画允许你在顶层覆盖其他所有可能播放的动画的效果(allowyoutooverlaytheeffectsofanimationontopofanyothersthatmaybeplaying).当你制作一个附加动画时,Unity将计算动画片断里的第一帧(firstframe)和当前帧(currentframe)的差异.然后它将在所有其他播放的动画之上应用这个差异(Thenitwillapplythisdifferenceontopofall
otherplayinganimations).
现在你只需要制作一个左倾(lean-left)和右倾(lean-right)动画.Unity将为此倾斜动画新建一个层并置于walk,idle或run循环的层级之上.
下面是代码:
提示Tip:
当使用附加动画时它会判断你同时也在播放一些其他的使用了附加动画的非附加动画,否则动画将添加到最后一帧结果的顶部,这通常不是你所需要的。
程序动画角色ProcedurallyAnimatingCharacters
有时你需要程序化的驱动你的角色骨骼.例如你可能需要你的角色的头注视3d空间的某个点.这个活最好让脚本来干.幸运的是,Unity做这个很容易.在Unity中所有骨骼来驱动蒙皮网格(skinnedmesh)的变换(Transforms).因而你可以给角色的骨骼写脚本,就和其他GameObject一样.
很重要的一点是动画系统updatestheTransforms是在Update()function调用之后,LateUpdate()function调用之前.因而如果你要调用LookAt()function你应该dothatinLateUpdate()tomakesurethatyouarereallyoverridingtheanimation.
布娃娃系统Ragdolls也是用同样的方法制作出来的.你可以简单的把刚性物体(Rigidbodies),角色关节(CharacterJoints)和胶囊碰撞体(CapsuleColliders)连接给不同的骨骼.这样物理系统就可以作用于蒙皮角色(skinnedcharacter).(什么是布娃娃系统,当你在射击类游戏中打死对手时可以注意到当角色快接近地面时,他的四肢开始瘫软在地面上,这个不是动画师调出来的,而是布娃娃系统自动计算出来的。)
动画重放和取样AnimationPlayback和Sampling
这一部分将说明引擎如何在动画重放时取样.
动画片断制作时总是有一个特定的速率.举例来说,你可能在Max或Mayaat创建了一个帧速为60frames每秒(fps)的动画.当导入Unity后,输入模块将读取帧速,所以导入的动画帧速还是60fps.
可是,游戏运行时的速率是不断变化的.有的电脑帧速快有的电脑帧速慢,即使是同一台电脑前一秒和后一秒因为视角的不同帧速也不一样.基本上当游戏开始运行时我们无法确定一个精确的帧速.这意味着即使我们的动画片断制作时是60fps,它重放时也许用的是另外一个速率,例如56.72fps,或83.14fps.它可以变成任何一个速率.
Unity对这些变化的速率取样,不在于其制作时的速率.幸运的是,3d电脑图形动画不是由分散的动画组成,确切地说是由连续的曲线构成的.这些曲线可以让我们在任何时间点取样;而不是适配某一个原始帧的时间点.I这也意味着如果游戏运行速率高于原始制作速率,动作事实上看起来会更平滑流畅.
对绝大多数应用场合,Unity对变化帧速的采样我们无需对其进行干预.可是,如果你的某个游戏逻辑所依赖的动画变化或道具(transformsorproperties)结构十分特殊,那你必须知道这一点.举例说,如果你有一个动画是把一个物体30帧内从0旋转到180度,你想从代码中得知什么时候动画完成一半,你不能写一段条件语言来检查现在旋转值是不是90度.因为Unity依照游戏的变化速率来对动画采样,它可能在旋转快到90度时进行采样,或者是刚好过90度的时候采样.如果你需要通报动画中一个特殊点到达时,
你可以使用AnimationEvent来替代.
同样需要注意的是变化的帧速采样结果,一个使用WrapMode.Once模式重放的动画的采样不一定是精确的最后一帧(lastframe).在游戏中很有可能是刚好结束前的某一帧,在下一帧时间可能超过动画的长度,soitisdisabled和notsampledfurther.如果你需要动画的最后一帧采样精确,你可以使用WrapMode.ClampForever.如果是那样的话动画将不停的对最后一帧进行采样直到你自己停止动画.
动画脚本AnimationScripting
Unity's动画系统允许你创建一个漂亮的动画蒙皮角色,动画系统支持动画融合,混合,添加动画,步调周期时间同步.动画层,控制动画回放的所有方面(时间,速度,混合权重)每个顶点有1.2.4个骨骼影响的mesh,基于物理系统的布娃娃系统,另外还有程序动画.为了获得最佳效果推荐您在制作模型和动画绑定前阅读一下ModelingOptimizedCharacters章节。。Unity3D教程手册
制作一个动画角色主要包括两个方面;在世界中移动和由此产生的动画。如果你想了解角色移动相关的更多内容,请参阅CharacterControllerpage.实际上角色动画是由Unity's脚本界面完成的。
你可以下载exampledemos中预设置好的动画角色.当你学完本页的基础部分你还可以看一看animationscriptinterface.
AnimationBlending动画融合
在现今的游戏中AnimationBlending是一项保证游戏动画顺畅过渡的基本的特性.动画师创建的动画例如:walk循环,run循环,idle原地空闲动画或射击动画.在游戏的任何时间点你都有可能从空闲站立转换到走动,反之亦然.当然你不希望两个不同的动作之间突然跳转,你需要动画平滑过渡.
而这个问题的解决就依赖动画融合技术.在Unity中你可以让同一个角色拥有任意数量的动画.所有这些动画融合添加成为一个总的动画.
首先我们来为一个角色添加两个动画原地空闲站立和走动并平滑的使这两个动画过渡.为了使我们在写脚本时简单些,首先我们设置动画的WrapMode为Loop.然后关闭PlayAutomatically来让我们的脚本来独占动画的播放.
我们第一个动画脚本很简单;我们需要一些方法来探查角色移动的有多快,然后在走和站立之间淡入淡出.在这个简单的测试中我们使用pre-setupinputaxes.
01 | functionUpdate(){ |
02 | |
03 | if(Input.GetAxis(“Vertical”)>0.2) |
04 | |
05 | animation.CrossFade(“walk”); |
06 | |
07 | else |
08 | |
09 | animation.CrossFade(“idle”); |
10 | |
11 | } |
1.创建一个js脚本Assets->CreateOther->Javascript.
2.把代码贴进去。
3.把脚本拖拽给角色character(ItneedstobethesameGameObjectastheanimation)
点击Play按钮,当你按上下键时角色会走动,松开上下键时角色站立不动、
动画层AnimationLayers
层是一个非常有用的概念它可以让你将动画片段任意成组并且区分优先顺序。在Unity's动画系统中,你可以混合任意数量的动画片段。你可以手工分配权重或者直接使用animation.CrossFade(),来自动分配权重。。Unity3D教程手册
混合权重混合权重总是在应用前被规格化normalized。
比如说我们现在有一个walkcycle和一个runcycle,权重都是1(100%).当unity计算最终动画时会规格化权重,这意味着walk占50%权重,runcycle占50%权重。
这在大多数情况下都是不错的,但当两个动画片段同时运行而其中一个权重明显大于另外一个。那么你需要手动调整权重值,但如果你使用动画层来解决这个问题过程会容易得多。
制作动画层的范例LayeringExample
例如现在你有一个射击动画,一个空闲站立,一个走动循环。你需要在走和站两个动作间持续的淡入淡出(在玩家走动速度的基础上)但当玩家射击时我们只想展示射击动画。因而射击动画此时的优先度最高。
为了达到这一目的最简单的方法是在射击时简单的保持walk和idle动画。接下来需要确定shootanimation在一个比idle和walk更高的层.这意味着shootanimation将首先收到混合权重.walk和idle只有在shootanimation不使用100%混合权重的情况下接收权重.所以当CrossFadingtheshootanimationin,权重将从0开始很短时间内到达100%.在开始阶段walk和idle层将依然可以收到混合权重
但当shootanimation完全切入时,他们就收不到权重了。这才是我们需要的!
01 | functionStart(){ |
02 | |
03 | //Setallanimationstoloop设置所有动画为循环 |
04 | |
05 | animation.wrapMode=WrapMode.Loop; |
06 | |
07 | //exceptshooting除了射击(不循环) |
08 | |
09 | animation[“shoot”].wrapMode=WrapMode.Once; |
10 | |
11 | //放置idle和walk进低一级别的layers(默认layer总是0) |
12 | |
13 | //Thiswilldotwothings这将作两件事情 |
14 | |
15 | //-当callingCrossFade时,由于shoot和idle/walk在不同的layers中 |
16 | |
17 | //它们将不会影响互相之间的重放. |
18 | |
19 | //-由于shoot在高一级的layer,当fadedin时shoot动画将替换 |
20 | |
21 | //idle/walk动画. |
22 | |
23 | animation[“shoot”].layer=1; |
24 | |
25 | //Stopanimationsthatarealreadyplaying停止已经播放的动画 |
26 | |
27 | //(万一user忘记的话,自动disable播放) |
28 | |
29 | animation.Stop(); |
30 | |
31 | } |
32 | |
33 | functionUpdate(){ |
34 | |
35 | //Basedonthekeythatispressed,基于按下的键 |
36 | |
37 | //playthewalkanimationortheidleanimation播放走,站动画 |
38 | |
39 | if(Mathf.Abs(Input.GetAxis(“Vertical”))>0.1) |
40 | |
41 | animation.CrossFade(“walk”); |
42 | |
43 | else |
44 | |
45 | animation.CrossFade(“idle”); |
46 | |
47 | //Shoot射击 |
48 | |
49 | if(Input.GetButtonDown(“Fire1”)) |
50 | |
51 | animation.CrossFade(“shoot”); |
52 | |
53 | } |
动画混合AnimationMixing
动画混合可以让你缩减你必须为游戏制作的动画片断数量,方法是制作只对身体某个部分起作用的动画。这意味着这些动画可以和其他动画合并起来一起使用。
如果你想给一个动画添加animationmixingtransformtoananimationbycallingAddMixingTransform()onthegivenAnimationState.
混合范例MixingExample
例如你可能有一个挥手(hand-waving)动画.你可能需要让一个空闲站立(idle)角色或者一个走动(walking)角色来挥手.如果没有动画混合你可能需要制作两个挥手hand-waving动画:一个给idle,一个给walking.可是,如果你将挥手(hand-waving)动画作为一个mixingtransform添加到shouldertransform,挥手动画将只控制肩膀.身体余下部位不受其影响,下半身会继续播放idle或者walk动画.因而你只需要一个挥手(hand-waving)动画。
01 | ///AddsamixingtransformusingaTransformvariable |
02 | |
03 | varshoulder:Transform; |
04 | |
05 | animation[“wave_hand”].AddMixingTransform(shoulder); |
06 | |
07 | Anotherexampleusingapath. |
08 | |
09 | functionStart(){ |
10 | |
11 | //Addsamixingtransformusingapathinstead |
12 | |
13 | varmixTransform:Transform=transform.Find(“root/upper_body/left_shoulder”); |
14 | |
15 | animation[“wave_h和”].AddMixingTransform(mixTransform); |
16 | |
17 | } |
附加动画和动画混合可以让你缩减为游戏制作的动画片断的数量,并且对面部动画(facialanimations)来说非常重要,我们来看看如果创建一个在跑和转身时身体可以自动倾斜的角色。
你已经制作好了一个walk和run循环,现在你还要制作一个走动左倾(walk-lean-left),走动右倾(walk-lean-right),跑左倾(run-lean-left),跑右倾(run-lean-right)动画.
这意味着你需要多做4个动画片断!制作这么多数量的动画会累死人的.而附加动画(Additiveanimations)和混合(Mixing)可以大大减少这些工作量!
附加动画范例AdditiveAnimationExample
附加动画允许你在顶层覆盖其他所有可能播放的动画的效果(allowyoutooverlaytheeffectsofanimationontopofanyothersthatmaybeplaying).当你制作一个附加动画时,Unity将计算动画片断里的第一帧(firstframe)和当前帧(currentframe)的差异.然后它将在所有其他播放的动画之上应用这个差异(Thenitwillapplythisdifferenceontopofall
otherplayinganimations).
现在你只需要制作一个左倾(lean-left)和右倾(lean-right)动画.Unity将为此倾斜动画新建一个层并置于walk,idle或run循环的层级之上.
下面是代码:
01 | privatevarleanLeft:AnimationState; |
02 | |
03 | privatevarleanRight:AnimationState; |
04 | |
05 | functionStart(){ |
06 | |
07 | leanLeft=animation[“leanLeft”]; |
08 | |
09 | leanRight=animation[“leanRight”]; |
10 | |
11 | //Puttheleaninganimationinaseparatelayer |
12 | |
13 | //SothatothercallstoCrossFadewon'taffectit. |
14 | |
15 | leanLeft.layer=10; |
16 | |
17 | leanRight.layer=10; |
18 | |
19 | //Settheleananimationtobeadditive混合模式为附加 |
20 | |
21 | leanLeft.blendMode=AnimationBlendMode.Additive; |
22 | |
23 | leanRight.blendMode=AnimationBlendMode.Additive; |
24 | |
25 | //SettheleananimationClampForever |
26 | |
27 | //WithClampForeveranimationswillnotstop |
28 | |
29 | //automaticallywhenreachingtheendoftheclip |
30 | |
31 | leanLeft.wrapMode=WrapMode.ClampForever; |
32 | |
33 | leanRight.wrapMode=WrapMode.ClampForever; |
34 | |
35 | //Enabletheanimation和fadeitincompletely |
36 | |
37 | //Wedon'tuseanimation.Playherebecausewemanuallyadjustthetime |
38 | |
39 | //intheUpdatefunction. |
40 | |
41 | //Insteadwejustenabletheanimation和setittofullweight |
42 | |
43 | leanRight.enabled=true; |
44 | |
45 | leanLeft.enabled=true; |
46 | |
47 | leanRight.weight=1.0; |
48 | |
49 | leanLeft.weight=1.0; |
50 | |
51 | //Fortestingjustplay“walk”animation和loopit |
52 | |
53 | animation[“walk”].wrapMode=WrapMode.Loop; |
54 | |
55 | animation.Play(“walk”); |
56 | |
57 | } |
58 | |
59 | //Everyframejustsetthenormalizedtime |
60 | |
61 | //basedonhowmuchleanwewanttoapply |
62 | |
63 | functionUpdate(){ |
64 | |
65 | varlean=Input.GetAxis(“Horizontal”); |
66 | |
67 | //normalizedTimeis0atthefirstframe和1atthelastframeintheclip |
68 | |
69 | leanLeft.normalizedTime=-lean; |
70 | |
71 | leanRight.normalizedTime=lean; |
72 | |
73 | } |
当使用附加动画时它会判断你同时也在播放一些其他的使用了附加动画的非附加动画,否则动画将添加到最后一帧结果的顶部,这通常不是你所需要的。
程序动画角色ProcedurallyAnimatingCharacters
有时你需要程序化的驱动你的角色骨骼.例如你可能需要你的角色的头注视3d空间的某个点.这个活最好让脚本来干.幸运的是,Unity做这个很容易.在Unity中所有骨骼来驱动蒙皮网格(skinnedmesh)的变换(Transforms).因而你可以给角色的骨骼写脚本,就和其他GameObject一样.
很重要的一点是动画系统updatestheTransforms是在Update()function调用之后,LateUpdate()function调用之前.因而如果你要调用LookAt()function你应该dothatinLateUpdate()tomakesurethatyouarereallyoverridingtheanimation.
布娃娃系统Ragdolls也是用同样的方法制作出来的.你可以简单的把刚性物体(Rigidbodies),角色关节(CharacterJoints)和胶囊碰撞体(CapsuleColliders)连接给不同的骨骼.这样物理系统就可以作用于蒙皮角色(skinnedcharacter).(什么是布娃娃系统,当你在射击类游戏中打死对手时可以注意到当角色快接近地面时,他的四肢开始瘫软在地面上,这个不是动画师调出来的,而是布娃娃系统自动计算出来的。)
动画重放和取样AnimationPlayback和Sampling
这一部分将说明引擎如何在动画重放时取样.
动画片断制作时总是有一个特定的速率.举例来说,你可能在Max或Mayaat创建了一个帧速为60frames每秒(fps)的动画.当导入Unity后,输入模块将读取帧速,所以导入的动画帧速还是60fps.
可是,游戏运行时的速率是不断变化的.有的电脑帧速快有的电脑帧速慢,即使是同一台电脑前一秒和后一秒因为视角的不同帧速也不一样.基本上当游戏开始运行时我们无法确定一个精确的帧速.这意味着即使我们的动画片断制作时是60fps,它重放时也许用的是另外一个速率,例如56.72fps,或83.14fps.它可以变成任何一个速率.
Unity对这些变化的速率取样,不在于其制作时的速率.幸运的是,3d电脑图形动画不是由分散的动画组成,确切地说是由连续的曲线构成的.这些曲线可以让我们在任何时间点取样;而不是适配某一个原始帧的时间点.I这也意味着如果游戏运行速率高于原始制作速率,动作事实上看起来会更平滑流畅.
对绝大多数应用场合,Unity对变化帧速的采样我们无需对其进行干预.可是,如果你的某个游戏逻辑所依赖的动画变化或道具(transformsorproperties)结构十分特殊,那你必须知道这一点.举例说,如果你有一个动画是把一个物体30帧内从0旋转到180度,你想从代码中得知什么时候动画完成一半,你不能写一段条件语言来检查现在旋转值是不是90度.因为Unity依照游戏的变化速率来对动画采样,它可能在旋转快到90度时进行采样,或者是刚好过90度的时候采样.如果你需要通报动画中一个特殊点到达时,
你可以使用AnimationEvent来替代.
同样需要注意的是变化的帧速采样结果,一个使用WrapMode.Once模式重放的动画的采样不一定是精确的最后一帧(lastframe).在游戏中很有可能是刚好结束前的某一帧,在下一帧时间可能超过动画的长度,soitisdisabled和notsampledfurther.如果你需要动画的最后一帧采样精确,你可以使用WrapMode.ClampForever.如果是那样的话动画将不停的对最后一帧进行采样直到你自己停止动画.
相关文章推荐
- unity手游开发--如何得到当前物体播放的动画
- Unity3D 项目用 git 做版本控制
- Unity5 如何做资源管理和增量更新
- InvokeRepeating("PlaySound",2.0f,0.5f) 2秒后每隔0.5秒调用
- [Unity3D]自己动手重制坦克舰队ArmadaTank
- Unity3d读取CSV中的文本到Rich Text中换行符不识别的问题
- 如何将Unity工程打包成apk
- Unity 5.0 IL2CPP
- Unity3D摄像机跟随人物
- Unity3d NGUI的drawcall,UISprite与UITexture
- [Unity3D]降低向Shader中传值的开销
- 【Unity3d学习笔记】刚体碰撞和关节
- 【Unity3d学习笔记】基本游戏地形
- Unity3d + NGUI 的多分辨率适配
- 【Unity3d学习笔记】基础引擎操作
- 使用Unity遇到的若干个坑
- unity内部float类型转换string类型只保留整数部分
- 使用Unity3D编写ARPG游戏——角色属性的定义与实现(二)
- Unity3d_协程和Invoke
- 【unity3D】鼠标控制camera的移动、放大(俯视浏览效果、LOL摄像机移动效果)