1.基于DOTS的大批量骨骼动画方案及实现
基于DOTS的大批量骨骼动画方案及实现
本文主要探讨如何基于Unity的DOTS(Data-Oriented Technology Stack)实现大规模骨骼动画的高效绘制。传统Unity骨骼动画依赖于SkinnedMeshRenderer,然而其在绘制大批量角色时,GPU绘制效率不高,主要瓶颈在于CPU将绘制数据提交给GPU。SkinnedMeshRenderer不支持静态合批、mybaits源码分析博客动态合批、GPU Instancing,导致无法有效解决此问题。 已有方案如将动画烘焙为纹理并使用GPU Instancing来绘制骨骼动画,但这种方法存在局限性,如实现动画淡入淡出(Cross Fade)较为复杂且效率低下。而DOTS提供的解决方案虽在GitHub示例中已有提及,但其功能尚不完整,需要自行实现一套骨骼动画系统以满足项目需求。Unity Roadmap已经预告了Animator的开发,但具体发布时间尚不可知。 本文基于官方的DOTS示例,构建了一个最小可用的源码密探骨骼动画播放系统,并在项目中应用。系统源码使用Entities版本为1.0.,推荐使用Unity .3.5f1c1打开。以下为系统构建步骤。1. 骨骼动画基本原理
回顾骨骼动画原理,程序实现时,所有骨骼初始位于模型坐标系原点,便于计算。每一帧AnimationClip保存对应骨骼的qce源码变换矩阵,标记为[公式]。动画播放时,读取对应骨骼的变换矩阵与顶点初始坐标[公式]相乘,得到顶点最终坐标[公式]。 若程序直接实现骨骼蒙皮动画,美术人员将反对,因所有骨骼置于模型坐标系原点,模型无法观看。因此,脱壳源码美术在模型制作软件中需正常摆放骨骼,初始姿势命名为BindPose,人型模型类似字母“T”,称为T-Pose。模型导出时需连同“从BindPose转换回局部空间的变换矩阵”一同输出。动画播放时,顶点位置需从“BindPose位置”变换至“相对于模型局部空间原点的位置”,再变换至“动画当前帧的位置”。2. 搭建Deformation底层
本文基于Unity官方的hdtv源码DOTS示例进行开发,首先移植示例代码。主要实现步骤包括: Deformation数据:通过Package Manager安装com.unity.entities.graphics包后,运行时自动为SkinnedMeshRenderer生成Entity。组件中重要的是SkinMatrix,用于存储当前帧蒙皮变换后的矩阵,通过PushSkinMatrixSystem提交到GPU。 Deformation蒙皮数据烘焙:将SkinnedMeshRenderer数据烘焙成Entity可访问的组件数据。最终生成组件包括SkinMatrix、AnimationRequest(用于接收动画请求的DynamicBuffer)、BindPose逆矩阵等。 Deformation骨骼数据初始化:在数据烘焙完成后,单独一个System初始化每根骨骼的Entity组件数据,包括SkinMatrix等。 计算变换矩阵:准备数据后,通过CalculateSkinMatrixSystemBase计算最终变换矩阵。 Shader:直接访问由CPU端传入的二进制byte数据,通过解析ByteAddressBuffer在Shader中使用SkinMatrix数据。实现GPU骨骼蒙皮算法。3. 动画控制
实现动画播放器,包括以下功能:- 自定义动画格式:通过ScriptableObject定义SkinnedMeshAnimationClip,包含位置和缩放曲线、旋转曲线。
- 动画控制逻辑:接收动画播放请求,加载动画片段数据,通过BakedCurve转化为运行时数据AnimationCurveCache,最终设置到骨骼上。
4. 调用播放动画接口
实现接口,通过两步操作让指定角色播放动画。利用Frame Debugger观察,+个角色只有一个Batch,实现了高效绘制。5. 总结
本文构建的DOTS骨骼动画系统,在满足基本功能的基础上,实现了大规模骨骼动画的高效绘制。这套系统在DOTS中补充了基础系统,为使用DOTS制作3D游戏的开发者提供了基础设施,满足了特定项目需求。