当前位置: 首页 > news >正文

Unity的GPUSkinning进一步介绍

  大家好,我是阿赵。
  在几年前,我曾经写过一篇介绍GPUSkinning的文章,这么多年之后,还是看到不停有朋友在翻看这篇旧文章。今天上去GitHub看了一下,GPUSkinning这个开源的插件已经很久没有更新过了,还是停留在2017年的0.2.3版本。GPUSkinning的魅力在于可以在消耗比较低的情况下同屏显示很多个蒙皮动画的角色。
  看了一下之前写的文章,当时的我,水平也比较有限,所以只是简单的介绍了一下这个插件的用法。这么多年过去了,我感觉可以更深入的讨论一下这个插件的用法,还有它的实现原理。

一、使用说明和原理介绍

1、下载和安装

  由于最近上GitHub似乎有些困难,所以我这里再提供多一个能下载的地址:
https://kgithub.com/chengkehan/GPUSkinning/
在这里插入图片描述

  把插件下载到本地后解压缩,里面是一个Unity项目,也可以把GPUSkinning文件夹复制到自己的项目里面
在这里插入图片描述

2、采样动画数据

接下来要把我们基于Animator的动画转换成GPUSkinning插件使用的动画格式。

1.添加GPUSkinningSampler脚本

  把我们需要的带动画的预设文件拖到场景里面,然后添加一个GPUSkinningSampler脚本上去
在这里插入图片描述

  这里要注意一点,这个Animator组件里面的AnimatorController不能是AnimatorOverrideController,一定要是非Override的AnimatorController。不然会有报错提示。

2.必须设置的选项

在这里插入图片描述

  这里有几个东西需要设置,首先是这个动画角色的名称,然后是一个顶点受多少根骨骼影响,使用怎样的shader,设置根骨骼节点,选择是否生成新的Shader,最后指定动画片段。
需要注意的东西有:
  (1)顶点受多少根骨骼影响这个是可以后改的,不管选择多少根骨骼,工具都会导出uv2和uv3数据,其中uv2的数据是该顶点对应第1、2根骨骼的蒙皮权重,uv3是顶点对应第3、4根骨骼的蒙皮权重。区别只是在于自动选择或者生成的shader不同而已,shader可以后面在材质球直接选择或者修改的。
  (2)是否选择生成新shader,决定于你的模型是否有特殊的效果。如果有,比如原来的模型是使用了卡通渲染,或者pbr渲染之类的,在插件默认提供的shader里面找不到相同效果的shader可以选择时,就可以选择生成新shader,那么就会生成一个新的shader文件,里面的顶点程序是写好了蒙皮方法的,比如skin2或者skin3或者skin4之类,我们就可以修改这个shader,达到想要的效果
  (3)先设置动画片段的数量,然后动画片段需要手动拖进去,后面有两个选项,RootMotion是根节点是否移动,Individual Difference是该动画如果同时出现在多个个体身上时,是否需要有差异。之前的文章里面我说过GPUSkinning的其中一个缺点是在场景里面同一个角色播放同一个动作时会完全一样,这里的Individual Difference是为了解决这个问题,如果某个动作选择勾上这个选项,那么如果这个动作循环播放时,将会随机取一个数字,来错开动画播放的帧。

3.LOD选项

  在展开LOD选项后,可以配置LOD等级,这是一个可选项,如果本身模型有做多个不同等级的LOD模型,可以在这里设置
在这里插入图片描述

设置一个size,然后指定不同LOD等级使用的网格模型和距离。
在这里插入图片描述

4.预览和编辑

点击Preview/Edit按钮,可以打开预览和编辑的内容
在这里插入图片描述

这里可以选择动画,预览动画,并且增加动画事件
在这里插入图片描述

可以设置Bounds
在这里插入图片描述

最下面还有一个骨骼列表,前面可以勾选。这个勾选的作用,是可以保留某个骨骼节点。因为在通过GPUSkinning播放动画时,原有的骨骼和网格模型都不存在了,只有一个空节点。如果我们想做一些跟随功能,比如角色手上拿着的武器可以替换,那么我们就可以把手的骨骼勾上,这样播放的时候,会看到手的骨骼的节点,那么就可以把武器挂上去了。
在这里插入图片描述

5.采样动画

  在LOD下面,有个Step1:Play Scene的按钮。这其实就是提示我们如果要开始采样动画,就先点这个按钮运行场景。
在这里插入图片描述

  运行场景之后,这里会出现Step2,意思就是第二步,正式开始采样了。点击一下这个按钮
在这里插入图片描述

  插件就开始采样动画,并生成需要的文件了。实际上的过程,是逐个动画播放一次,然后每一帧获取骨骼的bindposes矩阵,这个矩阵是每根骨骼的位移旋转缩放,然后记录下来。
在这里插入图片描述

