第三十四章 Unity人形动画(上)
在我们DirectX课程中,我们讲过一个模型最少拥有网格和材质,可以没有动画。游戏场景中的静态物体就可以是这样的模型,例如花草树木,建筑物等等,他们通过MeshRenderer就可以渲染。对于一个带有动画的FBX文件,里面不仅仅包含了网格和材质,还包括了“骨架”和动画数据,这里的动画数据其实就是骨架中每块骨骼的移动和旋转变换数据。这里大家一定要分清骨架和骨骼两个概念哦。这样的模型需要使用SkinMeshRenderer才可以渲染。我们知道,骨骼动画就是骨骼变换控制网格顶点变换形成的,两者是通过“蒙皮”产生的关联关系,“蒙皮”的过程就是骨骼对顶点影响的权重设置。这里面涉及到了两种数据,一种是网格和材质,另一种就是骨骼动画。前者是差异化的,每个模型肯定都是不一样的;而后者有可能共享通用的,每个模型可能会有相同的动画。例如,两个人物模型,他们都应该有待机,走路,跑步等等通用的动画。那么,这些动画数据能不能独立成单独的文件,被其他模型使用呢?如果可以使用的话,我们就不需要为每一个模型制作动画了,节省一些不必要的时间了。答案,肯定是可以的。从数据角度出发,两个不同的模型,只要他们的“骨骼结构”(骨架)是一样的,那么基于该骨架的动画数据,就可以重用。这里的一样指的是骨骼的数量以及父子关系大致保持一致,名称不一样可以通过“映射”来统一。在3ds max中,就提供了一个完整的人形骨架,称之为“Biped”,如下所示:
也就是说,如果大家在给人物模型添加骨架的时候,都使用“Biped”的话,那么我们所有的基于“Biped”的动画就可以重用了。事实上,3ds max也是这样设计的,我们可以从网上下载到很多的基于“Biped”的动画数据。在Unity中,同样也拥有一套人形骨架,如下:
Unity的人形骨架与3ds max的人形骨骼大致相同。但是,大部分情况下,我们还需要将两者的骨骼进行一个“映射”,也就是“mapping”。映射的目的就是为了让Unity能够知道模型上面的那些骨骼对应Unity自己的头部,身体,胳膊以及腿脚信息等等。这个应该很容易理解。
Mecanim Example Scenes是由Unity发布的一款免费资源,旨在指导开发者如何使用Unity的Mecanim及角色动画系统,项目中包含11个示例场景,分别演示了动画状态机、混合树、集群模拟、多层次IK、目标匹配、处理武器、跟随、预测及导航网格集成等。
我们在Assets资源面板中导入上面的资源包。如下所示:
这个资源包并没有统一放置到一个独立的文件夹中,比较乱。我们发现在Assets根目录下有很多的场景文件,我们随便打开一个“Animator Controller.unity”查看一下。
当我们Play运行之后,就可以通过WASD键来控制里面的人物模型移动了,同时会有移动动画。当然,这个不是我们研究的内容。这个人物模型存放在 “Assets\Characters\U_Character”目录下,如下所示
在这个目录下,我们可以看到材质,贴图以及模型 “U_Character_REF.fbx”文件,查看它的Inspector检视视图。
我们注意到它的Animation Type一项为 Humanoid类型,也就是人形动画。关于这一项,我们之前已经介绍过Legacy旧版动画 和Generic新版动画,而Humanoid就是新版人形动画。我们继续点击“Animcation”选项面板,查看其下动画剪辑内容。
我们发现,这个模型文件并没有动画剪辑数据。我们重新创建一个新的“SampleScene3.unity”场景,然后将这个模型文件拖拽到Scene视图中,如下所示
我们在“Hierarchy”层次面板中查看该文件中有什么数据信息吧。
其中顶级“U_Character_REF”是我们整个游戏对象,它的下面有U,U_Char,U_Char_Eye_L,U_Char_Eye_R四个子对象,后面三个分别是人物主模型,人物左眼模型和人物右眼模型。那么第一个U对象是什么呢?U是一个父对象,它的下面有一个“joint_Char”的对象,这个对象就是“人形骨架”的根骨骼。我们上面已经说明过,动画数据是可以共享的,模型想要从外部获取动画的话,它本身必须拥有“人形骨架”,并且是被“蒙皮”处理过的。应该蒙皮处理过的模型需要“Skinned Mesh Renderer”组件才能渲染出来。我们点击U_Char查看Inspector检视视图,就能看到这个渲染组件,如下
在上面的“Root Bone”一项中,就能看到根骨骼就是“joint_Char”了。我们上面也提到了,这个模型是没有动画剪辑的(但是有骨骼信息),那么动画信息在哪里呢?
接下来,我们去“Assets\Animations”目录下查看一下,
我们会发现,有很多的动画片段,例如Idles,Run,Jump等等。这些专门的动作文件是怎么来的呢?他们也是可以通过3ds max导出来的,操作很简单,我们只需要在3ds max中选中“骨架”,然后导出FBX文件,再导出设置中只勾选“Animation”动画一项。我们还可以设置开始帧数和结束帧数。Untiy要求导出的文件名称格式为“模型名@动画名”。例如,我们可以给之前的“Elf”单独导出一个攻击的动画文件“Elf@Attact.FBX”,如下所示
导出“Elf@Attact.FBX”之后,我们将其复制到“Assets/Elf2”目录下查看
我们可以点击这个动画,在Inspector中的Animation选项卡中查看这个动画效果。
有兴趣的同学,可以将这个动画片段添加到“动画控制器”中进行编辑。接下来,我们继续查看“U_Character_REF”模型对应的动画,例如“Run”动画,效果如下
接下来,我们就使用Idles,Run,Jump这三个动画来演示一下吧。首先,我们在“Hierarchy”层次视图中选中“U_Character_REF”这个游戏对象,查看它的Inspector检视视图。如果没有“Animator”组件的话,我们就给它添加一个,如下所示
毫无疑问,我们需要先创建一个动画控制器。在Asset视图空白处,右击选择“Create”-》“Animator Controller”,将其命名为“U_Character_Animator_Controller”
接下来,我们双击这个文件,打开“Animator”窗口,如下
然后,我们将上面提到的Idles,Run,Jump三个动画文件拖拽进来。
默认是Idle动画,这个问题不大。接下来,我们需要链接Idle到Run动画。我们在“Idle”动画状态上面右击选择“Make Transition”,然后移动鼠标到“Run”动画状态上面点击完成。然后我们继续链接“Run”到“Jump”,如下所示
接下来,我们在创建一个“动画参数”,这次我们创建一个Int类型的“run_jump”变量
接下来,我们点击“Idle”到“Run”之间的连线,并在Inspector检视视图中编辑
这次我们选择的操作符是“Equals”等于操作符,对应的数值是1
然后我们点击“Run”到“Jump”之间的连线,设置操作数值为 2
这样的话,当我们设置“run_jump”为数值1的时候,我们的游戏角色就会从idle状态过渡到run状态,然后设置为数值2的时候,就会从run状态过渡到Jump状态。这个动画控制器设置完毕后,不要忘了将它拖拽到“Animator”组件的“Controller”栏中去。
在上图中,我们还有一个小问题要调整。就是取消“Apply Root Motion”勾选项。它的意思是说,当我们播放动画的时候,人物模型不会产生移动,也就是原地播放动画。接下来,我们来创建一个C#脚本,命名为“U_Character_Animator_Script.cs”,内容如下所示
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class U_Character_Animator_Script : MonoBehaviour
{// 动画播放组件private Animator animator;// Start is called before the first frame updatevoid Start(){// 获取Animator组件animator = GetComponent<Animator>();}// Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.W)){animator.SetInteger("run_jump", 1);}if (Input.GetKeyDown(KeyCode.J)){animator.SetInteger("run_jump", 2);}}
}
以上的代码非常简单,我们就不再过多的解释了。我们将脚本附加到人物角色上后运行工程。
运行工程之后,我们就发现了几个问题。首先,工程运行后自动播放idle动画,这个没有问题。但是,必须等idle动画播放完毕后,我们才能按下W键进入跑步动画,紧接着我们继续按下J键播放jump动作。如果不想等待idle动画播放完毕就能直接进入跑步动画的,可以点击“idle”到“run”之间的过渡线,然后取消掉“Has Exit Time”选项,如下所示
最后,人物模型就静止不动了。因为jump动画不是循环播放,且此时run_jump的数值等于2。如果想让人物模型继续进入idle动画或者run动画的话,我们需要重新设置run_jump的数值了。因此,这里的动画切换逻辑需要重新设计一下。例如,当我们按下W键的时候,设置run_jump数值为1,当按起的时候,设置run_jump数值为2。这里我们就不再演示了。
本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id
相关文章:

