Unity的Write Defaults->从一个例子谈起


Write Defaults是什么?


 在Unity的Animator中点击任何一个手动创建的State,我们就会在Inspector面板中看到下图的WriteDefaults选项

先说说Write Defaults的作用(文档中语焉不详,下面解释掺杂一些本人的理解,不一定完全正确):
任何一款引擎内部处理动画,都是处理的一个个具体的动画曲线。对于Unity来说,每一个动画曲线只改变一个浮点数,比如位置的修改,其实是包含了三条动画曲线,这里就不展开了,日后有机会写一些相关的Blog。
每个动画文件都描述了他要修改哪些物体的哪些属性.Unity中的Animator会统计整个状态机中一共修改了哪些属性。如果各个动画之间修改的属性不一致的时,比如动画A修改了属性X,Y,Z.动画B修改了属性X,Y,W.当状态机从动画A过渡到动画B的时候,对于属性Z的处理就是Write Defaults来决定的。此时若其勾选(默认勾选)则播放动画B的时候,属性Z会被设置为该属性在Animator组件运行前的值(如绑定姿势)。若不勾选则属性Z会继承动画A播放后修改的值。


例子描述


 先描述我遇到的问题:项目中有一个骷髅弓箭手的小怪,正常情况下从他的出生到开始攻击的动画流程应该如下图:

不过偶尔会出现小怪弓的位置出错的问题,出错的程度也并不一致。


问题分析


 现在就来分下一下原因吧,这个小怪的简化版状态机如下,其中只有AnyState->Attack01的条件是一个Trigger,其他状态间切换都是正常过渡:

1.在我们的项目中所有状态默认勾选的WriteDefault都被手动的去掉了。这是因为有时候需要从前一个状态继承一些当前状态没有的属性值。
2.通过检查max文件又发现美术在制作的时候除了Birth动作以外,小骷髅的其它动作针对弓箭挂点的骨骼都没有相应的动画曲线。这就意味着,这些动作的弓箭挂点的位移和旋转是依赖于Birth状态的。
3.可见如果从Birth状态到后面状态过渡出现问题的话,就会导致弓箭挂点永远错下去,因为Birth只会播放一次,并且后续状态都不包含对弓箭挂点的属性修改。

针对第三点我再多说几点:
我发现Stand动作也没有弓箭挂点的相关动画曲线,但是Birth->Stand的过渡是没有问题的。为什么呢?原因就是下图:

可以看到Birth->Stand的动画过渡区间配置的比较合理,保证了两个动画在插值过程覆盖了Birth动画的全部长度。在Max中发现,大概Birth动作到达上图白线位置的时候,弓箭挂点就已经到达了正确的旋转和位移,之后不再有变化。所以理论上只要动画过渡区间覆盖到白线就能保证不出错。

既然弓箭丢失不是Birth->Stand过渡引起的,那就应该是从AnyState到Attack01这个状态过渡的问题了,因为AnyState的特殊性,所以没有勾选HasExitTime,而此时的过渡情况就很微妙了,在下图中所看到的过渡区间并不是真正的过渡时间,由于官方没有相关的说明,自己做了些测试,假设下图中过渡区间占了Birth动作条的15%,而在触发AnyState->Attack01切换条件的时候,Birth已经播放到了10%.那么实际上接下来Birth动作参与动作融合的部分是其动作条的10%到25%的阶段,也就是实际的融合取决于前置状态的播放进度。

因为Attack01状态的WriteDefault是没有勾选的,那就意味着它对于弓箭挂点的位置和旋转完全依赖于前置动作在融合过程中最后一帧的值。接下来就能合理的解释,为什么有的时候弓箭不会脱手,而有的时候脱手,脱手的程度又不一致的问题了。正是因为AnyState->Attack01的触发条件Attack01的触发时间并不完全一致导致的。如果碰巧触发的时机合适,其融合区间包含了弓箭挂点到达正确位置和朝向的部分,那么看上去就是对的了,

以上的这些分析都是基于一个前提,就是Birth动作没有播放到合适的时机就被切换了。你也许会奇怪为什么不保证Birth播放完了再进行状态切换呢。这就得问策划了。在我们的游戏里,小怪有一个出生的范围,到达了出生范围就会生成小怪,状态机自动播放出生动作;还有一个攻击范围,如果进入了攻击范围,就会播放攻击动作。很显然如果角色的移动速度很快,或者生成范围和攻击范围相差太小,就会导致小怪刚一播放出生动作还没播完,Attack01的触发器就会被激活。也就可能出现弓箭脱手的问题了。

另外,这个问题只出现在远程兵身上,近战兵从来没有发现过武器脱手的。大家可以想想为什么。


解决方案


既然为分析出来了,解决的办法有很多,但是如果要治本,还是要从动作资源本身上解决这个问题。勾选WriteDefault是可以解决这个问题的,但又会导入新的问题,这个不行,我们在文章开始解释WriteDefault的那个例子中,我们只要让动作B也包含Z属性的曲线,这样WriteDefault这个选项就失去了意义,不过这样会让Attack01动作引入新的动作曲线。但由于在这个本例中,我们并不需要在Attack01动作过程中对弓箭挂点有什么修改,所以只要让他有一个绑定姿势的常量值就好了。Unity也会对常量曲线进行优化,所以问题并不大。

啰嗦了这么多,不知道有没有把这个问题讲清楚。Unity的Animator这块内容,用起来上手很快,但它实际涉及的内容量还是很大,Unity尝试对个各个概念去包装,让大家能容易理解,但就我的经验来看,他们做的还不够,无论是文档,还是使用界面都还有待优化。不管是国内国外,相关的资料都很少。也不知道国内有没有同行遇到过这个问题,希望大家多多研究,多多分享,功能营造一个好的氛围。

尊重他人智慧成果,若要转载,请注明作者esfog,原文地址http://www.cnblogs.com/Esfog/p/Unity_WriteDefaults.html 

猜你喜欢

转载自www.cnblogs.com/Esfog/p/Unity_WriteDefaults.html
今日推荐