最后生成了这些文件
在这里插入图片描述

接下来说一下这些文件的作用
(1)anim属性文件
这个文件是导出的动画文件的总文件,里面包含了这个动画角色的大部分信息,比如名字、骨骼列表、动画列表、Bounds范围、根骨骼index、保存每帧动画的texture的宽高、Lod等级设置等。
在这里插入图片描述

(2)材质球文件
每个角色,都会生成一个材质球,如果在生成时勾选了新Shader,这里还会生成一个对应的Shader
在这里插入图片描述

(3)网格模型文件
包含了本身的角色的网格模型,还有lod等级里面的网格模型
在这里插入图片描述

仔细的看看信息,它包含了uv2和uv3的信息,上面介绍过,就是这个模型的顶点蒙皮权重
(4)还有一个包含Texture的byte文件。
  这个文件其实是一个贴图文件来的,不过是什么格式并不重要,因为里面的颜色值rgba,其实是每一帧每根骨骼的bindpose矩阵,3个顶点颜色代表了一个矩阵。
  之前在采样的时候说过,实际上是每个动画播放一次,然后每帧记录bindposes,这里就是把这些数据记录在rgba颜色里面。在需要播放动画的时候,从这些颜色值里面还原骨骼矩阵,然后结合着模型的uv2和uv3带有的蒙皮信息,就可以算出顶点在某一帧动画里面的位置了。

6.运行动画

  当生成完了需要的文件之后,就可以进行播放了
  先建一个空的GameObject在场景里,然后添加一个GPUSkinningPlayerMono脚本到GameObject上。
在这里插入图片描述

  把刚才生成的文件对应的拖入到GPUSkinningPlayerMono脚本里面
在这里插入图片描述

  当文件都拖入之后,就能看到场景里面出现了会动的模型了。
在这里插入图片描述

  这里可以选择需要播放的动画
在这里插入图片描述

  然后在运行的时候,可以通过脚本播放指定的动画:

player = GetComponent<GPUSkinningPlayerMono>().Player;
player.Play("Idle");

  观察一下GameObject节点,会发现刚才勾选了暴露的手部骨骼,在下面生成出来了。
在这里插入图片描述

  现在可以创建很多个这样的角色了同时运行。
在这里插入图片描述

二、原理的归纳

  刚才在介绍用法的时候,也介绍了一部分原理,这里归纳一下:

1、数据准备阶段

  1.通过uv2和uv3记录网格模型的顶点蒙皮信息
  2.采样的时候,每个动画播放一遍,然后每一帧记录骨骼的位移旋转缩放
  3.把动画里面每根骨骼的位移旋转缩放矩阵,通过rgba颜色,一个颜色记录四个数据,然后一个4x4矩阵原则上是需要4个像素的颜色记录的,但由于最下面一行数据是固定的0,0,01,所以只记录前面3行就够了,所以这个工具实际上只使用了3个像素颜色来记录一个骨骼的矩阵。这些像素色,记录在一张Texture2D上,然后通过Texture2D.GetRawTextureData方法获得byte[]并保存。

2、播放阶段

  1.通过一个控制器统一去加载和分配角色的动画资源,比如同一个角色,他使用的材质球其实是一样的,这样可以合并DrawCall
  2.通过Texture2D.LoadRawTextureData方法还原Texture2D数据,并还原每一帧每根骨骼的矩阵
  3.在需要播放动画的时候,通过uv2和uv3去得蒙皮信息,然后通过矩阵和权重计算出顶点的位置,达到了播放动画的目的。
  4.通过Renderer.SetPropertyBlock给Render设置不同的参数,就能得到差异化的播放动画了。

三、扩展思考

  类似GPUSkinning的功能,阿赵我其实自己也实现过,我实现过2次:
  一次是在以前做页游的时代,使用AS3编写过在GPU进行蒙皮骨骼动画播放的功能,骨骼动画的原理在之前的文章里面也介绍过,有兴趣的朋友可以去翻一下旧文章。
  另外一次是在Unity里面实现的,和GPUSkinning有点类似,也是通过贴图来记录动画关键帧信息,不过却有点不一样。
  我自己的实现方式具体是这样的:
  我在贴图里面记录的不是骨骼的信息,我也不记录顶点的蒙皮信息,我只关心顶点位置。
1、记录顶点的uv2

我把所有的顶点编了一个顺序,每个顶点的序号记录在uv2的u坐标里面,然后uv2的v坐标固定是0

Vector2[] uv2 = new Vector2[vertCount];
for(int i = 0;i<vertCount;i++)
{Vector2 tempUV = new Vector2((float)i /(float) (vertCount-1), 0);uv2[i] = tempUV;
}newMesh.uv2 = uv2;

  这里的意思是,只要根据uv2采样贴图,就能得到顶点对应某一帧的像素颜色,然后移动v坐标,就可以实现不同帧数的采样。
