# 前言

上一篇文章 『锁』帧同步的简单实现 写了实现一个简单『帧锁定同步』的过程。

下一步按照正常流程来说,应该是整一个 『乐观帧锁定同步』,不过在选择继续使用个人网络小框架,还是使用开源的 ET 框架的选择上出现了一点点分歧:

如果使用个人网络小框架,那么就跟上一篇文章的 锁帧同步 实现流程类似,反正主要就是把这个『功能』实现,而不会去考虑其他。
『其它』是指什么呢?角色、场景、以及好一点的『表现』。

最后差不多也就是一个简单的 Demo,几个方块『人』受玩家操作,在场景走一走,打一打之类的。

而如果采用 ET 呢,则是冲着实现一个完整流程『游戏』过程走,主要有一下几点:

  • 在未进入匹配环节的表现,使用 TCP 协议以状态同步方式可以在一个场景中跑动或交互
  • 好看的 (或可以看的) 资源 —— 角色、人物模型
  • 研究研究状态同步 MMO 的实现 (因为此前个人都是做手游卡牌、SLG,还没涉及过这种类型)
  • 研究研究 ET (虽然以前也看过代码,不过并不深入)
  • 可能的话,把一个『MMO 网游元素』都实现一下

限于上述几点,个人做的网络小框架就不大好用了 —— 如果要说做 Demo 而已强行用,也不是不行,就是性能和扩展性肯定比不上开源了数年的 ET 了。看名字 CrySimpleNet 就知道,而且为了方便使用,反射之类的用的都不少。

于是后续就倾向于使用 ET 整了。

如此,这几天就开始搜集了下相关资源和插件 (可惜由于现在 Unity 反盗版严重, 想学习使用以前收藏的论坛都找不到几个好的插件了)

# 资源

关于这个,上次写 为博客添加Live2D看板娘折腾的那些事 那篇文章的时候,就感觉,如果有『兴趣』的话,效率会更高。

于是打算采用卡通渲染风格作表现。

首先,关于人物模型,个人收集了几个原神 MMD 模型,使用 Blender MMD 插件 cats 导出为 FBX 格式,然后放进 Unity 使用。

然后为了好看一点,在 Github 上拉了 UnityURPToonLitShaderExample 来暂且用着,后面有时间再考虑自己搞搞 —— 毕竟发现原神这个模型,就算使用内置的 UnlitShader 都有不错的表现了... 也就是说美术画的挺好。

图片
图片

(说到这里,就想起以前拿 Unity 素体做 demo 的时候了,太丑了)

其实 MagicCloth 仅仅只是常规使用是非常简单的,唯一能引起一点障碍的就是英文文档了,不过过一遍再试试也差不多了。

# MagicCloth

MagicCloth 是 Unity3D 的一个插件,采用 Unity Job System + Burst compiler 进行工作,因此据说性能上来说,肯定比以前那些单纯 C# 实现的好。

其可以同时支持 骨骼 和 Mesh 模拟,当然性能上来说官方还是推荐使用骨骼模拟。

由于整个本身是个付费插件,个人整着玩就直接找的论坛,使用的插件是论坛上找的 Magica Cloth 1.9.4,当然,最新版本早就到 1.10.3 了。

介绍的话说这么多,现在进入正题。

# 关于组件

这里主要涉及到最终表现 生效 的组件有四种:

  • Bone Cloth:以『骨骼』为最小单位进行物理模拟,效果与骨骼位置、蒙皮有关,适合头发、带骨骼的衣物
  • Bone Spring:以『骨骼』为最小单位进行物理模拟,适用于仅一个节点的配饰、小物件
  • Mesh Cloth:以『Mesh』为最小单位进行物理模拟,MagicCloth 内建了 Mesh 转换代码,会先将 Unity 的常规 Mesh 转化为 MagicaVirtualDeformer 再行使用,不过相比骨骼模拟来说,性能消耗依然不是一个量级的。
  • Mesh Spring:同上,适用于没有『骨骼』控制的小物件,例如,官方推荐可以作为胸部摇晃使用

总体来说,Bone 相关组件适用于分离物理层级,或具有骨骼蒙皮的角色。Mesh 相关组件适用于单个物体部分模拟控制,例如角色不带骨骼的部位就只能用 Mesh 进行模拟。

注:这里的骨骼特指 tranform 变换层级,就算用 Cube 组合的层级也是可以一用的

