查看: 2007|回复: 2
打印 上一主题 下一主题

[经验分享] 在Unity3D的Legacy动画系统中应用Root Motion

[复制链接]

100

主题

3

听众

7683

积分

高级设计师

Rank: 6Rank: 6

纳金币
2378
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2015-2-9 21:11:30 |只看该作者 |倒序浏览
最近仔细比较了unity3D目前版本中的两套动画系统:Legacy和Mecanim。Mecanim系统功能较之Legacy要强大很多,但是使用AnimatorController着实不方便(尽管使用AnimatorOverrideController可以避免重复编辑状态机),是因为游戏逻辑层面往往要用一个状态机或者类似的机制来控制角色的状态,而角色层面的状态逻辑和动画层面是无法一一对应的,两套复杂的状态机要配合起来。。。想想就觉得蛋疼啊!难怪很多朋友现在还在使用Legacy动画系统。Legacy动画系统其实功能也很全面了,包括Layer、过渡混合、上下身混合之类的功能完全能够胜任,而且控制起来就直接的多了。唯独Root Motion这个我很需要特性没有支持,本文就探讨一下如何在Legacy动画系统之上附加Root Motion功能,其实很简单大笑。

何谓Root Motion

在不使用Root Motion的情况下,类似走、跑这样的位移控制是这样的:
请美术在导出动画时把位移去掉;
在程序代码里控制角色移动的速度,在播放动画的同时,计算其位移。
这种做法其实挺不科学的,程序控制的角色,只能当做一个质点来处理,并且大多数时候都是匀速运动,而动画中的角色的移动往往很难跟这个匹配。所以需要比较良好的计算和比较好的美术技巧才能避免角色“滑步”的现象。在“跑”这种快速移动这,滑步还比较好处理,如果是慢速移动。。。。再厉害的美术也爱莫能助了。这种情况下,最好还是使用Root Motion:
美术在导出动画的时候是附带位移的;
程序把动画的每一帧的位移是从动画中读取出来,再应用到角色上的,这样就能达到动画和位移的完美匹配了。

在Legacy中添加Root Motion功能

了解了Root Motion的概念之后,在unity3d引擎中我们很简单就可以实现此功能了。Unity3D有一个统一的对象层次结构设计,这点非常赞,我们可以很简单找到角色的根骨骼,然后把其中的Transform变换读取出来,请见以下示例代码://-- 计算当前帧的Root Motion
                Vector3 rootPos = m_rootBone.localPosition;
                m_rootMotion = rootPos - m_lastRootPos;
                m_lastRootPos = rootPos;
                rootPos.x = 0;
                rootPos.z = 0;
                m_rootMotion.y = 0;
                m_rootBone.localPosition = rootPos;



请注意,我们在后续的代码中要把m_rootMotion附加的角色对象上,所以m_rootBone的postion被reset了。
在读取了此帧的Root Motion,在可以把它应用到当前对象之上了:
//-- Apply Root Motion
        Vector3 nextPos = this.transform.position + m_rootMotion;
        this.transform.position = nextPos;



另外,一个细节需要处理一下,在动画循环的那一帧,需要特殊处理一下。好的,看一下完整的源代码吧:using UnityEngine;
using System.Collections;

public class ApplyRootMotion : MonoBehaviour
{
        public Transform m_flagObject;        // 用来测试位置的一个对象

        //-- Root Motion 控制变量
        Transform m_rootBone;
    Vector3 m_lastRootPos;
    Vector3 m_rootMotion;
    int m_lastAnimTime;

        void Start ()
        {
                //-- 从SkinnedMeshRenderer中读取Root Bone
                SkinnedMeshRenderer skinMesh = this.gameObject.GetComponentInChildren<SkinnedMeshRenderer>();
        m_rootBone = skinMesh.rootBone;

        //-- 变量初始化
        m_rootMotion = Vector3.zero;
        m_lastRootPos = m_rootBone.localPosition;
        m_lastAnimTime = 0;
        }
        
        void Update ()
        {
                //-- Apply Root Motion
                Vector3 nextPos = this.transform.position + m_rootMotion;
        this.transform.position = nextPos;

        //-- 测试代码:更新测试物体的位置
        Vector3 flagPos = m_flagObject.position;
        flagPos.x = nextPos.x;
        flagPos.z = nextPos.z;
        m_flagObject.position = flagPos;

        //-- 测试代码:更新摄像机
        Camera.main.transform.LookAt(this.transform);
        }

        void LateUpdate()
    {
                AnimationState animState = this.animation["walking"];

                if ((int)animState.normalizedTime > m_lastAnimTime)
                {
                //-- 动画循环处理
                m_lastRootPos = m_rootBone.localPosition;
                m_rootMotion = Vector3.zero;
        }
        else
        {
                //-- 计算当前帧的Root Motion
                Vector3 rootPos = m_rootBone.localPosition;
                m_rootMotion = rootPos - m_lastRootPos;
                m_lastRootPos = rootPos;
                rootPos.x = 0;
                rootPos.z = 0;
                m_rootMotion.y = 0;
                m_rootBone.localPosition = rootPos;
        }
        m_lastAnimTime = (int)animState.normalizedTime;
    }
}


请移步百度网盘:http://pan.baidu.com/s/1o6kJsIe 密码:osoc


分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

115

主题

3

听众

5676

积分

高级设计师

Rank: 6Rank: 6

纳金币
7268
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2015-2-9 21:17:25 |只看该作者
Thanks for sharing this one !
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-27 14:15 , Processed in 0.102132 second(s), 27 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部