2、记录关键帧的时候,同样把所有动画播放一次,然后每一帧记录。不过记录的不是骨骼的bineposes,而是每个顶点在当前帧的实际位置。
这里会存在2个问题
  1.由于颜色的值只能是0-255,或者说是0-1范围,但顶点的坐标是没有范围的,而且可以是负数的。为了解决这个问题,所以需要先计算出所有顶点可能出现的最大和最小范围,记录两个Bounds,然后颜色值实际记录的,是当前顶点坐标在最大最小值之间的比例,所以肯定是0-1的。
  2.如果模型顶点很多,图片的宽度会变得特别的大,比如一个一万顶点的模型,动画总共有100帧,按照上面说的生成方式,图片的大小将会是10000x100,这样明显是不合理的,所以一般来说会设置一个最大宽度,比如2048,那么上面这个模型,将会生成一张2048*500的贴图。
3、播放动画的时候,就非常简单了,只需要指定当前需要播放第几帧,然后根据uv2的v坐标来上下移动贴图的采样范围,就能得到某一帧的颜色点,然后计算出顶点的实际坐标了。
4、由于只需要移动uv2的v坐标,所以控制方式可以很多样,单纯在shader里面用_Time来自动播放也行,传入Index指定播放某一帧也可以。
对比一下GPUSkinning,我这种方法有优点,也有缺点
优点:
  我这种计算方式,实际上是比GPUSkinning的计算量要小的,因为所有参数包括贴图都是直接放入材质球里面,基本上不需要C#的额外干涉就能播放,也不需要计算权重,直接设置顶点坐标就行。而且控制的手段也比较的灵活。
缺点:
  我这种计算方式,缺点也很明显。由于记录关键帧动画是根据顶点来记录的,所以如果顶点很多的模型,比如上万个顶点的模型,也是有的,需要记录的数据就会非常多。而GPUSkinning记录的是骨骼,一个角色模型骨骼再多也就几十到上百根骨骼而已,记录的数据就明显少很多。
  说了这么多,最后说句老实话,如果要我写一套像GPUSkinning一样完整的解决方案,阿赵我还是很难写出来的,因为要配套写很多相关的编辑器工具,对于我来说,工具量还是非常大的。

相关文章:

Unity的GPUSkinning进一步介绍

大家好&#xff0c;我是阿赵。   在几年前&#xff0c;我曾经写过一篇介绍GPUSkinning的文章&#xff0c;这么多年之后&#xff0c;还是看到不停有朋友在翻看这篇旧文章。今天上去GitHub看了一下&#xff0c;GPUSkinning这个开源的插件已经很久没有更新过了&#xff0c;还是停…...

Mysql redolog

一、redolog 是啥 数据库的ACID&#xff1a;A原子性&#xff0c;C一致性&#xff0c;I隔离性&#xff0c;D持久性&#xff1b; redolog&#xff1a;保证 持久性&#xff1b; redolog: 系统奔溃重启时需要按照上述内容所记录的步骤重新更新数据页&#xff0c;特点&#xff1a…...

【设计模式】Head First 设计模式——桥模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点&#xff0c;然后分离它们&#xff0c;从而管理变化。将变化像小兔子一样关到笼子里&#xff0c;让它在笼子里随便跳&#xff0c;而不至于跳出来把你整个房间给污染掉。 设计思想 桥模式。将抽象部分(业务功能)与实现部分(平…...

CESM2代码下载

这半年忙着毕业写论文&#xff0c;好久好久好久不更新了∠( ω)&#xff0f; &#xff0c;今天准备开个新坑 ๑乛◡乛๑&#xff0c;学习一下CESM&#xff08;Community Earth System Model&#xff09;&#xff0c;它是一个完全耦合的全球气候模型&#xff0c;可用于地球过去、…...

编写OpenCL程序的基本步骤

