第三十一章 Unity骨骼动画

关于骨骼动画的原理,我们这里不再详细介绍,有不清楚的可以回去看DirectX课程和3dsMAX课程。接下来,我们来讲解一下Unity的骨骼动画系统。Unity 的动画系统基于动画剪辑(Animation Clip)的概念,它的本质就是一小段动画,代表了一个游戏角色的动作,例如:走路,跑步,攻击,死亡等等。我们可以在3dsMax或者Maya中制作一个游戏角色的所有完整动画,然后导出FBX的时候,连同动画一起导出。这样,我们在导入Unity的时候,就可以根据帧数来分割成不同的动画剪辑(Animation Clip)。当然,制作动画的过程是由“动画师”这个职业来完成的,导出给研发人员的时候,他们会清楚的告诉你那些帧数代表那些动作,方便我们在Unity中进行分割。分割完毕后就会形成一个个的动画剪辑,也就是对应的一个个“动作”,例如:待机动作,走路动作,跑步动作,攻击动作,受伤动作,死亡动作等等。对于简单的动画系统来讲,就是根据玩家的输入来播放对应的动画剪辑(动作)。例如,我们按下前进按键(W键)的时候,我们就使用Translate方法在transform.forward方向上移动角色,并且播放走路动画剪辑,这样就完成角色走路的代码逻辑啦。这样看来,动画系统只需要一个Play播放方法,然后传递一个动画剪辑ID即可完成,没有必要设计复杂的动画系统。旧版的Unity动画系统的确是这样做的,这样的动画系统虽然简单,但是对于我们各个动画剪辑之间的切换逻辑,就需要我们使用大量的代码来完成。因为当我们的动画剪辑越来越多,每个动画剪辑之间都可能进行切换,例如从走路动作切换到攻击动作,或者攻击动作切换到死亡动作等等。久而久之,这些切换逻辑就会成为臃肿杂乱的累赘。为了避免这种情况的发生,我们需要一个清晰地“结构设计”来替换这个缺陷,这就是Unity新的 Mecanim 动画系统。

首先,我们创建一个新的“MecanimDemo”工程来展示Unity的动画系统。然后,我们需要一个带有动画的模型,这次我们选择使用“Elf”这个模型。这个模型是我从网上获取,并为其添加了3ds max的Biped骨骼,然后蒙皮,最后制作了4个动画剪辑。我们要做的就是将“Elf.zip”解压到“Assets”目录下即可,最后我们在Project工程面板中可以看到。

这个模型除了FBX文件之外,还有四张贴图,分别是头部,身体,手臂和腿部。我们发现FBX文件有一个三角按钮,我们可以点击它,

我们可以看到,它有很多内容,包括骨骼(Bip001),材质,网格,以及名称为“Take 001”的动画数据。这个动画数据由4个动作组成,他们分别是idle待机动作(0-60帧),walk走路动作(61-97帧),run跑步动作(98-129帧)以及dead死亡动作(130-190帧)。我们可以点击FBX文件,在对应的Inspector检视面板中的Animation选项切割动作剪辑。

在上面的截图中,注意到“Model”,“Rig”,“Animation”和“Materials”四个Tab选项按钮,他们分别代表了“网格”,“骨骼”,“动画”以及“材质”四部分内容。我们的动画数据就在“Animation”选项下面,因此我们需要点击“Animation”这个选项按钮。在上面的截图中,最下面有一个“Take 001”的隐藏窗口,我们将鼠标移动到上面,鼠标就会变成上下两个箭头的样子,表示我们可以上下拖拽。于是,我们向上拖拽出隐藏的窗口。

如果我们点击三角形的播放按钮,就能看到所有动作播放效果了,如下所示

接下来,我们就来分割四个动作剪辑,我们在Inspector检视面板中找到如下内容:

这个其实就是动画剪辑列表,这里显示只有一个动画剪辑,名称为“Take 001”。下面的加号和减号代表可以增加和删除选择的动画剪辑。再下面就是每一个动画剪辑的具体内容设置,目前只有一个“Take 001”,其中Start表示该动画剪辑开始的帧数,End为结束的帧数。因为目前只有一个“Take 001”的剪辑,它从-1帧到199帧。首先,我们先分割第0帧到60帧的待机动画剪辑,我们直接在“Take 001”的基础上修改即可。

我们修改了动画剪辑的名称,开始帧数和结束帧数,修改完毕后,动画剪辑列表也改变了。接下来,我们点击“+”号来增加一个新的动画剪辑。

新增加的动画剪辑的名称和帧数都是默认的,我们需要进行修改。

我们同样修改动画剪辑的名称,开始和结束帧数。注意我们勾选了“Loop Time”选项,它代表循环播放动画片段的意思,因为走路动画就应该循环播放,这个大家应该很容易理解。接下来,我们按照上述方式来增加剩余的跑步和死亡动画,如下所示:

其实前三个动画剪辑都应该是“Loop Time”,之后死亡动画是一次性播放的。关于“Loop Time”,有一个非常重要的特性,就是开始帧数的动作姿势与结束帧数的动作姿势必须一致,否则循环播放就无法形成连贯性,也就是前后动画不能无缝连接了。动画剪辑分割完毕后,记得保存这些修改,我们点击“Apply”按钮即可(这个按钮可能需要滚动后才能看到哦)。我们可以在最下面的动画播放窗口中点击播放箭头来查看每一个剪辑的播放效果。我们回到Project工程面板中,再次点开模型文件的三角符号时候,就能在展开的内容中看到新分割的动画剪辑了。

以前是只有一个“Take 001”的动画剪辑,现在被我们分割成了四个不同的动画剪辑。接下来,我们就开始使用代码来播放这四个动画剪辑。我们将FBX文件直接拖拽到Scene视图中,然后调整好角度,使得我们方便的观察到模型,如下所示:

此时,我们在展开Hierarchy层次面板,查看游戏对象的父子结构,如下所示

最上面的“Elf”是顶级父对象,它只有一个Transform组件,它的下面Bip001是骨骼结构,而子级Elf是模型组,再下面的body,hair,hand,head,leg才是真正的模型文件。普通模型(例如一个Cube立方体),它没有动画,它只有Mesh Filter组件和MeshReaderer组件,前者包含模型顶点数据,后者用于渲染该模型。而包含动画的模型(例如body)则使用Skinned Mesh Renderer(蒙皮网格渲染)组件,该组件即包含顶点数据,也包含蒙皮数据等等。这跟我们使用DirectX解析两种不同的模型基本上是一样的。如下所示。

在旧版的动画系统中,播放动画是通过“Animation”组件来实现的。但是这要求我们的FBX模型也必须使用旧版动画系统,我们选中FBX文件,然后在Inspector检视面板中选择“Rig”项,然后在Animation Type下拉中选择“Legacy”旧版动画系统,最后点击“Apply”应用。

接下来,我们需要给当前的顶级游戏对象Elf添加一个“Animation”组件(已自动添加了),如果没有自动添加的话,大家可以自己手动添加一下 Animation 组件(不要搞错了),如下所示:

在上面的“Animation”组件的面板中,我们首先看到的是“Animation”和“Animations”两个重要的参数,从英文单词可以看出一个是单数形式,一个是复数形式,而且“Animations”的下面就是一个List,我们可以通过“+”/“-”来添加和删除动画片段。既然是这样,我们就点击“+”来添加我们上面分割的“adle”,“walk”,“run”和“dead”四个动画片段吧。Unity好像已经给我们添加好了。如果没有添加好的话,我们可以手动添加。我们点击“Element 0”最后面的圆点按钮,也就是列表中第一个元素,会出现一个弹框。

这个弹框会自动找到我们工程中的动画剪辑文件,我们双击选择“idle”这个动画剪辑。这样,第一个动画剪辑就被添加进来了。我们按照同样的方式,将剩余的也添加进来。添加完之后,我们还需要给“Animation”参数设置一个默认的动画片段。很明显,我们的默认动画肯定是“idle”动画。大家注意到有一个“Play Automatically”的参数,它的意思就是自动播放默认动画的意思。接下来,我们需要给当前游戏对象Elf添加一个C#脚本AnimationScript.cs,在该脚本中我们将通过“Animation”组件来播放动画片段,如下所示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AnimationScript : MonoBehaviour
{
    // 旧动画播放组件
    private Animation animation;

    // Start is called before the first frame update
    void Start()
    {
        // 获取Animation组件
        animation = GetComponent<Animation>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            animation.Play("idle");
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
            animation.Play("walk");
        }
        if (Input.GetKeyDown(KeyCode.D))
        {
            animation.Play("run");
        }
        if (Input.GetKeyDown(KeyCode.F))
        {
            animation.Play("dead");
        }
    }
}

上面的代码非常简单,我们首先获取“Animation”组件,然后按下ASDF键的时候,执行其play方法来播放idle,walk,run,dead动画片段。我们将脚本挂载到游戏对象Elf上,并运行工程试试。

其实,当我们运行工程后,会自动播放idle动画,这是上面“Play Automatically”参数决定的。当我们按下S键的时候,会播放名称为walk的动画,但是只执行了一次,并没有循环播放走路动画。我们之前不是设置了“Loop Time”了嘛,它就应该是循环播放的啊。这个原因在于,我们修改Animation Type为“Legacy”旧版动画系统的原因。我们可以回到FBX文件的Inspector检视面板的Animation动画剪辑那里,重新检查之前剪辑的四个动画片段。