第三十四章 Unity人形动画(上)
在我们DirectX课程中,我们讲过一个模型最少拥有网格和材质,可以没有动画。游戏场景中的静态物体就可以是这样的模型,例如花草树木,建筑物等等,他们通过MeshRenderer就可以渲染。对于一个带有动画的FBX文件,…...

计算机图形学-GAMES101-7
引言 场景中有很多的三角形,如果实现可见性和遮挡呢? 一个简单的想法是,从远到近画,近处的物体自然会覆盖掉远处的物体,这种画法也叫画家算法。 但是实际绘制中物体的顺序是不容易确定的,比如如下图绘制…...
AndroidAuto 解决PCTS NF7
直接上代码 public void handleNavigationFocusRequest(int focusType) {// Always grant requested focus in this example.-mGal.galReceiver.sendNavigationFocusState(focusType);+mGal.galReceiver.sendNavigationFocusState...

GPT:你知道这五年我怎么过的么?
时间轴 GPT 首先最初版的GPT,来源于论文Improving Language Understanding by Generative Pre-Training(翻译过来就是:使用通用的预训练来提升语言的理解能力)。GPT这个名字其实并没有在论文中提到过,后人将论文名最后…...

Python一行命令搭建HTTP服务器并外网访问 - 内网穿透
文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章:【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…...
TypeScript5-泛型
泛型是 TS 中一个重要的概念,它可以创建可复用的组件,同时保持对类型信息的一致性。 泛型提供了一种方式使得类型可以被参数化,这样就可以创建可以适用于各种数据类型的函数或类,而不仅仅限于一个数据类型。 一、泛型 先来看一…...

IMX6ULL裸机篇之DDR3的时钟配置
一. MMDC 控制器 对于 I.MX6U 来说,有 DDR 内存控制器,否则的话它怎么连接 DDR 呢?MMDC控制器 就是 I.MX6U 的 DDR内存控制器。 MMDC 外设包含一个内核(MMDC_CORE)和 PHY(MMDC_PHY),内核和 PHY 的功能如下: MMDC 内…...
PBDB Data Service:Specimens and measurements(标本和测量)
Specimens and measurements(标本和测量) 描述摘要1. [Single specimen(单个标本)](https://blog.csdn.net/whitedrogen/article/details/130685099)2. [Add specimen records or update existing records(添加标本记录…...

Zookeeper(一)
简介 设计模式角度 Zookeeper:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那…...

Maven(五):Maven的使用——依赖的测试
Maven(五):Maven的使用——依赖的测试 前言一、实验六:测试依赖的范围1、依赖范围1.1 compile 和 test 对比1.2 compile 和 provided 对比1.3 结论 二、实验七:测试依赖的传递性1、依赖的传递性1.1 概念1.2 传递的原则…...

超级独角兽 Databricks 的崛起之路
在数据扩张以及 AI 兴起的时代,数据存储和分析平台拥有巨大价值和能量。 随着互联网数据的爆炸性增长,数据已经成为企业的新型资源,犹如石油般重要。越来越多的企业希望利用各种结构化和非结构化数据来发挥自己的优势。 然而,他…...

python 3.8 + tensorflow 2.4.0 + cuda11.0 的问题
版本匹配 🔗从源代码构建 | TensorFlow 报错:Could not load dynamic library ‘cupti64_110.dll’; dlerror: cupti64_110.dll not found 是因为我电脑中的 cuda 版本以前是 10,现在是 11.4 ,所以需要安装对应版本的 cudatoolk…...
华为杯”研究生数学建模竞赛2021 年中国研究生数学建模竞赛 E 题: 信号干扰下的超宽带(UWB)精确定位问题-参考思路
一、背景 UWB ( Ultra-Wideband )技术也被称之为“超宽带”,又称之为脉冲无线电技术。这是一 种无需任何载波,通过发送纳秒级脉冲而完成数据传输的短距离范围内无线通信技术,并且信 号传输过程中的功耗仅仅有几十 W 。 UWB 因其独有的特点,使其在军事、物联网等各个领…...
Java 中的访问修饰符有什么区别?
Java 中的访问修饰符用于控制类、类的成员变量和方法的访问权限,主要有以下四种: public:公共访问修饰符,可以被任何类访问。public 修饰的类、成员变量和方法可以在任何地方被访问到。 protected:受保护的访问修饰符…...

Go基础篇:接口
目录 前言✨一、什么是接口?二、空接口 interface{}1、eface的定义2、需要注意的问题 三、非空接口1、iface的定义2、itab的定义3、itab缓存 前言✨ 前段时间忙着春招面试,现在也算告一段落,找到一家比较心仪的公司实习,开始慢慢回…...
边缘计算:数字时代的新战场
随着数字化时代的到来,云计算已经成为了各行各业不可或缺的技术支持。但是,由于云计算涉及到数据的传输和存储,对于网络带宽和延迟的要求也非常高,这使得云计算难以满足一些低延迟、高实时性要求的场景。在这种情况下,…...
PBDB Data Service:Fossil occurrences(化石产出记录)
Fossil occurrences(化石产出记录) 描述摘要1. [Single fossil occurrence(单条化石产出记录)](https://blog.csdn.net/whitedrogen/article/details/130519180)2. [List of fossil occurrences(化石产出记录列表&…...

虾皮Shopee商品详情接口(item_get-根据ID取商品详情)代码封装
item_get-根据ID取商品详情接口 通过代码封装该接口可以拿到商品标题,商品价格,商品促销信息,商品优惠价,商品库存,sku属性,商品图片,desc图片,desc描述,sku图片…...

原生js手动实现一个多级树状菜单效果(高度可过渡变化) + 模拟el-menu组件实现(简单版)
文章目录 学习链接效果图代码要点 简单模拟el-menu实现TestTree.vueMenu.vueSubMenu.vue 学习链接 vue实现折叠展开收缩动画 - 自己的链接 elment-ui/plus不定高度容器收缩折叠动画组件 - 自己的链接 vue的过渡与动画理解 Vue transition 折叠类动画自动获取隐藏层高度以及…...

RK3568平台开发系列讲解(Linux内存篇)Linux内存管理框架
🚀返回专栏总目录 文章目录 一、内核态内存分配二、用户态内存分配三、内存篇章更新哪些内容沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起将整个内存管理的体系串起来。 对于内存的分配需求,可能来自内核态,也可能来自用户态。 一、内核态内存分配…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...