opencl pyopencl OpenCL-Headers OpenCL(全称为Open Computing Langugae&#xff0c;开放运算语言)是第一个面向异构系统(此系统中可由CPU&#xff0c;GPU或其它类型的处理器架构组成)的并行编程的开放式标准。 它是跨平台的。 OpenCL由两部分组成&#xff0c;一是用于编写…...

计算机网络之TCP/IP协议第一篇:网络基础知识

文章目录 写给自己的话 一:前言 1:手握金刚钻的TCP/IP 2:计算机中的协议 3:分组...

虚拟机扩容

系统环境centos8&#xff0c;分两步&#xff0c;第一步先在vmware扩容&#xff0c;第二部在虚拟机内部扩容 1.vmware分配磁盘空间 2.虚拟机内部扩容 查看当前磁盘信息&#xff0c;这个是扩容之前的&#xff0c;扩容完成才会显示新的 df -h查看系统分区信息 fdisk -l查看目录…...

Linux下的系统编程——进程间的通信(九)

一、进程间通信常用方式 IPC方式&#xff1a; Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到&#xff0c;所以进程和进程之间不能相互访问&#xff0c;要交换数据必须通过内核&am…...

Qt QtableWidget、QtableView表格删除选中行、删除单行、删除多行

文章目录 Qt QtableWidget表格删除选中行只能选择一行&#xff0c;点击按钮后&#xff0c;删除一行可以选择中多行&#xff0c;点击按钮后&#xff0c;删除多行选中某一列中的不同行&#xff0c;点击按钮后&#xff0c;删除多行 QTableWidgetSelectionRange介绍QTableWidget的选…...

【代码随想录day24】不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xf…...

数学建模--Subplot绘图的Python实现

目录 1.Subplot函数简介 2.Subplot绘图范例1:绘制规则子图 3.Subplot绘图范例2:绘制不规则子图 4.Subplot绘图范例3:gridspec辅助实战1 5.Subplot绘图范例4:gridspec辅助实战2 1.Subplot函数简介 """ 最近在数学建模种需要绘制多张子图,发现对于subplot函…...

JMeter(三十九):selenium怪异的UI自动化测试组合

文章目录 一、背景二、JMeter+selenium使用过程三、总结一、背景 题主多年前在某社区看到有人使用jmeter+selenium做UI自动化测试的时候,感觉很是诧异、怪异,为啥?众所周知在python/java+selenium+testng/pytest这样的组合框架下,为啥要选择jmeter这个东西[本身定位是接口测…...

c++ 移动构造方法为什么要加noexcept

背景: 最近看了候捷老师的c的教程, 他说移动构造方法要加noexcept, 在vector扩容的时候, 如果有移动构造方法没有加noexcept,是不会调用的. 个人感觉有些神奇, 这就去查下一探究竟. 过程: 测试代码如下: #include <iostream> #include <vector> struct A {A(){s…...

鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...

手把手教你搭建园林园艺小程序商城

现如今&#xff0c;随着互联网的快速发展&#xff0c;小程序成为了企业和个人展示产品和服务的新方式。在园林园艺行业&#xff0c;构建一个园林园艺小程序能够更好地推广和销售自己的产品和服务。那么&#xff0c;如何构建一个园林园艺小程序呢&#xff1f;下面我们来详细介绍…...

Java Iterator(迭代器)

Java迭代器&#xff08;Iterator&#xff09;是 Java 集合框架中的一种机制&#xff0c;是一种用于遍历集合&#xff08;如列表、集合和映射等&#xff09;的接口。 它提供了一种统一的方式来访问集合中的元素&#xff0c;而不需要了解底层集合的具体实现细节。 Iterator 是 …...

Logstash同步MySQL数据到ElasticSearch

当MySQL数据到一定的数量级&#xff0c;而且索引不能实现时&#xff0c;查询就会变得非常缓慢&#xff0c;所以使用ElasticSearch来查询数据。本篇博客介绍使用Logstash同步MySQL数据到ElasticSearch&#xff0c;再进行查询。 测试环境 Windows系统MySQL 5.7Logstash 7.0.1El…...

【C++】运算符重载的示例实现和应用

C运算符重载的格式&#xff1a; operator 运算符 比如要重载 ! 运算符 &#xff1a; operator ! 下面是一个例子&#xff1a; class DemoText{DemoText(string str, int num){m_text str; m_number num;}string m_text;int m_number; }这里来定义两个对象&#xff1a;…...

Kubernetes禁止调度

在Kubernetes中&#xff0c;您可以通过几种方式来禁止某个Pod调度到节点上。以下是一些方法&#xff1a; Node Selector&#xff1a;您可以使用Node Selector来限制Pod只能调度到带有特定标签的节点上。如果您希望完全禁止Pod调度到某些节点上&#xff0c;可以确保这些节点不拥…...

CocosCreator3.8研究笔记(七)CocosCreator 节点和组件的介绍

相信很多新手朋友&#xff0c;肯定会问&#xff0c;CocosCreator 中什么是节点&#xff1f;什么是组件&#xff1f; 一、什么是组件&#xff08;Component&#xff09;&#xff1f; Cocos Creator 3.8 的工作流程是以组件式开发为核心&#xff0c;即以组合而非继承的方式进行游…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

9-Oracle 23 ai Vector Search 特性 知识准备

很多小伙伴是不是参加了 免费认证课程&#xff08;限时至2025/5/15&#xff09; Oracle AI Vector Search 1Z0-184-25考试&#xff0c;都顺利拿到certified了没。 各行各业的AI 大模型的到来&#xff0c;传统的数据库中的SQL还能不能打&#xff0c;结构化和非结构的话数据如何和…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...