这里的参数发生了变化,没有“Loop Time”勾选项了,取而代之的是Wrap Mode下拉框,我们选择其中的“Loop”,然后点击“Apply”应用即可。我们也可以将其他动画片段都修改为“Loop”模式,最后点击“Apply”保存FBX文件即可。接下来,我们再运行工程。这次我们的idel动画可以连续播放了,并且我们按下S键的时候,走路动画也可以连续播放了。两次走路动画之间的衔接不好的原因在于,走路动画的开始姿势和结束姿势不一样。这是循环动画能够连贯播放的前提,这个需要我们去修改FBX文件才能解决。最后,我们再介绍另一个方法,如下:

            animation.CrossFade("run", 1f);

这个CrossFade方法使用比较频繁,它的作用在于会使用“淡进淡出”的方式来过渡两个动画。我们举一个例子,如果当前游戏角色正在地上坐着,然后我们需要播放一个攻击动画。如果我们使用play方法直接播放攻击动作的话,我们就会发现这个游戏角色会突然变成站立的姿势(攻击动作的开始姿势),并开始播放攻击动画。这个很明显,不符合现实世界物理规律,应该是有一个“起来”的过程,然后在开始播放攻击动画。那么,这个“起来”的过程就是我们所说的“淡进淡出”。它的实现原理应该就是骨骼动画的“线性插值”。关于CrossFade方法的实际效果,大家可以自己试试,我们不再展示gif动画了。本章节我们介绍了Unity的旧动画系统,主要目的还是回顾一下骨骼动画。

本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/17367.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode - 239 滑动窗口最大值

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 239. 滑动窗口最大值 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k…

springboot+vue前后端分离项目打包成jar包及运行

将 Spring Boot 和 Vue.js 项目打包成 jar 包需要按照以下步骤操作&#xff1a; 在项目的根目录中&#xff0c;使用命令行进入 Vue.js 项目的根目录&#xff0c;然后运行以下命令&#xff1a; npm run build这个命令将会构建 Vue.js 项目&#xff0c;并在项目的 dist 目录中生…

鸿蒙Hi3861学习八-Huawei LiteOS(事件标记)

一、简介 事件是一种实现任务间通信的机制&#xff0c;可用于实现任务间的同步。但事件通信只能是事件类型的通信&#xff0c;无数据传输。一个任务可以等待多个事件的发生&#xff1a;可以是任意一个事件发生时唤醒任务进行事件处理&#xff1b;也可以是几个事件都发生后才唤醒…

华为网络设备+WinRadius 实现用户统一管理设备

一、直接贴配置 ###配置VTY用户界面所支持的协议、验证方式 user-interface vty 0 4 protocol inbound telnet authentication-mode aaa quit ###配置RADIUS认证 ###&#xff08;1&#xff09;配置RADIUS服务器模板&#xff0c;指定服务器的IP地址与端口号、共享密钥 radius-s…

Unity - Render Doc - 解决 Waiting For Debugger 导致连接不了 APP 的问题

环境 Unity : 2020.3.37f1 Pipeline : BRP RDC : 1.26 问题 平常有一些公司内的游戏发布在移动端运行会有各种异常&#xff0c;但是 unity editor (android opengl es / dx) 下正常 如果没有真机抓帧分析&#xff0c;是搞不定的 然后 RenderDoc 在抓发布出来的调试包也抓不…

漫画 | Linux之父:财务自由以后,我失眠了!

前言&#xff1a;今年是Linux诞生的30周年&#xff01; 1991年的8月&#xff0c; Linus在新闻组中公布了他正在开发的一个免费的操作系统&#xff0c;这也是以后风靡世界的Linux操作系统的雏形。 今天翻到这篇漫画&#xff0c;看到Linux的诞生过程&#xff0c;很是感慨&#x…

SuperMap GIS基础产品云GIS FAQ集锦(2)

SuperMap GIS基础产品云GIS FAQ集锦&#xff08;2&#xff09; 【iManager】云套件ispeco-dashboard-api的日志等级只有到info&#xff0c;如何设置才能查看到debug级别的日志&#xff1f; 【解决方案】可以在ispeco-dashboard-api的deployment中添加以下环境变量&#xff0c;…

vue框架快速入门

vue 1、第一个Vue程序1.1、什么是Vue程序1.2、为什么要使用MVVM1.3、Vue1.4、第一个vue程序 2、基础语法2.1、v-bind2.2、v-if&#xff0c; v-else2.3、v-for2.4、v-on 3、Vue表单双绑、组件3.1、什么是双向数据绑定3.2、在表单中使用双向数据绑定3.3、什么是组件 4、Axios异步…

PyQt5 基础篇(一)-- 安装与环境配置

