用mcu做灯光效果网站,江西省城乡住房建设厅网站,项目经理职责及工作范围,wordpress 静态文件大家好#xff0c;我是阿赵。 在几年前#xff0c;我曾经写过一篇介绍GPUSkinning的文章#xff0c;这么多年之后#xff0c;还是看到不停有朋友在翻看这篇旧文章。今天上去GitHub看了一下#xff0c;GPUSkinning这个开源的插件已经很久没有更新过了#xff0c;还是停… 大家好我是阿赵。 在几年前我曾经写过一篇介绍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 GetComponentGPUSkinningPlayerMono().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;ivertCount;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一样完整的解决方案阿赵我还是很难写出来的因为要配套写很多相关的编辑器工具对于我来说工具量还是非常大的。