因此,虽然上面已经说了个人找了不少好康的模型,不过在这里,本文毕竟是以介绍 MagicCloth 使用为主,就先以 Cube 搭建的一个简单层级为开始吧(官方实例场景就是这样整过的)

# Bone Cloth

# 基础使用

首先,将 /MagicaCloth/Res/Prefab/MagicaPhysicsManager.prefab 放在场景中,该组件为 MagicaCloth 物理管理器,是个单例,负责执行实际物理更新。

在每个对象挂载的 Cloth 相关组件初始化时会调用 MagicaPhysicsManager.Instance.Team.CreateTeam 将自身注册进去,因此每个场景必须有一个。

然后,创建了四个球体,并形成子父级,每个子节点的 Position 都是 (0,-1.5,0),于是形成如下排列:

图片

点击第一个球体,创建 BoneCloth,然后把它的引用放在 RootList:

图片

点击 StartPointPosition 检查可移动节点:

图片

此时可能会发现 “全绿”,代表全部可以被模拟移动,这样是不行的,作为 BoneCloth,至少需要一个 固定节点,以使其不会无限往下掉。

点击 Fixed Point,然后点击根节点的球体处,可以将其设置为固定点,如上图所示。

最后点击最下方的红色 Create 按钮,MagicBoneCloth 就会根据当前设置生成数据,可以在组件最上方看到:

图片

然后运行游戏,可以看到:

什么都没发生!

原因很简单:Magica Bone Cloth 貌似是不能放在被控制的骨骼层级下的,刚才我们创建的 Magica Bone Cloth 组件直接就是 Sphere 的一个子级了。

正规来说,应当建立一个作为父级的空物体来装载,不过此时可以简单地将该物体拉出来:

图片

再运行,表现就出来了:

图片

# 头发模拟

步骤与上述基本一致,不过由于其模拟复杂一些,可能需要额外的配置项。

不过 MagicaCloth 直接提供了一些常用的参数的预制项,若感觉麻烦,直接加载使用即可。

不过正规使用的时候,一般还需要添加碰撞体,以防止物理模拟下导致的『穿模』,MagicCloth 同样提供了两种碰撞体:胶囊碰撞体及球形碰撞体。

这里以原神角色 刻晴 为例:
(因为她的头发看起来比较合适)

  1. 右键角色,创建 Magica Bone Cloth
  2. 将两根作为头发的骨骼根节点节点放入 RootList
  3. 确认初始固定点正确
    图片
  4. 为了效果好一点,可以加点碰撞,右键角色,Create Magica Sphere Collider,然后调整好大小
    图片
  5. 点击面板上的 Collider 项目下 All Select 可以自动加载所有该对象下的 Collider
    图片
  6. 手动配置参数或点击下方的设置处的 Preset 按钮,加载一个合适的预设配置
    图片
  7. 点击 Create 创建模拟数据
  8. 运行场景查看效果

其中,如果是环形封闭的裙子,则需要注意将 ConnectMode 设置为 Mesh:

图片

最后效果如下:

图片

(有同学可能会好奇为什么角色会眨眼睛?因为 MMD 模型自带 表情的 BlendShape,于是就简单用脚本控制了一下眼睛,加了个眨眼睛的动作,让她好康一点 (✪ω✪))

# Mesh Cloth

Mesh Cloth 与上述 Bone Cloth 使用方式类似,区别只是前置准备的差异。
例如:Mesh Cloth 需求额外的 VirtualMesh 组件等。

还是以一个 Cube 为例,下面说一下需要额外准备的差异步骤:

  1. 创建一个空物体,这里命名为 MeshClothObj,并在其下级创建一个 Cube
  2. 在 Cube 上挂载 MagicaRenderDeformer
  3. Create MagicaVirtualDeformer
  4. 将 Cube 上的 MagicaRenderDeformer 引用至 MagicaVirtualDeformer RenderDeformer 参数
  5. 创建 MagicaMeshCloth,并将上一步创建 MagicaVirtualDeformer 引用设置过来
  6. 点击 StartPointPosition,设置固定点与可移动点,最后如图所示:
    图片
  7. 点击 Create 创建数据,运行即可看到效果了

最后效果如下:

图片

这里由于采用了 Cube 作为示例,因此看起来相比布料更像『果冻』。

如果采用面数更高的模型就可以看到并调整类似布料效果了。


参考文章:

  • 官方文档