1 PyQt5 图形界面开发工具 Qt 库是跨平台的 C 库的集合&#xff0c;是最强大的 GUI 库之一&#xff0c;可以实现高级 API 来访问桌面和移动系统的各种服务。PyQt5 是一套 Python 绑定 Digia QT5 应用的框架。PyQt5 实现了一个 Python模块集&#xff0c;有 620 个类&#xff0c;…

从0学会Spring框架

文章目录 1. 对Spring的理解2. Spring IoC3. DI4. 如何创建一个Spring项目4.1 创建一个Maven项目4.2 添加Spring框架支持4.3 添加启动类 5. 存储Bean对象5.1 添加配置文件5.2 创建Bean对象5.3 注册Bean 6. 获取并使用Bean对象7. 更简单存储Bean对象的方式7.1 前置工作7.2 添加存…

基于javaweb的学生就业管理系统

一、简介 学生基业管理系统有三个角色&#xff1a;管理员、企业、学生 对学生信息管理、企业信息管理、求职信息管理 后端架构&#xff1a;spring springmvc mybatis 前端架构&#xff1a;jsp layui 系统环境&#xff1a;jdk1.8 | maven | mysql 二、主要功能 1. 登录…

一个集团企业,如何从0到1构建信息化系统?

当今时代&#xff0c;信息技术已经成为企业发展不可或缺的一部分&#xff0c;特别是对于一个大型集团公司来说&#xff0c;如何构建一个高效的信息化系统对于其业务发展至关重要。 我们想要构建一个优质高效的信息化系统&#xff0c;首先需要了解现在大的趋势是怎样的。 目前…

看我如何通过帮助服务台轻松黑掉数百家公司

导语&#xff1a;几个月前&#xff0c;我发现黑客可以利用一个漏洞访问目标公司的内部通信。 这个漏洞只需要点击几下&#xff0c;就可以访问企业内部网络、 Twitter等社交媒体账户&#xff0c;以及最常见的Yammer和Slack团队。 更新: The Next Web 写了一篇我发现的这个漏洞的…

【Java笔试强训 28】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;猴子分桃…

二分法相关使用

文章目录 1. 在一个有序数组中,找某个数是否存在2. 在一个有序数组中,找大于等于某个数最左侧的位置3. 在一个有序数组中, 找小于等于某个数最右侧的位置4. 局部最大值问题 1. 在一个有序数组中,找某个数是否存在 在线OJ&#xff1a;704. 二分查找 有序数组下的二分思路如下:…

几种常见时间复杂度实例分析

多项式量级 常量阶 O(1) 对数阶 O(logn) 线性阶 O(n) 线性对数阶 O(nlogn) 平方阶O(n2 ),立方阶O(n3 )...k次方阶O(nk) 非多项式量级&#xff08;NP&#xff08;Non-Deterministic Polynomial&#xff0c;非确定多项式&#xff09;问题&#xff09; 指数阶O(2n) 阶乘阶…

Android WebRtc+SRS/ZLM视频通话(1):虚拟机安装Ubuntu

Android WebRtcSRS/ZLM视频通话&#xff08;1&#xff09;&#xff1a;虚拟机安装Ubuntu 来自奔三人员的焦虑日志 秉着没事找事的原则&#xff0c;这里直接从服务器安装开始说起&#xff0c;也当记录自己这一路以来的愚昧之举&#xff0c;由于没有物理服务器&#xff0c;这里以…

MySQL 精选 35 道面试题大厂稳了(含答案)

MySQL 精选 35 道面试题 1.说一下 MySQL 执行一条查询语句的内部执行过程&#xff1f;2.MySQL 查询缓存有什么优缺点&#xff1f;3.MySQL 的常用引擎都有哪些&#xff1f;4.常用的存储引擎 InnoDB 和 MyISAM 有什么区别&#xff1f;5.什么叫回表查询&#xff1f;6.如果把一个 I…

95后阿里P7晒出工资单:狠补了这个,真香···

最近一哥们跟我聊天装逼&#xff0c;说他最近从阿里跳槽了&#xff0c;我问他跳出来拿了多少&#xff1f;哥们表示很得意&#xff0c;说跳槽到新公司一个月后发了工资&#xff0c;月入5万多&#xff0c;表示很满足&#xff01;这样的高薪资着实让人羡慕&#xff0c;我猜这是税后…

TCP的粘包和拆包

UDP有数据边界&#xff0c;TCP是没有数据边界&#xff0c;是流协议。如何拆包&#xff0c;就要靠应用层来处理。 四层网络模型&#xff0c;消息在进入每一层时都会多加一个报头。mac头部记录的是硬件的唯一地址&#xff0c;IP头记录的是从哪来和到哪去&#xff0c;传输层头记录…