MagicaCloth2中文文档

提示:经搬运者测试,在ecs1.0中运行最为良好

如何安装

目录 [隐藏]

如何安装

MagicaCloth2 需要 Unity 2021.3.16 (LTS) 或更高版本才能工作。
购买资产后,您可以从包管理器安装它。

从编辑器菜单中打开 Window/PackageManager,然后从 MyAssets 中选择 MagicaCloth2 进行导入。

img

它需要两个包,Burst和Collections才能工作,但这些包在导入MagicaCloth时会自动安装。
因此,与 Ver1 不同,无需手动单独安装软件包。

如果在安装过程中出现以下对话框,请在安装完成后重新启动 Unity 编辑器一次。

img

运行测试示例

导入完成后,让我们检查操作。
UnityChanKAGURA_从演示场景文件夹,如下所示?? 加载场景。

img

这些示例分为渲染管线(CoreRP/URP/HDRP),因此请从您当前使用的渲染管线的文件夹中选择。
每条pib线的场景之所以不同,只是为了切换绘图着色器,与MagicaCloth的操作无关。

如果执行场景,角色的袖子、头发、裙子等都在晃动,则安装完成。

img

可以删除示例文件夹

可以删除资产中包含的“示例(可删除)”文件夹。
如果不需要该示例,可以安全地将其删除。

如何更新

MagicaCloth定期更新。
在大多数情况下,最新版本通过导入工作正常。
但是,如果文件的结构发生更改,则旧文件和新文件可能会重复并可能失败。
因此,请按照以下步骤尽可能执行全新安装。

  1. 对项目进行完整备份
  2. 从 Unity 编辑器中删除 MagicaCloth2 文件夹
  3. 从程序包管理器导入最新的 Magica Cloth 2
发生错误时该怎么办

如果在使用上述步骤导入或更新后仍发生错误,则可能是由于某种原因未安装或已过时所需的软件包。
首先,从菜单中打开 Windows/包管理器,然后选择 InProject 以显示列表。

img

MagicaCloth 需要突发 1.8.1 或更高版本和集合 1.4.0 或更高版本才能工作。
确保“突发”和“集合”存在于此列表中,并且是正确的版本。
如果软件包不存在或已过时,则需要按照以下步骤手动安装它:

  1. 按包管理器左上角的 + 按钮 [从 git URL 添加包…] 选择
    img
  2. 要安装 Burst,请在 URL 中输入“com.unity.burst”并执行它。
  3. 要安装集合,请在 URL 中输入“com.unity.collections”并执行它。

这将安装最新版本的突发和集合。
如果错误仍然存在,请联系支持人员
在这种情况下,如果您可以描述控制台开头显示的错误全文,那将非常有帮助。

如何卸载

如果由于某种原因您不再需要MagicaCloth,则可以按照以下步骤将其卸载:

  1. 删除 MagicaCloth2 文件夹
  2. 从包管理器卸载突发
  3. 从包管理器卸载集合
  4. 从包管理器中卸载数学

删除包时请谨慎操作,因为项目中可能还有其他资源正在使用中。

如何检查版本

MagicaCloth的当前版本是Tools/MagicaCloth2/About。 您可以从菜单中检查它。

img

如何使用骨布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目录 [隐藏]

起先

以下是有关如何使用MagicaCloth的指南。
让我们逐步了解每个功能。
省略了每个项目的详细说明,以方便解释。
有关详细信息,请参阅单独的参考页面。
从最常用的骨布开始!

什么是骨布?

BoneCloth是一种基于Unity的变换结构执行交叉模拟的机制。
非常适合摇曳头发和配饰,骨头内置于网眼中。

  • 通过操纵变换来表达摇晃
  • 由于处理负荷低,它可以大量使用。
骨布简介

在这里,我将以示例中的 UnityChanKAGURA 腰带为例来解释设置。

img

首先,为您的角色添加一个魔术布组件。
选择一个字符以在“层次结构”窗口中打开右键单击菜单。
从菜单中选择创建其他/魔术布2/魔术布,如下所示:

img

这将生成一个 MagicaCloth 游戏对象。

img

对于放置MagicaCloth组件的位置没有特别的限制,因此请随意放置它们。

检查器概述

魔法布检查器由四个方块组成:
… 信息窗口
蓝色… 模拟设置
绿色… 运行参数设置
黄… 在 SceneView 中配置辅助图标显示

img

有很多,但只有蓝色和绿色部分与设置相关。
首先,蓝色部分设置仿真目标,然后绿色部分设置晃动行为。

骨布使用设置

首先要做的是将组件的类型更改为BoneCloth。
将布料类型更改为 [骨布],如下所示:

img

这将切换 BoneCloth 的检查器。

配置转换

您需要在 BoneCloth 中注册要模拟的转换。 在卡古拉,腰带有10种转变,如下所示。

img

在 BoneCloth 中,仅注册作为层次结构起点的转换。
在腰带中有两个变换:[DB_Wing_01_L] 和 [DB_Wing_01_R]。

img

将这两个转换添加到根骨骼列表中。

img

此时,“场景”视图使用红色和白色球体以及浅蓝色线条可视化变换结构,如下所示:

img

红色和白色球体表示模拟顶点的属性。
浅蓝色线代表变换的连接结构。

切换小控件的显示

img

您可以在检查器底部“小控件”面板中的“场景”视图中显示的小控件类型之间切换。
请注意,如果您取消选中启用,则不会显示小控件。
详细信息将在单独的页面上解释。

顶点属性和绘制

在MagicaCloth中,模拟顶点分为三个行为属性。

固定需要系留不从其原始位置移动 的顶点移动顶点
迁移白色或绿色绘画时用绿色表示,以获得自由移动的顶点 可见性
忽视模拟中完全忽略的顶点

BoneCloth 将添加到根骨骼的变换设置为固定属性,并自动设置其余变换以移动属性。
如果要更改此设置,还可以手动重写顶点属性。
在这种情况下,请单击笔标记以启动顶点绘制模式,如下所示。

img

场景视图中将出现一个绘画窗口,您可以在其中更改顶点属性。

img

本指南不详细介绍顶点绘制。
我将在如何使用网格布中详细解释顶点绘制。

参数设置

设置变换和顶点属性后,您所要做的就是设置控制移动的参数。
该参数是实现理想运动的基本项目。
但是,从检查器中可以看出,有很多参数,需要一些经验和熟悉才能掌握整个事情。
因此,最好从预制预设开始,以便于设置。
这可以从检查器的“预置”菜单中选择。

img

按下预设按钮并选择 [尾部] 预设。

img

尾部预设内容现在已扩展为参数。

操作检查

您所要做的就是按下 Unity 编辑器中的播放按钮。
让我们完成它!
如果你在奔跑过程中移动你的角色并且你的腰带在摆动,你就成功了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运行时延迟

关于执行,有一件事要提一下。
与Ver1不同,MagicaCloth2在运行时动态创建交叉数据。
此跨数据创建是在后台线程上完成的,但需要一点时间。
这意味着在角色出现和模拟实际开始之间会有几帧的延迟。
请记住这一点。

下一步是什么?

这一次,我可以轻松地运行BoneCloth,但我仍然需要做很多工作才能更接近我的理想动作。
首先,请继续阅读以了解如何使用MeshCloth
了解网格交叉模拟和顶点绘制。

如何使用网布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目录 [隐藏]

起先

本指南继续介绍如何使用BoneCloth
因此,我们将跳过已经讨论过的项目,因此请在本指南之前阅读如何使用 BoneCloth

什么是网布?

网格布是一种交叉模拟网格顶点的方法。
它可以表达比骨布更逼真的颤抖。
但是,负载更高。

  • 通过操纵网格顶点表示抖动
  • 即使网格不包含骨骼也可以使用
  • 如果由于处理负载高而大量使用它,请注意性能
  • 主要适用于台式电脑和高端控制台
配置模型导入程序

在使用网布之前,您需要检查目标模型的导入设置。
网格布需要网格的读/写属性来操作顶点。

由于这通常为 OFF,因此请在“项目”视图中选择目标模型,并将模型导入程序的“读\写”检查设置为“开”,如下所示。

img

其他条件

  • 对于蒙皮网格,一个顶点的最大权重必须为 4 或更少。
网布介绍

让我们介绍一下MeshCloth。
在这里,我将以示例中的 UnityChanKAGURA 裙子为例来解释设置。

img

首先,从层次结构中的右键单击菜单中添加一个 Magica Cloth 组件,就像 BoneCloth 一样。

img

然后将“布类型”更改为“网布”。
这会将检查器切换到网格布。

img

MeshCloth 檢查器與 BoneCloth 的區別僅在於 Main 配置,如下所示:
其余部分与BoneCloth相同。

img

渲染和代理网格

使用 MeshCloth 时的一个重要概念是代理网格划分。
MeshCloth 不使用渲染网格或显示网格进行模拟。
这主要是由于以下原因:

  • 如果按原样使用渲染网格,顶点数量将太大,模拟负载将巨大
    (即使对于简单网格,顶点数量超过 10,000 的情况也并不少见)。
  • 三角形连接结构一般不适合仿真
  • 在许多情况下
    ,为了表达而分割网眼(例如,分割以分离裙子背面和正面之间的材料)

代理网格解决了这个问题。
代理网格是基于渲染网格的具有减少顶点的虚拟网格。
此代理网格在运行时仅存在于内存中。

下图显示了原始渲染网格(顶部)和简化代理网格(底部)之间的关系。

img

img

您可以看到下行中的代理网格减少了顶点并简化了形状。
在 MeshCloth 中,所有模拟都在此代理网格上运行。
然后将结果反馈到原始渲染网格并显示在屏幕上。
请记住这一点,因为这是一个非常重要的概念。

注册渲染网格体

现在,让我们注册渲染网格,它是代理网格的源。
您可以注册 SkinnedMeshRenderer 和 MeshRenderer。
KAGURA的裙子被分配了SkinnedMeshRenderer,如下所示:

img

将此 SkinnedMeshRenderer 添加到 MeshCloth 的源渲染器列表中。

img

场景视图现在显示代理网格。

img

此代理网格在简化之前,因此它仍然具有与渲染网格相同的结构。

还可以注册多个渲染网格。
在这种情况下,所有渲染网格将合并到单个代理网格中。

减少

创建渲染网格时的代理网格与渲染网格具有相同的结构。
可以按原样开始仿真,但如上所述,以更简单的形式使用代理网格在性能和稳定仿真方面具有优势。
还原是简化的工作。

减速面板

img

简化是通过组合两个滑动条来完成的。

简单距离只需连接附近的顶点即可。 它不考虑网格的结构等。
形状距离根据网格的形状连接附近的顶点。 未作为曲面连接的顶点即使靠得很近,也不会连接
在查看场景视图时进行调整

尝试移动滑动条。
移动滑动条可实时简化代理网格,并将其显示在场景视图中。
让我们看一下场景视图并简化代理网格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

应该简化多少?

这取决于网格的形状和长度以及您要执行的模拟类型,因此很难设定通用标准。
但是,请参考以下指标作为指导。

  1. 代理网格越简单,性能越好
  2. 应该将其简化为消除渲染网格的细突起。
  3. 如果过于简化,碰撞检测将很弱。
    此外,渲染网格和代理网格之间的间隙可能会变大,并且显示可能会变得不稳定。
完成代理网格

这一次,我试图将其简化为代理网格的表面几乎平坦的程度。

img

顶点涂料

简化代理网格后,下一步是确定每个顶点的行为。
这就是顶点绘制的作用。
与BoneCloth不同,MeshCloth的顶点涂料很重要。
这是因为在 MeshCloth 中,所有顶点属性都初始化且无效。
因此,在MeshCloth中,有必要始终进行顶点绘制以确定每个顶点的属性。

固定和移动属性

这里的重要任务是将非移动顶点与移动顶点清楚地分开。
以裙子为例,腰部附近的顶点不应移动,其余部分应自由移动。
非移动顶点称为固定属性,移动顶点称为移动属性。

启动顶点绘制

顶点绘画由下一个笔标上的按钮激活。
启动时,场景视图将切换到绘画模式。

img

img

油漆面板

“画图”属性是使用“画图”面板设置的。

img

画点大小显示的顶点球体的大小
画笔尺寸画笔大小
显示形状打开后,代理网格的结构显示为小控件。
背面剔除启用后,当代理网格体的顶点法线与场景摄像机的方向相反时,不会显示顶点球体。
Z 测试打开后,顶点球体将显示网格和深度测试结果。
油漆属性选择要绘制的顶点属性

顶点属性分为三类:

移动绿将移动属性 设置为可以自由移动的顶点
固定将固定属性 设置为不移动的顶点
无效灰色设置要从无效属性模拟中 排除的折点。 例如,如果腰部以上的区域与模拟完全无关,例如一件,则将其设置为禁用属性将提高性能。
成品漆

让我们实际绘画。
选择要绘制的属性,并通过单击或将鼠标光标拖动到代理网格进行绘制。

对于这条裙子,我画了如下。
完成绘画后,按“退出”按钮退出绘画模式。

img

这样就完成了代理网格的配置!

参数设置

最后,设置控制运动的参数。
在这里,让我们从预设以及如何使用BoneCloth轻松设置它。

从预设菜单中选择[裙子],如下所示:

img

img

裙子的预设内容现在已扩展为参数。

操作检查

让我们完成它!
如果你在奔跑和裙子中移动你的角色,你就成功了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下一步是什么?

这一次,我做了MeshCloth的最小设置。
但是,从动画中可以看出,这条裙子尚未设置为检测与人体的碰撞。
因此,裙子穿过腿部。
下一章将更详细地介绍此碰撞检测配置

配置碰撞检测

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目录 [隐藏]

起先

在这里,我们将解释与人体的碰撞检测,这在模拟角色的服装时是必不可少的。
BoneCloth 和 MeshCloth 的碰撞检测设置相同。

碰撞检测的类型

MagicaCloth有四种碰撞控制机制。

碰撞体碰撞检测与碰撞体(如球体、胶囊、飞机等)进行碰撞检测。 这是最常用的技术。 我将在此页面上进行解释。
逆止器通过设置可以穿透顶点法线方向的距离和半径来防止交叉进入人体的方法。
自碰撞自碰撞。 它可以防止十字架挖进自己。
相互碰撞相互碰撞。 防止十字架切入其他布料。

本页仅介绍碰撞机碰撞检测。
有关其他碰撞检测,请参阅专用指南页面。

对撞机碰撞原理

碰撞体碰撞检测的原理很简单:执行拉伸,使顶点不会穿透碰撞体的形状,例如球体或胶囊。

img

通过根据人体的形状布置这种对撞机,它是一种防止布料进入的机制。

对撞机类型

对撞机有多种形状可供选择。

球体对撞机

img

它是一个球形对撞机。

胶囊对撞机

img

它是一个胶囊形的对撞机。
您可以更改起点和终点的半径和长度。

平面对撞机

img

它是一个平面对撞机。
无法设置大小。
它被视为一个无限平面。

箱式碰撞体

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(目前未实施)

碰撞模式

您可以选择如何为碰撞体确定代理网格。

顶点球体模式

代理网格的顶点被视为球体,并使用碰撞体进行碰撞判断。
球体的大小是可调的。

img

它的优点是能够使用它而不必担心它,因为处理负载很轻。

但是,请注意,如果对撞机很小,则存在它在球之间滑动的问题。

img

边缘模式

此模式确定代理网格体边缘与碰撞体之间的碰撞。
边缘的厚度是可调的。
边缘模式具有很大的优势,即不存在球形模式下存在的滑移问题。

img

但是,请谨慎使用它,因为它的处理成本高于球体模式。
最好仅在顶点球体模式出现问题时才考虑使用它。

碰撞体放置

现在,让我们以神乐裙子为例设置一个对撞机。
假设裙子已经使用网布设置好了。

对于裙子,您需要一个腿部对撞机和腰部对撞机。
首先,选择左脚的骨头。
在神乐中,它将是[CH_Thigh_L]。
然后打开右键菜单并选择创建其他/Magica Cloth2/Magica 胶囊对撞机。

img

胶囊碰撞体组件已添加如下:

img

然后,该小控件将显示在“场景”视图中。

img

使用胶囊对撞机上的探测器调整位置和大小。

img

胶囊对撞机具有单独的方向和长度,以及起点和终点半径。
尝试更改每个参数。
您应该看到“场景”视图中的小控件会相应地转换。

如果希望胶囊对撞机的起点和终点尺寸不同,请按检查器上的[S]按钮,如下所示。

img

这允许您独立设置开始和结束半径。

img

使用这些属性将碰撞体调整到您的腿部。
进行调整时,请将场景视图更改为线框模式以获得更好的可见性。

img

此外,通过移动碰撞体的游戏对象而不是中心属性来调整位置通常更容易。
调整碰撞体以使其位置如下:

img

让我们以同样的方式将球体碰撞体添加到臀部。
选择腰骨的[CH_Hips],然后从右键菜单中选择球体碰撞体。
添加了球体碰撞体。

img

球体碰撞体的属性很简单,只有半径。

img

调整半径和位置以匹配左髋线,方法与胶囊对撞机相同。

img

在右侧也这样做,最后放置四个碰撞体,如图所示。

img

注册碰撞体

让我们注册使用交叉组件创建的最后一个碰撞体。
请注意,没有注册,对撞机将无法工作。
碰撞体注册在“碰撞体碰撞”面板中完成。

img

在碰撞体列表中注册生成的碰撞体。

img

这样就完成了对撞机的设置!

顶点半径和摩擦设置

最后,设置碰撞模式、其厚度(半径)和上述摩擦力。

img

还可以使用曲线更改厚度,以根据代理网格顶点的深度改变半径。
尝试操作 RADIUS 滑动条。
您在场景视图中设置的半径应实时反映。
查看此场景视图时,调整适合您放置的碰撞体的顶点球体的大小。
这一次,顶点球体的大小被统一设置为 0.02。

img

摩擦是碰撞体和顶点接触时滑移的难度。
增加值可以减少其滑度。

操作检查

现在,一切都准备好了!
让我们实际运行它并检查运动。
如果碰撞体设置如下,代理网格的顶点碰撞并防止穿透,则成功!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下一步是什么?

到目前为止,我们已经解释了如何使用BoneCloth和MeshCloth,以及如何设置碰撞检测。
但是,为了执行理想的运动,有必要调整大量参数。
以下参数配置指南介绍了它们的工作原理。

设置参数

img

目录 [隐藏]

起先

为了实现理想的运动,必须调整参数。
本节介绍与参数密切相关的基线的概念以及每个参数的作用。

了解基线

img

设置参数需要了解的一件事是基线的概念。
基线是从代理网格的固定顶点开始,沿着表面连接到末端移动顶点的路径。

例如,请考虑以下转换层次结构:

img

从此结构的固定骨骼开始创建骨布时,将按如下方式分配基线:

img

您可以通过检查小控件的 [基线] 来检查此行。

img

MagicaCloth根据此基线恢复形状。
这实现了类似 2.5D 的行为,该行为结合了 2D 运动,同时保留了物理上逼真的运动。

起点、终点和深度

基线包含有关起点、终点和深度的信息。
您可以通过在小控件设置中打开[基线]和[深度]来检查这一点。
让我们以转换结构为例。
白色数字代表深度,起点为(0.0),终点为(1.0),您可以检查每个顶点落到的深度。
这个深度数字是参数设置不可或缺的指标。

img

深度会自动分配,以便代理网格中最长基线的端点为 (1.0)。

骨布的基线

在 BoneCloth 中,基线只是从转换的树结构构建的。
因此,它与转换层次结构相同。

网布基线

MeshCloth 稍微复杂一些,基线是根据固定顶点周围的表面连接自动计算的。
例如,在神乐裙中,基线自动形成如下:

img

请记住,MeshCloth 基线因表面连接和固定顶点的分布而异。

深度与参数的关系

如上所述,创建基线时,将为每个顶点设置深度。
此顶点的深度是调整参数时的重要指标。
MagicaCloth中的许多参数都根据此深度确定数字。

例如,让我们看一下限制角度的角度限制运动。
“角度限制”限制基线边可以弯曲的角度。
“角度限制”设置面板如下所示:

img

目前,曲线设置处于关闭状态,因此无论深度如何,都会均匀设置 60 度。
让我们在这里按右侧的 [C]。

img

这将扩展检查器,以便您可以设置曲线。
这允许您为每个顶点的深度设置不同的限制角度。
让我们看一下已设置的曲线的内容。

img

横轴为深度(0.01.0),纵轴为参数强度(0.01.0)。

在深度 (0.0) 处,强度为 0.2,因此极限角为 60x0.2 = 12 度。
在深度 (0.5) 处,强度为 0.6,因此极限角为 60 x 0.6 = 36 度。
在深度 (1.0) 处,强度为 1.0,因此极限角为 60 x 1.0 = 60 度。

尝试将其与上面的BoneCloth深度图相结合。
顶点深度(0.0~1.0)对应于曲线的水平轴。
我想你可以理解每个顶点所承受的极限角度是如何确定的。

img

这样,曲线参数的最终值与深度一起计算。
这是深度和参数之间的关系。
请记住,任何带有 C 按钮的参数都与此相对应。

参数类型

在这里,我们将按类型介绍实际存在什么样的参数。
详细解释每个参数的功能会产生大量的页面,因此在这里我们将重点介绍参数的概述及其设置指南。
有关参数的详细信息,请参阅单独的参考。

img

力控制**:
控制**重力和空气阻力等力。
最好在一定程度上增加重力以实现逼真的运动。
如果空气阻力降低,顶点不会静止不动。
相反,如果增加空气阻力,顶点会缓慢移动。

重力衰减可减少由于十字方向引起的重力影响。
例如,如果 Falloff 为 1.0,如果十字与初始姿势的角度相同,则根本不会有重力。

角度修复

img

将“恢复角度”基线的每个边**旋转
**回其原始位置。
此角度恢复是控制运动的最重要参数。
可以肯定地说,大部分运动都是在这里决定的。

刚度是一次性补偿的旋转角度量。
增加刚度将加快恢复速度。

速度衰减是在恢复过程中应用于顶点的速度衰减。
当降低时,加速度变得更强并像弹簧一样反弹,相反,当升高时,它变成了悠闲的恢复。

调整这两个属性需要一些熟悉和经验。
首先,您可能希望加载预设并尝试复制其内容。

角度限制

img

角度约束
限制基线的每一条边从其起始位置弯曲的角度。
如果您不希望它弯曲太多,例如刘海或类似的东西,它是有效的。
设置一些角度限制以保持裙子的形状也是一个好主意。

形状修复

img

[形状恢复]
执行三个动作以保持代理网格的形状。

距离网眼拉伸性。 每个顶点移动以保持与其连接的顶点的恒定距离。 通常,将其保留为 1.0 就可以了。但是,如果外部稍微拉伸一下看起来更好,例如旋转裙子,那么使用曲线来削弱终点附近的弹性也很有用。
系链限制顶点接近其基线起点的距离。 您只能设置缩小的范围。 降低压缩可防止折点接近其起点。 相反,如果您抬起它,顶点将能够自由移动。降低该值可使网格形状不易变形。 这避免了交叉过度收缩的现象。 但是,由于行动自由度降低,在某些情况下可能会很尴尬。 通常,建议将其设置为0.8或更高,并有限地降低。
三角形弯曲网格弯曲。 它可以将相邻三角形返回到其原始角度。 这是保持网格形状的重要部分。 1.0 通常没问题。 如果代理网格中没有三角形,则不执行任何操作。
惯性

img

惯性决定了十字的移动
如何影响顶点。
这是仅次于角度恢复确定运动的重要参数。

十字架总是有一个中心点。
这是根据固定属性的分布自动确定的,并在场景视图中显示为紫色球体。

img

当该中心移动时,运动和旋转力传递到顶点。
惯性参数限制了运动力。

例如,如果晃动对于角色的移动来说太大,则可以添加限制来抑制整体晃动。
此限制有四种类型,每种类型都具有以下特征:

运动惯性 旋转惯性减少运动或旋转力本身。 例如,如果属性为 0.1,则只会将十字移动的 1/10 添加到顶点。 即使十字高速移动,也能抑制晃动。但是,即使十字架移动缓慢,运动力也会减小,因此也存在晃动极小的缺点。
深度惯性根据顶点的深度减少惯性。 简单地说,如果增加此属性,深度越接近起点,它的移动难度就越大。 终结点不会收到缩减。如果您不希望裙子或头发在起点附近移动太多,这将很有用。 但是,请注意,如果起点附近的惯性减小,则整体运动将较弱。
移动速度限制 转速限制以设定速度切割运动力或旋转力。 例如,如果移动速度限制 = 2.0,则当角色在移动的 2 m/s 以内时,力将按原样传递,如果超过 2 m/s,则无论顶点移动的速度有多快,都不会再施加力。 此限制将摇晃限制在一定范围内,无论您是缓慢移动还是高速移动。基本上,我们建议从运动惯性/旋转惯性中使用它。
粒子速度限制限制单个顶点的最大速度。 这可以缓解长带尖端因离心力而过度向外膨胀的现象。但是,如果将其降低到 1.0 (1 m/s) 或更低,则碰撞检测的准确性会降低,因此在降低该值时要小心。
移动限制

img

移动约束(逆止器) 约束顶点相对于
代理网格的顶点法线方向的移动。
这也称为逆止器。

img

有关其工作原理,请参见上图。
简单地说,顶点只能在最大距离范围内移动,在逆阻碰撞之外移动。

例如,假设一件 T 恤的所有顶点法线都指向人体外部。
在这里,我们使用逆止器函数来限制顶点在与法线相反的方向上穿透超过一定距离。
这可以防止 T 恤在不使用碰撞对撞机的情况下咬入人体。
使用相同的原理也可以轻松防止刘海挖入头部内部。

重要的是它是使用代理网格的顶点法线计算的。
请记住,渲染网格的顶点法线没有任何关系。
此外,要限制的顶点位置和法线是从模拟前蒙皮代理网格的姿势获得的。
并且代理网格的法线也可以调整。

逆止器的描述可能有点长,因此请参阅逆止器描述页面以获取更多信息。

碰撞体碰撞

img

【对撞机碰撞检测】
这是最常用的碰撞控制,它使用球体和胶囊等对撞机来限制十字架进入人体。
碰撞体碰撞检测在碰撞检测设置中有详细说明,因此请参考。

自碰撞

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 试用版

img

【自碰撞+互碰撞】
在这里可以设置一个自碰撞,防止十字架切入自身,设置一个相互碰撞,防止十字架切入另一个十字架。

img

当使用自碰撞时,十字架与十字架本身碰撞,如图所示。
但是,自碰撞需要大量的碰撞计算,这是非常昂贵的。
因此,建议在台式PC和高端控制台上使用。

还要记住,自碰撞目前是一个实验性功能,即测试版。
因此,将来可能会更改行为和设置。
有关自碰撞的更多信息,请参阅专用页面。

校准提示

到目前为止,我们已经解释了每个参数的作用。
剩下的就是反复试验和错误,以更接近理想的机芯。
但是,这项工作非常困难,因此我想发布一些调整提示。

首先调整关键参数

参数数量很多,但真正决定运动的只有少数几个项目。
尝试先调整这些。

重力和空气阻力 ,这与顶点的运动有很大关系。
角度修复这是决定整个旋转修复运动的最重要参数 。 最好先从这里进行调整。
惯性如果角色奔跑或跳跃时十字架移动太多,请在此处进行调整。
运行时可调节

在执行期间,可以从检查器调整参数。
通过在玩实际游戏时进行调整,试错变得更加容易。

利用预设

img

预设是参数设置的快捷方式。
首先,让我们加载预设,看看它是否接近理想运动。
如果您的预设接近理想运动,则可以通过从那里独立调整参数来节省时间。

保存预设

参数可以轻松保存为原始预设。

img

将来之不易的参数保存为预设。
保存的预设可以通过预设按钮轻松设置。
在设置类似动作时,这可以节省大量时间。
预设也可以在运行时保存。

利用组件副本

调整时的难点之一是,在执行结束时将恢复在执行期间调整的检查器的所有内容。
让我们利用组件复制功能来避免这种情况!
此功能允许您通过在执行过程中按组件的“…”按钮来复制检查器的内容。

img

如果在执行过程中成功调整参数,请使用此函数复制内容。
然后,在执行完成后,从组件的“…”菜单中选择“粘贴”。

img

此操作允许您将正在运行的参数恢复到已停止的检查器。

下一步是什么?

到目前为止,我们已经解释了MagicaCloth的基本设置。
通过应用这些,可以设置大多数其他布。
因此,如果您不想做太多复杂的事情,则无需阅读任何进一步的指南。

但是,有一些功能我们尚未详细说明,例如设置逆止器和自碰撞。
如果您想了解更多关于它们的信息,请继续阅读我们的其他指南。

顶点绘制方法

img

目录 [隐藏]

什么是顶点绘制?

通过使用顶点绘制,可以将属性分配给代理网格的顶点。
通常,此函数用于将固定、移动和无效属性分配给顶点。
它还用于特殊属性设置,例如启用支持。

顶点绘画可以从基本设置中的绿色笔标记和“移动限制”面板中的蓝色油漆标记启动。

移动属性绘制

img

此绘制将移动、固定和禁用属性分配给顶点。

运动限制涂料

img

此油漆将移动限制分配给顶点。

基本操作

基本操作面板如下所示:

img

点大小更改用于绘画的顶点球体的大小。 此球体的大小与模拟无关。
画笔尺寸画笔的大小。
形状打开后,代理网格的结构显示为一条线。
淘汰如果设置为 ON,则当代理网格体的顶点法线与场景摄像机的方向相反时,不会显示点。 请注意,它是普通的代理网格,而不是渲染网格。
Z 测试打开后,将使用显示网格对顶点球体进行深度测试。
通过如果打开它,则可以忽略深度并填充光标中的点。 画笔大小也将更改为专用尺寸。
油漆属性确定要绘制的属性。 这取决于油漆的类型。
填补使用 set 属性填充所有点。
退出完成顶点绘制。 当前内容反映在组件中。

将鼠标光标移动到代理网格时,蓝色圆圈和填充顶点将显示为黄色。

img

您可以通过按原样单击或拖动鼠标进行绘画。

如何取消

顶点绘制没有明确的取消按钮。
因此,如果要取消顶点绘制的内容,请使用标准撤消功能。
这是编辑/撤消…,或菜单中的Ctrl + Z。

绘制移动属性

img

最常用的是绘制此顶点移动属性。
在顶点上绘制移动属性、固定属性和无效属性。

移动一个自由移动的顶点。
固定要固定的顶点。 有必要系住移动顶点。
无效无效的顶点。 无效顶点将完全从模拟中排除。 当顶部与模拟无关时,可以将其设置为一件,以便提高性能。
固定属性的重要性

固定属性用于将相邻的移动折点固定在一起。
因此,必须设置固定属性。
如果没有固定属性,则无法进行以下设置,因为无法连接移动折点。

img

在这种情况下,移动顶点将保持原位或下降。
请务必将它们与固定顶点连接,如下所示。

img

油漆移动限制

img

移动限制功能(如挡块)可以将自己的存在或不存在设置为顶部。
例如,通过按如下方式绘制,灰色顶点可以禁用移动限制功能。

img

带纹理的顶点绘画

在网格布中,您可以按纹理设置顶点属性。
你不能用BoneCloth做到这一点。
这可以通过将绘画模式更改为[纹理~]来利用,如下所示:

img

纹理固定(RD) 移动(GR) 忽略(BK)此模式将红色分配给固定属性,将绿色分配给移动属性。 不能指定移动限制。
纹理固定(RD) 移动(GR) 限制(BL) 忽略(BK)这是一种将移动限制添加到顶部蓝色的模式。

例如,考虑以下字符和纹理:

img

img

准备具有此角色裙子部分的顶点属性的纹理。

img

设置此纹理将完成顶点属性的添加。

img

纹理格式

请注意,此纹理有一些格式限制。

  1. 必须打开纹理导入程序的读/写检查。
  2. 准备尽可能小的质地。
    最好不超过64×64,大 - 高达128×128。
    这是因为读取纹理需要大量的CPU成本。
  3. 它也可用于压缩纹理。
  4. 如果大小为 256 或更大并且设置了 mipmap,则其中使用的 mipmap 不超过 128×128 个 mipmap
使用渲染网格

绘画贴图与 MeshCloth 的源渲染器一对一对应。
这意味着每个渲染器都需要一个绘制贴图。
此外,不支持子网格。
这意味着它不适用于在单个渲染器中使用两个或多个纹理的网格。

逆止器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目录 [隐藏]

起先

逆止器是一种碰撞检测,它限制相对于顶点法线方向可以穿透的距离。
通过使用它,您可以轻松防止刘海侵入您的头部。
它还可以防止T恤进入人体。
它是一种机理简单,处理负荷低的系统,可以强烈防止侵入人体。

逆止器由“移动限制”面板设置。

img

在本指南中,我们将首先解释逆止器的原理,然后我们将根据两个示例来解释如何使用它:刘海和裙子。

建设

逆止器的原理很简单。
限制代理网格的每个顶点相对于法线方向可以移动的范围。

img

img

上图显示了配置属性及其限制。
代理网格体的顶点和法线显示动画姿势或原点,而不是当前移动位置。
首先,顶点只能在围绕原点的最大距离半径为球体内移动。
这是第一个限制。

接下来,折点只能移动到“逆挡辐射”球体之外,其“逆挡半径”半径是“逆挡半径”距离与原点法线相反的方向相距。
这是第二个限制。

这两个限制允许折点仅在最大距离内和逆止碰撞之外移动。
您可以同时或仅一侧使用此限制。

刘海镶嵌示例

现在,让我们以刘海为例。
使用逆止器进行设置,使刘海不会侵入您的头部。

img

刘海预先设置有骨布以摇摆。

检查法线方向

首先,让我们检查当前代理网格的正常方向是什么。
通过将“辅助图标”面板的轴设置为“正常”来显示此信息。

img

绿线是正常方向。
顶点球体被隐藏以提高可见性。

img

BoneCloth 只是简单地使用变换 Y 轴,所以这个模型的方向很混乱。
在此状态下,逆止器不可用。

调整法线方向

让我们调整法线方向。
理想情况下,所有法线都应该指向头部之外。
在“法线轴”和“法线对齐”属性中进行调整。

img

将“法线对齐方式”设置为“变换”。

img

然后在头部中央注册转换。
如果头部中央没有变换,则可能需要创建新的游戏对象并注册它。

img

在变换模式下,法线从指定变换的坐标呈径向变化。
此更改是对代理网格进行的,不会影响原始 Transfrom 或 Mesh。
结果:

img

法线都指向头部并准备设置支持。

逆止器设置

剩下的就是设置你可以穿透的距离。
这次我做了以下工作:

img

曲线用于允许从起点到终点的约0厘米至5厘米的穿透。
这次我没有使用最大距离。
刚度是排斥力的强度。
降低该值将使顶点返回得更柔和一些。

完成

动手吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

*字符左右移动。
我能够在不使用对撞机的情况下防止头发进入我的头部。

裙子设置示例

在这里,我们将以裙子为例解释高级逆止器设置。
逆止器主要防止顶点进入人体。
然而,人体不断活跃,姿势以各种方式变化。
这使得它不像前面提到的刘海那么简单。

动画姿势的重要性

这就是动画姿势的用武之地。
这是变换或网格体在不使用 MagicaCloth 的情况下转换为动画的姿势。

例如,以下角色的裙子紧贴着左右腿。
所以裙子跟着腿和动画。
这是理想的,在这种情况下,您可以设置逆止器。

img

但是下一个角色裙子没有皮肤贴腿。
因此,在制作动画时,腿会穿过裙子。
不能在此状态下设置逆止器。

img

逆止器对动画姿势施加限制。
因此,在以下情况下,逆止器无法正常工作。
为了使逆止器正常工作,变换或网格体必须跟随动画。

调整动画姿势

解决上述问题的最佳方法是设置蒙皮权重,使网格跟随腿部。
或者在裙子上添加骨骼,并对每个动作(如奔跑、跳跃和攻击)的骨骼进行动画控制,以执行一些姿势控制。
这通常由艺术家使用外部工具(如Blender)完成。

在这位艺术家创建的动画姿势之上叠加交叉模拟的方法是防止侵入人体的最可靠方法。
建议使用此方法。

如果此方法不可行,则可以使用下面描述的自定义外观功能作为替代方法。

检查动画姿势

动画姿势的当前状态可以通过小控件显示。
您可以通过打开动画姿势检查来检查它,如下所示。

img

例如,样品中包含的UnityChanKAGURA裙子没有蒙皮贴腿。
您可以使用小控件确认这一点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用自定义外观

如果由于某种原因艺术家无法修复它,另一种方法是使用自定义皮肤。
此功能可自动为指定骨骼的代理网格蒙皮。
如果动画姿势已正确设置,则不需要。

img

打开“自定义外观”面板,并在“骨骼蒙皮”中注册外观所需的骨骼。
对于神乐裙子,我记录了从胸部到双腿的骨头如下。

img

这个配准骨可以通过带有黄线的小玩意来识别。

img

让我们在此状态下运行它。
自定义蒙皮现在允许代理网格跟随腿。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这将允许支持工作。
定制皮肤也可以在BoneCloth上使用。

但是,请记住,自定义外观只是一个替代功能。
因此,它不是很准确。

绘制有效顶点

逆止器可以设置为在每个顶点起作用。
这是通过从面板中的蓝色笔标记启动顶点绘制来完成的。

img

例如,如果您不希望逆止器适用于网格的特定部分,则可以使用此功能。

img

设置逆止器

此时,您所要做的就是设置逆止器,如 bangs 示例所示。
这一次,我们将使用神乐裙子的定制皮肤套装来做到这一点。
为了使效果更易于理解,禁止入侵距离已设置为0厘米。

img

完成

动手吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个仅逆止器控件,不使用任何碰撞器碰撞。
您可以看到,逆止器限制了腿的移动,从而阻止了顶点进入腿部。
还要注意,顶点不会侵犯腰部区域。

通过在此状态下添加和加固对撞机,您可以控制裙子,使其无论移动多用力都不会穿透腿部。

动画姿势比例

这个项目与逆止器没有直接关系,但它对控制晃动很重要,所以我会解释一下。

到目前为止,我们已经解释了动画姿势。
MagicaCloth在内部保留了初始姿势和动画姿势。
逆止器始终根据动画姿势计算。

但是,某些限制允许您指定恢复是基于初始姿势还是动画姿势。
这是动画姿势比。
这是通过“基本”面板中的“动画姿势比例”完成的。

img

此值越接近 1.0,根据动画姿势计算的恢复就越多。
初始值为 0.0,恢复是从初始姿势计算的。
换句话说,就是初始姿势还是当前动画姿势是还原目标的比率。

如果比率为 0.0,则生成弹性力以返回到初始状态。
如果比率为 1.0,则将生成复原能力以返回到当前动画状态。
如果比例为 0.5,则两种姿势以 1:1 的比例混合。

影响约束

此动画姿势比影响了三个约束。

  1. 角度修复
  2. 角度限制
  3. 形状修复
设置指征

基本上,将其保留在 0.0 没有问题。
这是因为在大多数情况下,十字架的运动更稳定。

但是,如果动画姿势变形很大,增加比例可能会更稳定。
此外,如果动画姿势完全由艺术家控制,则增加值会更稳定。
在这种情况下,请尝试在从大约 0.5 的设置观察运动的同时进行调整。

自碰撞设置

img

目录 [隐藏]

自碰撞与相互碰撞

本节介绍两种碰撞检测功能:自碰撞和相互碰撞。
两者相似,但用途不同。

什么是自碰撞?

自碰撞是十字架与自身碰撞的特征。
通过使用此功能,即使布本身重叠,也不会穿透。

img

什么是相互碰撞?

相互碰撞是一个十字架与另一个十字架碰撞的能力。
通过使用此功能,可以与单独设置的十字碰撞。

img

使用说明

这两个碰撞功能功能很强大,但有一些注意事项。
我们将继续调查和改进这些问题。

试用版

自碰撞功能目前处于测试阶段。
因此,将来很有可能功能会发生变化。

处理负载

自碰撞是一个非常昂贵的过程。
因此,建议在台式PC或高端控制台上使用它。
此负载与代理网格中的顶点数完全成正比。
因此,如果您在移动设备上使用它,请尽可能减少代理网格的顶点数。

精度问题

目前的自碰撞并不那么准确。
因此,如果高速移动,织物可能会缠结。
但是,还有一个内置机制来检测和解开纠缠。

振动问题

目前,自碰撞已被证实存在容易引起振动的问题。
这主要是由于代理网格的结构。
因此,根据网格的形状,可能难以应用。

自碰撞设置

自碰撞是从自碰撞面板配置的。
与以前的约束相比,设置要简单得多。

img

自碰撞仅使用两个属性:“自碰撞”和“曲面厚度”。

自我模式

目前,只能配置全网状网络。
全网格对其点-三角形和边-边组合执行碰撞检测。
如果三角形不存在,则只有边边将运行。

该模式将来可能会扩展。

表面厚度

碰撞的厚度。
基本单位是(m)。
自碰撞不使用用于碰撞体碰撞检测的顶点半径。
只有使用此厚度才能解决自碰撞。

请注意,厚度是碰撞组合的两个值的总和。
换句话说,即使厚度为0.005(m),实际分离厚度为0.01(m)。
还要注意的是,这个厚度是相互碰撞和共享的。

厚度越大,碰撞检测越可靠。
但是,如果太大,顶点可能会发生振动。

相互碰撞设置

相互碰撞也可以从“自碰撞”面板设置。
相互碰撞的设置有点复杂。

img

相互碰撞使用同步模式、表面厚度和布料质量。

同步模式

与自碰撞一样,此处只能设置全网格。
全网格为对手执行点三角形和边缘碰撞检测。

如果将模式更改为全网格,则可以将碰撞伙伴的一个交叉组件设置为同步伙伴。
了解此合作伙伴。

首先,假设有两个十字架,白色和绿色,如下所示。
两者作为交叉组件是独立的。

img

img

在相互碰撞中,仅在这两条边中的一侧设置相互碰撞。
您无需同时为两者设置它。

在这里,我们将白色十字设置为与绿色十字相互碰撞。
绿色十字设置应如下所示:

img

您不需要为白色交叉设置同步模式和同步伙伴。

这样,一个十字中只能设置一个相互碰撞。
因此,如果要对一个十字执行多个相互碰撞,请仔细考虑要设置哪一侧。

表面厚度

碰撞的厚度。
基本单位是(m)。
此设置与自碰撞共享。
有关详细信息,请参阅自碰撞说明。

重要的是将两个值相加并计算。
因此,必须在两侧正确设置厚度。

布料质量

用于相互碰撞的十字架本身的重量。
此值越高,它越重。

如果一块重布和一个轻十字架相互碰撞,较轻的十字架会移动得更多,而较重的十字架不会移动太多。

例如,如果配件和裙子相互碰撞,使裙子侧面更重可以避免配件不必要地向下推裙子的问题。
因此,通常使层的内交叉更重更稳定。

骨布高级设置

目录 [隐藏]

骨布网连接

BoneCloth能够从注册的变换自动构建网格。
通过使用此功能,变换之间的连接变得更强,并且在保持形状和检测碰撞方面也很强。
此外,由于边缘是横向连接的,因此通过将其与边缘碰撞结合使用,可以进一步增强碰撞检测。

img

设置是通过骨布中的[连接模式]进行的。

img

目前,有三种类型的连接方法可用。

img

作为示例,我将解释由10根骨形成的裙子的连接方法的特征,如下所示。

img

自动网格

img

自动连接附近的变换。
但是,根据变换的排列方式,它可能具有不自然的形状。

顺序循环网格

img

根据根骨的顺序横向连接。
因此,根骨骼的注册顺序很重要。
根骨的起点和终点是循环的。

img

顺序非环网格

img

根据根骨的顺序横向连接。
因此,根骨骼的注册顺序很重要。
根骨的起点和终点没有连接。

img

变换插值率

骨布允许您调整每个变换的旋转姿势。

img

这是每个变换最终将自己定位到它连接的父级或子级的插值速率。

根轮换

img

固定变换的旋转调整。
在 0.0 时,它不会从原始位置旋转。
在 1.0 中,它沿子变换的方向旋转。
平均多个孩子。
0.5 介于两者之间。

旋转插值

img

移动变换的旋转调整。
在 0.0 时,它沿父变换的方向旋转。
在 1.0 中,它沿子变换的方向旋转。
平均多个孩子。
0.5 介于两者之间。

终端转换始终沿父级的方向旋转,因为它没有子级。

风设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目录 [隐藏]

总结


通过使用风生成功能,您可以为交叉模拟赋予风并更逼真地描绘它。
这是通过在场景中放置一个指定风生成程度的 MagicaWindZone 组件来控制的。
MagicaCloth组件也可以通过调整“风”面板中的设置来受到风的影响。

示例场景


示例场景可用于风函数。
它们位于以下文件夹中,如果要测试它们,请在渲染管线中选择场景。

img

测试代码是附加到此示例场景中的 WindDemo .cs。
请注意,场景被管线划分的原因只是为了切换绘图材质。
其中包含的示例代码是相同的。

风区设置


要生成风,必须在场景中指定风的范围。
这是使用MagicaWindZone组件完成的。
请注意,Unity 也有一个 WindZone 组件,但它不会影响 MagicaCloth。
如果你想让MagicaCloth变得轻而易举,你需要一个专用的MagicaWindZone组件。

可以从右键单击菜单添加组件,如下所示:

img

img

风区根据[模式]分为几种类型。

img

由于每种模式的设置项目不同,我们接下来将解释这些类型。

全球方向

img

img

它是影响整个场景的定向风。
没有范围。

主要风速(米/秒)
湍流湍流速率
方向角 X风向 X 角(度)
方向角度 Y风向 Y 角(度)
是加法加法风旗
球体方向

img

img

影响球形区域的定向风。

半径半径
主要风速(米/秒)
湍流湍流速率
方向角 X风向 X 角(度)
方向角度 Y风向 Y 角(度)
是加法加法风旗
盒子方向

img

img

影响箱形区域的定向风。

箱体尺寸范围 XYZ 大小
主要风速(米/秒)
湍流湍流速率
方向角 X风向 X 角(度)
方向角度 Y风向 Y 角(度)
是加法加法风旗
球形径向

img

img

它是一种影响球形区域的放射性风。
辐射风从该地区的中心向外产生。
因此,没有指定方向。
也可以通过[衰减]指定从中心向外的风阻尼曲线。

半径范围半径
主要风速(米/秒)
湍流湍流速率
衰减阻尼曲线
是加法加法风旗
风区优先

如果多个风区与一个交叉组件重叠,则只会启用一个体积最小的风力区域。
但是,只有全局方向区域被视为优先级最低的体积∞。
如果 IsAdd 标志处于打开状态,则排除此优先级,如下所述。

Is添加标志

如果 IsAdd 标志设置为开,则风区将被视为累加区域。
添加剂类型忽略了风区的优先处理,并允许多个同时影响。
在这种情况下,将添加风而不是切换。
但是,对单个交叉分量施加的附加风不得超过三个。

魔术布设置


还可以为每个交叉分量调整风效果。
为此,请使用“风”面板。

img

影响整体风的影响率。 通过降低它,可以减少整体接收的风。 该值也可以设置为 1.0 (100%) 或更高。
频率摇晃的循环。 您可以调整晃动波形的速度。 该值也可以设置为 1.0 (100%) 或更高。
湍流湍流率。 您可以调整晃动干扰的大小。 该值也可以设置为 1.0 (100%) 或更高。
噪音混合波形的混合速率。 您可以调整正弦和噪声波形的混合速率。 罪恶和噪音波将在下面讨论。
同步同步速率。 您可以调整交叉移动中每个基线的同步方式。 如果将其设置为 1.0,它将以相同的方式移动,如果将其设置为 0.0,它将单独移动。
深度重量深度冲击。 通过增加该值,起点附近的顶点不会受到风的影响。 这对于稳定裙子、刘海等很有用。
移动的风移动的风效果。 可以为十字架的运动自动生成风。 值越高,运动过程中的风效应越强。
罪恶和噪音波

风波动有两种波形:正弦波形和噪声波形。
SIN波形具有恒定的周期日本,可以创建像动漫中的场景一样的运动。
但是,权衡不再是随机性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

噪声波形具有不规则的周期,使它们更加自然和逼真。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这两个波形可以与[噪声混合]混合。

移动的风

通过增加移动风参数,您可以在角色移动时自动生成风。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

运动风的风力受惯性参数的影响。
换句话说,如果运动影响被惯性参数抑制,运动风的影响也会相应减小。

校准提示


  • 风区的风速可以设置为30 m/s,但请注意,在检测到碰撞时,过强的风力可能会导致隧道问题。
  • 如果要减少某些交叉分量的风效果,请尝试调整“影响”。
  • 如果您不想用裙子过多地摇摆腰部,请尝试提高深度重量。
  • 如果要将头发抖开,请尝试降低同步。
  • 如果要调整抖动的随机性,请尝试调整除 NoiseBlend 之外的各种同步。
  • 移动风受惯性参数约简的影响
  • 对于冲击波,在球体径向上打开 IsAdd 标志并在一段时间内生成它是有效的。

在运行时构建

目录 [隐藏]

总结


MagicaCloth 2完全支持运行构建。
本节介绍如何在脚本运行时从脚本构建 MagicaCloth 组件。
假定读者了解 Unity 中的 C# 编程。

示例场景


示例场景可用于运行时构造。
它们位于以下文件夹中,如果要测试它们,请从渲染管线中选择一个场景。

img

测试代码是附加到此示例场景中的 RuntimeBuildDemo .cs。
本页还介绍了此测试代码摘录的内容。

请注意,场景分开的原因只是为了切换绘图材料。
其中包含的示例代码是相同的。

构建过程


若要生成,请执行以下步骤:

  1. 生成魔法布组件
  2. 设置参数
  3. 开始创建和运行跨数据

我将根据示例来解释这些。
构建时还需要记住一些事项。

顶点绘制设置

在编辑器的预构建中,我们使用顶点绘制功能手动设置每个顶点的属性。
但是,此方法在运行时不可用。
因此,在运行时的 MeshCloth 中,将准备单独的绘制贴图并添加属性。
绘制贴图在网格布中是强制性的。
有关详细信息,请参阅使用纹理绘制顶点页面

开始执行延迟

在MagicaCloth2中,交叉数据是在运行时构建的。
此构造是在单独的线程上完成的,因此对主线程几乎没有影响。
但是构建需要一些时间帧。

因此,在构建组件和实际开始交叉仿真之间存在几帧的延迟。


以下是一些构造示例。
该示例摘自示例场景的 RuntimeBuildDemo .cs,因此也请参考演示场景。
有关使用的 API,请参阅脚本 API 页面。

代码中编写的角色是角色的游戏对象。
gameObjectContainer 是一个简单的类,允许您从角色的名称中获取角色的游戏对象。

骨布构造示例 (1)
/// <summary>
/// BoneCloth construction example (1).
/// Set all parameters from a script.
/// </summary>
void SetupHairTail_BoneCloth()
{
  if (character == null)
    return;

  var obj = new GameObject("HairTail_BoneCloth");
  obj.transform.SetParent(character.transform, false);

  // add Magica Cloth
  var cloth = obj.AddComponent<MagicaCloth>();
  var sdata = cloth.SerializeData;

  // bone cloth
  sdata.clothType = ClothProcess.ClothType.BoneCloth;
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairTail_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairTail_00_B").transform);

  // setup parameters
  sdata.gravity = 3.0f;
  sdata.damping.SetValue(0.05f);
  sdata.angleRestorationConstraint.stiffness.SetValue(0.15f, 1.0f, 0.15f, true);
  sdata.angleRestorationConstraint.velocityAttenuation = 0.6f;
  sdata.tetherConstraint.distanceCompression = 0.5f;
  sdata.inertiaConstraint.particleSpeedLimit.SetValue(true, 3.0f);
  sdata.colliderCollisionConstraint.mode = ColliderCollisionConstraint.Mode.None;

  // start build
  cloth.BuildAndRun();
}

此示例创建一个 BoneCloth 并设置脚本中的所有参数。
重要的是 SerializeData 类。
可以从脚本操作的所有参数都包含在此 SerializeData 类中。
因此,我们将通过重写此类来设置它。

最后运行 BuildAndRun()。
这将开始在线程上创建交叉数据,模拟将在完成后自动启动。

骨布构造示例 (2)
/// <summary>
/// BoneCloth construction example (2).
/// Copy parameters from an existing component.
/// </summary>
void SetupFrontHair_BoneCloth()
{
  if (character == null || frontHairSource == null)
    return;

  var obj = new GameObject("HairFront_BoneCloth");
  obj.transform.SetParent(character.transform, false);

  // add Magica Cloth
  var cloth = obj.AddComponent<MagicaCloth>();
  var sdata = cloth.SerializeData;

  // bone cloth
  sdata.clothType = ClothProcess.ClothType.BoneCloth;
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairFront_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairSide2_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairSide_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairFront_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairSide2_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairSide_00_B").transform);

  // Normal direction setting for backstop
  sdata.normalAlignmentSetting.alignmentMode = NormalAlignmentSettings.AlignmentMode.Transform;
  sdata.normalAlignmentSetting.adjustmentTransform = gameObjectContainer.GetGameObject("HeadCenter").transform;

  // setup parameters
  // Copy from source settings
  sdata.Import(frontHairSource, false);

  // start build
  cloth.BuildAndRun();
}

在此示例中,参数是从另一个外部交叉组件 frontHairSource 导入的。
这简化了参数配置。

但是,有些参数可以导入,有些则不能。
这在源代码中作为注释提到。

/// [OK] Runtime changes.
/// [NG] Export/Import with Presets

在此示例中,正常对齐设置是手动设置的,因为它无法导入。

骨布构造示例 (3)
/// <summary>
/// BoneCloth construction example (3).
/// Load parameters from saved presets.
/// </summary>
void SetupRibbon_BoneCloth()
{
  if (character == null || string.IsNullOrEmpty(ribbonPresetName))
    return;

  var obj = new GameObject("Ribbon_BoneCloth");
  obj.transform.SetParent(character.transform, false);

  // add Magica Cloth
  var cloth = obj.AddComponent<MagicaCloth>();
  var sdata = cloth.SerializeData;

  // bone cloth
  sdata.clothType = ClothProcess.ClothType.BoneCloth;
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HeadRibbon_00_B").transform);
  sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HeadRibbon_00_B").transform);

  // setup parameters
  // Load presets from the Resource folder.
  // Since presets are in TextAssets format, they can also be used as asset bundles.
  var presetText = Resources.Load<TextAsset>(ribbonPresetName);
  sdata.ImportJson(presetText.text);

  // start build
  cloth.BuildAndRun();
}

在此示例中,参数作为预设文件 (Json) 导入。
参数可以以 JSON 格式从外部导出。
由于这是一个简单的文本文件,因此可以通过将其作为资源文件夹或资产包在运行时读取。

网布施工实例 (1)
/// <summary>
/// MeshCloth construction example (1).
/// Reads vertex attributes from a paintmap.
/// </summary>
void SetupSkirt_MeshCloth()
{
  if (character == null || skirtPaintMap == null)
    return;

  // skirt renderer
  var sobj = gameObjectContainer.GetGameObject(skirtName);
  if (sobj == null)
    return;
  Renderer skirtRenderer = sobj.GetComponent<Renderer>();
  if (skirtRenderer == null)
    return;

  // add Magica Cloth
  var obj = new GameObject("Skirt_MeshCloth");
  obj.transform.SetParent(character.transform, false);
  var cloth = obj.AddComponent<MagicaCloth>();
  var sdata = cloth.SerializeData;

  // mesh cloth
  sdata.clothType = ClothProcess.ClothType.MeshCloth;
  sdata.sourceRenderers.Add(skirtRenderer);

  // reduction settings
  sdata.reductionSetting.simpleDistance = 0.0212f;
  sdata.reductionSetting.shapeDistance = 0.0244f;

  // paint map settings
  // *** Paintmaps must have Read/Write attributes enabled! ***
  sdata.paintMode = ClothSerializeData.PaintMode.Texture_Fixed_Move;
  sdata.paintMaps.Add(skirtPaintMap);

  // setup parameters
  sdata.gravity = 1.0f;
  sdata.damping.SetValue(0.03f);
  sdata.angleRestorationConstraint.stiffness.SetValue(0.05f, 1.0f, 0.5f, true);
  sdata.angleRestorationConstraint.velocityAttenuation = 0.5f;
  sdata.angleLimitConstraint.useAngleLimit = true;
  sdata.angleLimitConstraint.limitAngle.SetValue(45.0f, 0.0f, 1.0f, true);
  sdata.distanceConstraint.stiffness.SetValue(0.5f, 1.0f, 0.5f, true);
  sdata.tetherConstraint.distanceCompression = 0.9f;
  sdata.inertiaConstraint.depthInertia = 0.7f;
  sdata.inertiaConstraint.movementSpeedLimit.SetValue(true, 3.0f);
  sdata.inertiaConstraint.particleSpeedLimit.SetValue(true, 3.0f);
  sdata.colliderCollisionConstraint.mode = ColliderCollisionConstraint.Mode.Point;

  // setup collider
  var lobj = new GameObject("CapsuleCollider_L");
  lobj.transform.SetParent(gameObjectContainer.GetGameObject("Character1_LeftUpLeg").transform);
  lobj.transform.localPosition = new Vector3(0.0049f, 0.0f, -0.0832f);
  lobj.transform.localEulerAngles = new Vector3(0.23f, 16.376f, -0.028f);
  var colliderL = lobj.AddComponent<MagicaCapsuleCollider>();
  colliderL.direction = MagicaCapsuleCollider.Direction.Z;
  colliderL.SetSize(0.082f, 0.094f, 0.3f);

  var robj = new GameObject("CapsuleCollider_R");
  robj.transform.SetParent(gameObjectContainer.GetGameObject("Character1_RightUpLeg").transform);
  robj.transform.localPosition = new Vector3(-0.0049f, 0.0f, -0.0832f);
  robj.transform.localEulerAngles = new Vector3(0.23f, -16.376f, -0.028f);
  var colliderR = robj.AddComponent<MagicaCapsuleCollider>();
  colliderR.direction = MagicaCapsuleCollider.Direction.Z;
  colliderR.SetSize(0.082f, 0.094f, 0.3f);

  sdata.colliderCollisionConstraint.colliderList.Add(colliderL);
  sdata.colliderCollisionConstraint.colliderList.Add(colliderR);

  // start build
  cloth.BuildAndRun();
}

在此示例中,我们构建一个 MeshCloth 并通过绘制图添加顶点属性。
请注意,绘制贴图与您设置的渲染器同步。
这意味着渲染器的数量和绘制地图的数量必须相同。

我们还创建了两个胶囊对撞机,并将它们添加到对撞机列表中。
创建碰撞体与创建典型的 Unity 组件相同。

除此之外,它与BoneCloth示例相同。

结束。

运行时更改

目录 [隐藏]

总结


MagicaCloth2 支持在执行期间更改参数。
本节介绍如何在执行期间操作脚本中的参数。
假定读者了解 Unity 中的 C# 编程。

变更程序


若要进行更改,请按照下列步骤操作:

  1. 获取 MagicaCloth 组件的 SerializeData 类
  2. 更改序列化数据的内容
  3. 调用 MagicaCloth 组件的 SetParameterChange()

MagicaCloth 的所有可修改参数都包含在此 SerializeData 类中。
直接重写此类。

但是,并非所有参数都可以更改。
是否可以更改该参数在源代码的注释中描述。

/// [OK] Runtime changes.
/// [NG] Export/Import with Presets

最后,通过调用 SetParameterChange() 通知系统更改。
有关使用的 API,请参阅脚本 API 页面。


更改参数 (1)
using MagicaCloth2;
using UnityEngine;

public class RuntimeParameterTest : MonoBehaviour
{
  public MagicaCloth cloth;
  public ColliderComponent col;

  bool sw = false;

  void Start()
  {

  }

  void Update()
  {
    if (cloth == null || col == null)
      return;

    // Check if MagicaCloth is running
    if (cloth.IsValid() == false)
      return;

    if (Time.frameCount % 100 == 0)
    {
      sw = !sw;
      UpdateParameter();
    }
  }

  /// <summary>
  /// Parameter change.
  /// </summary>
  void UpdateParameter()
  {
    // It manages all parameters that cloth.SerializeData can change at runtime.
    var sdata = cloth.SerializeData;
    if (sw)
    {
      // add collider.
      sdata.colliderCollisionConstraint.colliderList.Add(col);

      // gravity on
      sdata.gravity = 5.0f;
    }
    else
    {
      // remove collider
      sdata.colliderCollisionConstraint.colliderList.Remove(col);

      // gravity off
      sdata.gravity = 0.0f;
    }

    // change notification
    cloth.SetParameterChange();
  }
}

在此示例中,碰撞体每 100 帧添加/删除一次。
还要改变重力。

此示例包含所有参数更改。
也可以通过应用此操作来更改其他参数。

装扮过程

目录 [隐藏]

总结


以下是将MagicaCloth移植到另一个角色的方法。
如果您想用不同的头发和服装打扮您的游戏角色,这将非常有用。
假定读者了解 Unity 中的 C# 编程。

示例场景


示例场景可用于装扮过程。
它们位于以下文件夹中,如果要测试它们,请从渲染管线中选择一个场景。

img

测试代码是附加到此示例场景中的 RuntimeDressUpDemo .cs。
本页还根据此测试代码的内容进行了说明。

请注意,场景分开的原因只是为了切换绘图材料。
其中包含的示例代码是相同的。

示例数据


本节介绍示例场景中的数据。

Utc_sum_humanoid(骨架)

首先,有Utc_sum_humanoid(骷髅),这是一个只有骷髅的角色。

img

这个角色是一个只有变形的骷髅角色,没有头发、衣服或魔法布。

img

您将向此Utc_sum_humanoid(骨架)添加头发和衣服。

Utc_sum_humanoid(头发)

这是一个预制件,带有头发渲染器和MagicaCloth设置为骨骼角色。

img

此预制件包含所有框架。
(实际上只有你需要的游戏对象才好)

img

Utc_sum_humanoid(正文)

这是一个预制件,带有衣服渲染器和MagicaCloth设置为骨骼角色。

img

此预制件包含所有框架。
(实际上只有你需要的游戏对象才好)

img

装扮程序


要装扮,请按照以下步骤操作:

  1. 生成用于装扮的预制件
  2. 阻止魔法布自动构建
  3. 将渲染器移植到骨架头像
  4. 将魔法布移植到骷髅头像
  5. 将碰撞体和其他物体移植到骨骼化身
  6. 开始运行魔术布

(3)中渲染器的移植与MagicaCloth系统无关。
因此,您可以使用其他程序或资产。

取消程序


要脱衣服,请按照以下步骤操作:

  1. 销毁() 渲染器
  2. 破坏() 魔法布
  3. 销毁() 不需要的碰撞体
  4. 销毁() 一个不必要的游戏对象

基本上,你所要做的就是摧毁()任何你不需要的游戏对象,包括MagicaCloth。
关于 (1),您可以使用装扮程序中的其他程序或资产。


在这里,我们将解释示例场景的 RuntimeDressUpDemo .cs。
如果根据上述整理和发布程序查看代码,您应该能够掌握大致内容。

// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;

namespace MagicaCloth2
{
  /// <summary>
  /// Dress-up sample.
  /// </summary>
  public class RuntimeDressUpDemo : MonoBehaviour
  {
    /// <summary>
    /// Avatar to change clothes.
    /// </summary>
    public GameObject targetAvatar;

    /// <summary>
    /// Hair prefab with MagicaCloth set in advance.
    /// </summary>
    public GameObject hariEqupPrefab;

    /// <summary>
    /// Clothes prefab with MagicaCloth set in advance.
    /// </summary>
    public GameObject bodyEquipPrefab;

    //=========================================================================================
    /// <summary>
    /// Bones dictionary of avatars to dress up.
    /// </summary>
    Dictionary<string, Transform> targetAvatarBoneMap = new Dictionary<string, Transform>();

    /// <summary>
    /// Information class for canceling dress-up.
    /// </summary>
    class EquipInfo
    {
      public GameObject equipObject;
      public List<ColliderComponent> colliderList;

      public bool IsValid() => equipObject != null;
    }
    EquipInfo hairEquipInfo = new EquipInfo();
    EquipInfo bodyEquipInfo = new EquipInfo();

    //=========================================================================================
    private void Awake()
    {
      Init();
    }

    void Start()
    {
    }

    void Update()
    {
    }

    //=========================================================================================
    public void OnHairEquipButton()
    {
      if (hairEquipInfo.IsValid())
        Remove(hairEquipInfo);
      else
        Equip(hariEqupPrefab, hairEquipInfo);
    }

    public void OnBodyEquipButton()
    {
      if (bodyEquipInfo.IsValid())
        Remove(bodyEquipInfo);
      else
        Equip(bodyEquipPrefab, bodyEquipInfo);
    }

    //=========================================================================================
    /// <summary>
    /// Create an avatar bone dictionary in advance.
    /// </summary>
    void Init()
    {
      Debug.Assert(targetAvatar);

      // Create all bone maps for the target avatar
      foreach (Transform bone in targetAvatar.GetComponentsInChildren<Transform>())
      {
        if (targetAvatarBoneMap.ContainsKey(bone.name) == false)
        {
          targetAvatarBoneMap.Add(bone.name, bone);
        }
        else
        {
          Debug.Log($"Duplicate bone name :{bone.name}");
        }
      }
    }

    /// <summary>
    /// Equip clothes.
    /// </summary>
    /// <param name="equipPrefab"></param>
    /// <param name="einfo"></param>
    void Equip(GameObject equipPrefab, EquipInfo einfo)
    {
      Debug.Assert(equipPrefab);

      // Generate a prefab with cloth set up.
      var gobj = Instantiate(equipPrefab, targetAvatar.transform);

      // All cloth components included in the prefab.
      var clothList = new List<MagicaCloth>(gobj.GetComponentsInChildren<MagicaCloth>());

      // All collider components included in the prefab.
      var colliderList = new List<ColliderComponent>(gobj.GetComponentsInChildren<ColliderComponent>());

      // All renderers included in the prefab.
      var skinList = new List<SkinnedMeshRenderer>(gobj.GetComponentsInChildren<SkinnedMeshRenderer>());

      // First stop the automatic build that is executed with Start().
      // And just in case, it does some initialization called Awake().
      foreach (var cloth in clothList)
      {
        // Normally it is called with Awake(), but if the component is disabled, it will not be executed, so call it manually.
        // Ignored if already run with Awake().
        cloth.Initialize();

        // Turn off auto-build on Start().
        cloth.DisableAutoBuild();
      }

      // Swap the bones of the SkinnedMeshRenderer.
      // This process is a general dress-up process for SkinnedMeshRenderer.
      // Comment out this series of processes when performing this process with functions such as other assets.
      foreach (var sren in skinList)
      {
        var bones = sren.bones;
        Transform[] newBones = new Transform[bones.Length];

        for (int i = 0; i < bones.Length; ++i)
        {
          Transform bone = bones[i];
          if (!targetAvatarBoneMap.TryGetValue(bone.name, out newBones[i]))
          {
            // Is the bone the renderer itself?
            if (bone.name == sren.name)
            {
              newBones[i] = sren.transform;
            }
            else
            {
              // bone not found
              Debug.Log($"[SkinnedMeshRenderer({sren.name})] Unable to map bone [{bone.name}] to target skeleton.");
            }
          }
        }
        sren.bones = newBones;

        // root bone
        if (targetAvatarBoneMap.ContainsKey(sren.rootBone?.name))
        {
          sren.rootBone = targetAvatarBoneMap[sren.rootBone.name];
        }
      }

      // Here, replace the bones used by the MagicaCloth component.
      foreach (var cloth in clothList)
      {
        // Replaces a component's transform.
        cloth.ReplaceTransform(targetAvatarBoneMap);
      }

      // Move all colliders to the new avatar.
      foreach (var collider in colliderList)
      {
        Transform parent = collider.transform.parent;
        if (parent && targetAvatarBoneMap.ContainsKey(parent.name))
        {
          Transform newParent = targetAvatarBoneMap[parent.name];

          // After changing the parent, you need to write back the local posture and align it.
          var localPosition = collider.transform.localPosition;
          var localRotation = collider.transform.localRotation;
          collider.transform.SetParent(newParent);
          collider.transform.localPosition = localPosition;
          collider.transform.localRotation = localRotation;
        }
      }

      // Finally let's start building the cloth component.
      foreach (var cloth in clothList)
      {
        // I disabled the automatic build, so I build it manually.
        cloth.BuildAndRun();
      }

      // Record information for release.
      einfo.equipObject = gobj;
      einfo.colliderList = colliderList;
    }

    /// <summary>
    /// Removes equipped clothing.
    /// </summary>
    /// <param name="einfo"></param>
    void Remove(EquipInfo einfo)
    {
      Destroy(einfo.equipObject);
      foreach (var c in einfo.colliderList)
      {
        Destroy(c.gameObject);
      }

      einfo.equipObject = null;
      einfo.colliderList.Clear();
    }
  }
}
创建转换字典

首先,为骨骼头像创建转换字典。
这是按名称键入的字典。
使用此字典进行骨置换。

/// <summary>
/// Bones dictionary of avatars to dress up.
/// </summary>
Dictionary<string, Transform> targetAvatarBoneMap = new Dictionary<string, Transform>();

/// <summary>
/// Create an avatar bone dictionary in advance.
/// </summary>
void Init()
{
  Debug.Assert(targetAvatar);

  // Create all bone maps for the target avatar
  foreach (Transform bone in targetAvatar.GetComponentsInChildren<Transform>())
  {
    if (targetAvatarBoneMap.ContainsKey(bone.name) == false)
    {
      targetAvatarBoneMap.Add(bone.name, bone);
    }
    else
    {
      Debug.Log($"Duplicate bone name :{bone.name}");
    }
  }
}
停止自动构建魔法布

MagicaCloth 组件将自动开始使用 Start() 构建和执行交叉,因此它将停止此功能。
此外,如果组件是禁用的,则可能不会调用 Awake(),因此请初始化它以防万一。

// First stop the automatic build that is executed with Start().
// And just in case, it does some initialization called Awake().
foreach (var cloth in clothList)
{
  // Normally it is called with Awake(), but if the component is disabled, it will not be executed, so call it manually.
  // Ignored if already run with Awake().
  cloth.Initialize();

  // Turn off auto-build on Start().
  cloth.DisableAutoBuild();
}
移植皮肤网格渲染器

将渲染器移植到MagicaCloth之前的骨骼头像。
这是通过将 SkinnedMeshRenderer 的骨骼替换为骨骼化身的骨骼来完成的。

// Swap the bones of the SkinnedMeshRenderer.
// This process is a general dress-up process for SkinnedMeshRenderer.
// Comment out this series of processes when performing this process with functions such as other assets.
foreach (var sren in skinList)
{
  var bones = sren.bones;
  Transform[] newBones = new Transform[bones.Length];

  for (int i = 0; i < bones.Length; ++i)
  {
    Transform bone = bones[i];
    if (!targetAvatarBoneMap.TryGetValue(bone.name, out newBones[i]))
    {
      // Is the bone the renderer itself?
      if (bone.name == sren.name)
      {
        newBones[i] = sren.transform;
      }
      else
      {
        // bone not found
        Debug.Log($"[SkinnedMeshRenderer({sren.name})] Unable to map bone [{bone.name}] to target skeleton.");
      }
    }
  }
  sren.bones = newBones;

  // root bone
  if (targetAvatarBoneMap.ContainsKey(sren.rootBone?.name))
  {
    sren.rootBone = targetAvatarBoneMap[sren.rootBone.name];
  }
}

请注意,此过程与MagicaCloth无关。
换句话说,这部分可以由用户处理或使用其他装扮资产。

移植魔术布组件

将魔法布移植到你的骨骼头像上。
这是通过像SkinnedMeshRenderer一样替换内部骨骼来完成的。
替换是通过传递预先创建的转换字典来完成的。

// Here, replace the bones used by the MagicaCloth component.
foreach (var cloth in clothList)
{
  // Replaces a component's transform.
  cloth.ReplaceTransform(targetAvatarBoneMap);
}
移植碰撞体

如果您正在使用MagicaCloth的碰撞体,请将其移植到您的骨骼头像中。

// Move all colliders to the new avatar.
foreach (var collider in colliderList)
{
  Transform parent = collider.transform.parent;
  if (parent && targetAvatarBoneMap.ContainsKey(parent.name))
  {
    Transform newParent = targetAvatarBoneMap[parent.name];

    // After changing the parent, you need to write back the local posture and align it.
    var localPosition = collider.transform.localPosition;
    var localRotation = collider.transform.localRotation;
    collider.transform.SetParent(newParent);
    collider.transform.localPosition = localPosition;
    collider.transform.localRotation = localRotation;
  }
}
开始运行魔术布

最后开始构建和运行MagicaCloth。

// Finally let's start building the cloth component.
foreach (var cloth in clothList)
{
  // I disabled the automatic build, so I build it manually.
  cloth.BuildAndRun();
}
解除

如果您不再需要打扮,请按如下方式取消它。
这只是销毁()所有不再需要的游戏对象。

/// <summary>
/// Removes equipped clothing.
/// </summary>
/// <param name="einfo"></param>
void Remove(EquipInfo einfo)
{
  Destroy(einfo.equipObject);
  foreach (var c in einfo.colliderList)
  {
    Destroy(c.gameObject);
  }

  einfo.equipObject = null;
  einfo.colliderList.Clear();
}

牢记


请注意,此示例代码并未涵盖所有可能性。
本案例仅供参考。

例如,在这种情况下,不会移植存在于装扮预制件中但不存在于骨架头像中的游戏对象。
它们需要通过添加单独的处理进行移植。

结束。

性能

目录 [隐藏]

起先


本节介绍与性能相关的各个方面。
内容主要针对程序员。

MagicaCloth性能依赖关系


MagicaCloth运行在面向数据的技术堆栈(Unity DOTS)上。
因此,它完全依赖于 CPU。
相反,它根本不使用 GPU。

此外,由于DOTS支持多线程,因此CPU的内核(线程)越多,性能就越好,因为可以并行执行。

但是,在Android / iPhone上使用它时需要小心一点。
移动终端CPU通常由两种配置组成:大核心配置和小型低输出核心配置。
这称为大-小配置。
例如,即使终端具有 8 核 CPU,也几乎总是分配给 Big4/Little4 等。
在这种情况下,它被写为(4-4 个内核)。
Unity 只在 Big Core 上运行 DOTS。
因此,在上述端子的情况下,8 个内核中只有 4 个可以与 DOTS 一起使用。
请记住这一点。

台式电脑 CPU 没有这样的问题。

创建和执行跨数据


MagicaCloth需要各种数据来执行模拟。
这称为交叉数据。
然后,在运行时按需动态生成交叉数据。

由于这种交叉数据创建需要大量的计算处理,因此通常需要大约 20ms~100ms。
此创建过程在后台线程上执行,对主线程几乎没有影响。
此外,多个跨数据由多个线程创建并并行执行。

但是,模拟必须等到此交叉数据完成。
这会导致实际字符生成和模拟开始之间出现几帧的延迟。

运行编辑器时的注意事项


MagicaCloth使用Burst和JobSystem,它们在运行编辑器时比在构建时更昂贵。
因此,请记住,运行编辑器时的探查器与生成编辑器时的性能分析器不同。
这是由于以下因素:

突发 JIT 编译器

只有在编辑器中运行时,突发才是实时编译器。
这是在游戏开始后完成的,因此第一次使用 MagicaCloth 时,编译需要数百毫秒或更长时间。
因此,在编辑器环境中,在播放后第一次模拟开始之前会有相当大的延迟。
此问题仅在编辑器环境中出现,在生成时不会发生。

要变通解决此问题,请使用进入播放模式选项,如下所示:
这可以在玩家设置的编辑器选项卡中找到。

img

通过使用进入播放模式,即使重复执行,也不会再次对突发进行 JIT 编译。

作业调试器加载

在编辑器中,JobsDebugger 始终监视 Jobs 的操作。
这使得作业运行的时间比平时更长,并且作业之间没有不自然的空白时间。
因此,如果您担心负载,请按如下方式关闭作业调试器。

img

安全检查负载

同样,编辑器环境也会监控 Burst 的安全性。
此负载也会按预期发生,因此如果您担心,请关闭以下两项检查。

img

img

请注意,将不再报告错误

但是,请注意,如果您如上所述关闭作业调试器和安全检查,则不会显示突发/作业错误。
因此,如果您觉得MagicaCloth行为异常,请重新打开所有检查以检查是否有任何错误。

最快的构建时间

请注意,由于各种监控,MagicaCloth 在运行编辑器时的性能将低于构建时的性能。

发布版本消除了所有这些疏忽。
因此,最好在实际机器上构建和检查实际性能。

处理负荷清单


在这里,我们将解释MagicaCloth最苛刻的功能。
★ 负载越高。

十字型
网布★★★★MeshCloth比BoneCloth贵得多,因为除了模拟之外,还有代理网格蒙皮和写回来渲染网格。因此,在移动设备上使用时请注意性能。
骨布骨布非常轻巧。 在大多数情况下,即使大量使用也没有问题。
碰撞处理
自碰撞★★★★★★★★★★自碰撞是迄今为止所有功能中最昂贵的。 因此,它基本上旨在用于具有大量CPU内核的台式PC。如果在移动设备上使用它,请尽可能减少代理网格中的顶点数并注意性能。
相互碰撞★★★★★★★★由于相互碰撞只是与对手的碰撞判断,因此负载略低于自碰撞。但是,作为一个过程,它与自碰撞没有什么不同,所以请注意这里的性能。
边缘碰撞★★★★边碰撞比点碰撞昂贵几倍。请仅在存在点冲突问题时才尝试使用它。
点碰撞★★点碰撞比其他碰撞检测便宜得多。
逆止器逆止器要求最低,因为它需要一点计算。 您可以使用它而不必担心负载。

结束。

脚本

MagicaManager

目录 [隐藏]

总结


MagicaManager是唯一存在的MagicaCloth系统类。
MagicaManager的设置会影响整个系统。
可以按如下方式访问管理器:

{
  MagicaManager.SetGlobalTimeScale(magicaGlobalTimeScale);
}

性能


预仿真
/// <summary>
/// シミュレーション開始前イベント
/// Pre-simulation event.
/// </summary>
public static Action OnPreSimulation;
发布模拟
/// <summary>
/// シミュレーション完了後イベント
/// Post-simulation event.
/// </summary>
public static Action OnPostSimulation;

方法


设置全球时间刻度
/// <summary>
/// グローバルタイムスケールを変更します
/// Change the global time scale.
/// </summary>
/// <param name="timeScale">0.0-1.0</param>
public static void SetGlobalTimeScale(float timeScale)
获取全球时间尺度
/// <summary>
/// グローバルタイムスケールを取得します
/// Get the global time scale.
/// </summary>
/// <returns></returns>
public static float GetGlobalTimeScale()

MagicaCloth

目录 [隐藏]

总结

一个重要的单行为类,用于协调所有交叉组件。
通常,您可以将其附加到编辑器环境中的游戏对象,但您可以从脚本构建所有内容。
您还可以在执行期间操作参数以更改其行为。

有关从脚本生成和操作的信息,请参阅运行时脚本页面。

性能


序列化数据
/// <summary>
/// Serialize data (1).
/// Basic parameters.
/// Import/export target.
/// Can be rewritten at runtime.
/// </summary>
[SerializeField]
private ClothSerializeData serializeData = new ClothSerializeData();
public ClothSerializeData SerializeData => serializeData;

保存可在运行时操作的参数。
我主要通过我的脚本使用这个类。
有关详细信息,请参阅布料序列化数据

构建完成
/// <summary>
/// クロスデータ構築完了後イベント
/// Event after completion of cloth data construction.
/// (true = Success, false = Failure)
/// </summary>
public Action<bool> OnBuildComplete;

方法


是有效的
/// <summary>
/// Check if the cloth component is in a valid state.
/// クロスコンポーネントが有効な状態か確認します。
/// </summary>
/// <returns></returns>
public bool IsValid()
初始化
/// <summary>
/// 初期化を実行します
/// すでに初期化済みの場合は何もしません。
/// perform initialization.
/// If already initialized, do nothing.
/// </summary>
public void Initialize()
禁用自动生成
/// <summary>
/// コンポーネントのStart()で実行される自動ビルドを無効にします
/// Disable automatic builds that run on the component's Start().
/// </summary>
public void DisableAutoBuild()
构建和运行
/// <summary>
/// コンポーネントを構築し実行します
/// すべてのデータをセットアップしたあとに呼び出す必要があります
/// build and run the component.
/// Must be called after setting up all data.
/// </summary>
/// <returns>true=start build. false=build failed.</returns>
public bool BuildAndRun()
替换转换
/// <summary>
/// コンポーネントが保持するトランスフォームを置換します。
/// 置換先のトランスフォーム名をキーとした辞書を渡します。
/// Replaces a component's transform.
/// Passes a dictionary keyed by the name of the transform to be replaced.
/// </summary>
/// <param name="targetTransformDict">Dictionary keyed by the name of the transform to be replaced.</param>
public void ReplaceTransform(Dictionary<string, Transform> targetTransformDict)
设置参数更改
/// <summary>
/// パラメータの変更を通知
/// 実行中にパラメータを変更した場合はこの関数を呼ぶ必要があります
/// You should call this function if you changed parameters during execution.
/// </summary>
public void SetParameterChange()
设置时间刻度
/// <summary>
/// タイムスケールを変更します
/// Change the time scale.
/// </summary>
/// <param name="timeScale">0.0-1.0</param>
public void SetTimeScale(float timeScale)
获取时间尺度
/// <summary>
/// タイムスケールを取得します
/// Get the time scale.
/// </summary>
/// <returns></returns>
public float GetTimeScale()
复位布
/// <summary>
/// シミュレーションを初期状態にリセットします
/// Reset the simulation to its initial state.
/// </summary>
public void ResetCloth()
获取中心位置
/// <summary>
/// 慣性の中心座標を取得します
/// Get the center of inertia position.
/// </summary>
/// <returns></returns>
public Vector3 GetCenterPosition()
GetSerializeData2
/// <summary>
/// シリアライズデータ2の取得
/// SerializeData2クラスはシステムが利用するパラメータクラスです。
/// そのためユーザーによる変更は推奨されていません。
///
/// Acquisition of SerializedData2.
/// The SerializeData2 class is a parameter class used by the system.
/// Therefore, user modification is not recommended.
/// </summary>
/// <returns></returns>
public ClothSerializeData2 GetSerializeData2()

ClothSerializeData

目录 [隐藏]

总结


类包含所有参数。
从脚本生成布料组件时,需要操作此类的成员。
还可以在运行时操作此类以更改其参数。
但是,某些参数无法在运行时更改。
此外,此类的成员可以导出和导入为 Json。
这些通常用作预设功能。

是否可以在运行时更改并导出为预设,注释中注明如下:

/// [OK] Runtime changes.
/// [NG] Export/Import with Presets

在运行时更改参数


运行时的参数更改首先操作 ClothSerializeData 类的相应成员。
然后,它调用 SetParameterChange() 来通知系统更改。
此操作对于所有参数都是通用的。

以下示例每 100 帧添加/删除一次碰撞器。

using MagicaCloth2;
using UnityEngine;

public class RuntimeColliderTest : MonoBehaviour
{
  public MagicaCloth cloth;
  public ColliderComponent col;

  bool sw = false;

  void Start()
  {

  }

  void Update()
  {
    if (cloth == null || col == null)
      return;

    // Check if MagicaCloth is running
    if (cloth.IsValid() == false)
      return;

    if (Time.frameCount % 100 == 0)
    {
      sw = !sw;
      UpdateCollider();
    }
  }

  /// <summary>
  /// Add or Remove colliders
  /// </summary>
  void UpdateCollider()
  {
    // It manages all parameters that cloth.SerializeData can change at runtime.
    if (sw)
    {
      // add collider.
      cloth.SerializeData.colliderCollisionConstraint.colliderList.Add(col);
    }
    else
    {
      // remove collider
      cloth.SerializeData.colliderCollisionConstraint.colliderList.Remove(col);
    }

    // change notification
    cloth.SetParameterChange();
  }
}

性能


布料类型
/// <summary>
/// simulation type.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public ClothProcess.ClothType clothType = ClothProcess.ClothType.MeshCloth;
/// <summary>
/// Cloth Type
/// </summary>
public enum ClothType
{
  MeshCloth = 0,
  BoneCloth = 1,
}
源渲染器
/// <summary>
/// Renderer list used in MeshCloth.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public List<Renderer> sourceRenderers = new List<Renderer>();
绘画模式
/// <summary>
/// vertex paint mode.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public PaintMode paintMode = PaintMode.Manual;
public enum PaintMode
{
  Manual = 0,

  [InspectorName("Texture Fixed(RD) Move(GR) Ignore(BK)")]
  Texture_Fixed_Move = 1,

  [InspectorName("Texture Fixed(RD) Move(GR) Limit(BL) Ignore(BK)")]
  Texture_Fixed_Move_Limit = 2,
}
油漆地图
/// <summary>
/// texture for painting.
/// Sync to sourceRenderers.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public List<Texture2D> paintMaps = new List<Texture2D>();
根骨
/// <summary>
/// Root bone list used in BoneCloth.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public List<Transform> rootBones = new List<Transform>();
连接模式
/// <summary>
/// BoneCloth connection method.
/// [NG] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public RenderSetupData.BoneConnectionMode connectionMode = RenderSetupData.BoneConnectionMode.Line;
public enum BoneConnectionMode
{
// line only.
// ラインのみ
Line = 0,

//Automatically mesh connection according to the interval of Transform.
// Transformの間隔に従い自動でメッシュ接続
AutomaticMesh = 1,

//Generate meshes in the order of Transforms registered in RootList and connect the beginning and end in a loop.
// RootListに登録されたTransformの順にメッシュを生成し、最初と最後をループ状に繋げる
SequentialLoopMesh = 2,

// Generate meshes in the order of Transforms registered in RootList, but do not connect the beginning and end.
// RootListに登録されたTransformの順にメッシュを生成するが最初と最後を繋げない
SequentialNonLoopMesh = 3,
}
旋转插值
/// <summary>
/// Transform rotation interpolation rate in BoneCloth.(0.0 ~ 1.0)
/// (0.0=parent-based, 0.5=middle, 1.0=child-based)
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
[Range(0.0f, 1.0f)]
public float rotationalInterpolation = 0.5f;
根旋转
/// <summary>
/// Rotation interpolation rate of Root Transform in BoneCloth.(0.0 ~ 1.0)
/// (0.0=does not rotate, 0.5=middle, 1.0=child-based)
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
[Range(0.0f, 1.0f)]
public float rootRotation = 0.5f;
动画姿势比
/// <summary>
/// Blend ratio between initial pose and animation pose.
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
[Range(0.0f, 1.0f)]
public float animationPoseRatio = 0.0f;
缩减设置
/// <summary>
/// vertex reduction parameters.
/// </summary>
public ReductionSettings reductionSetting = new ReductionSettings();
/// <summary>
/// Configuration data for reduction.
/// リダクション用の設定データ
/// </summary>
[System.Serializable]
public class ReductionSettings : IDataValidate
{
  /// <summary>
  /// Simple distance reduction (% of AABB maximum distance) (0.0 ~ 1.0).
  /// 単純な距離による削減(AABB最大距離の%)(0.0 ~ 1.0)
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 0.1f)]
  public float simpleDistance = 0.0f;

  /// <summary>
  /// Reduction by distance considering geometry (% of AABB maximum distance) (0.0 ~ 1.0).
  /// 形状を考慮した距離による削減(AABB最大距離の%)(0.0 ~ 1.0)
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 0.1f)]
  public float shapeDistance = 0.0f;
}
自定义外观设置
/// <summary>
/// custom skinning parameters.
/// </summary>
public CustomSkinningSettings customSkinningSetting = new CustomSkinningSettings();
[System.Serializable]
public class CustomSkinningSettings : IValid, IDataValidate
{
  /// <summary>
  /// valid state.
  /// 有効状態
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  public bool enable = false;

  /// <summary>
  /// bones for skinning.
  /// Calculated from the parent-child structure line of bones registered here.
  /// スキニング用ボーン
  /// ここに登録されたボーンの親子構造ラインから算出される
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  public List<Transform> skinningBones = new List<Transform>();
}
正常对齐方式设置
/// <summary>
/// Normal definition.
/// </summary>
public NormalAlignmentSettings normalAlignmentSetting = new NormalAlignmentSettings();
/// <summary>
/// Normal adjustment settings.
/// 法線調整設定
/// </summary>
[System.Serializable]
public class NormalAlignmentSettings : IValid, IDataValidate
{
  public enum AlignmentMode
  {
    None = 0,

    /// <summary>
    /// Radiation from center of AABB.
    /// 中心から放射
    /// </summary>
    BoundingBoxCenter = 1,

    /// <summary>
    /// Emit from the specified transform.
    /// 指定トランスフォームから放射
    /// </summary>
    Transform = 2,
  }

  /// <summary>
  /// adjustment mode.
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  public AlignmentMode alignmentMode = AlignmentMode.None;

  /// <summary>
  /// Transform at which the radiation is centered.
  /// [NG] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  public Transform adjustmentTransform;
}
正常轴
/// <summary>
/// axis to use as normal.
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
public ClothNormalAxis normalAxis = ClothNormalAxis.Up;
重力
/// <summary>
/// Gravity.
/// [OK] Runtime changes.
/// [OK] Export/Import with Presets
/// </summary>
[Range(0.0f, 10.0f)]
public float gravity = 5.0f;
重力方向
/// <summary>
/// Gravity world direction.
/// [OK] Runtime changes.
/// [OK] Export/Import with Presets
/// </summary>
public float3 gravityDirection = new float3(0, -1, 0);
重力衰减
/// <summary>
/// 初期姿勢での重力の減衰率(0.0 ~ 1.0)
/// 1.0にすることで初期姿勢では重力係数が0になる。
/// 0.0では常にどの姿勢でも重力が100%発生する。
///
/// Attenuation rate of gravity at initial pose (0.0 ~ 1.0)
/// By setting it to 1.0, the gravity coefficient becomes 0 in the initial posture.
/// At 0.0, gravity is always 100% in any pose.
///
/// [OK] Runtime changes.
/// [OK] Export/Import with Presets
/// </summary>
[Range(0.0f, 1.0f)]
public float gravityFalloff = 0.0f;
稳定时间复位后
/// <summary>
/// リセット後の速度安定化時間(s)
/// 急激な速度変化を抑えます。
///
/// Speed stabilization time after reset (s).
/// Avoid sudden speed changes.
///
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
[Range(0.0f, 1.0f)]
public float stablizationTimeAfterReset = 0.1f;
混合重量
/// <summary>
/// 元の姿勢とシミュレーション結果のブレンド割合(0.0 ~ 1.0)
///
/// Blend ratio of original posture and simulation result (0.0 ~ 1.0).
///
/// [OK] Runtime changes.
/// [NG] Export/Import with Presets
/// </summary>
[System.NonSerialized]
public float blendWeight = 1.0f;
阻尼
/// <summary>
/// air resistance.
/// [OK] Runtime changes.
/// [OK] Export/Import with Presets
/// </summary>
public CurveSerializeData damping = new CurveSerializeData(0.05f);
半径
/// <summary>
/// Particle radius.
/// [OK] Runtime changes.
/// [OK] Export/Import with Presets
/// </summary>
public CurveSerializeData radius = new CurveSerializeData(0.02f);
惯性约束
/// <summary>
/// Inertia.
/// </summary>
public InertiaConstraint.SerializeData inertiaConstraint = new InertiaConstraint.SerializeData();
[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Movement Influence (0.0 ~ 1.0).
  /// 移動影響(0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float movementInertia;

  /// <summary>
  /// Rotation influence (0.0 ~ 1.0).
  /// 回転影響(0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float rotationInertia;

  /// <summary>
  /// depth inertia (0.0 ~ 1.0).
  /// Increasing the effect weakens the inertia near the root (makes it difficult to move).
  /// 深度慣性(0.0 ~ 1.0)
  /// 影響を大きくするとルート付近の慣性が弱くなる(動きにくくなる)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float depthInertia;

  /// <summary>
  /// Centrifugal acceleration (0.0 ~ 1.0).
  /// 遠心力加速(0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float centrifualAcceleration;

  /// <summary>
  /// Movement speed limit (m/s).
  /// 移動速度制限(m/s)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CheckSliderSerializeData movementSpeedLimit;

  /// <summary>
  /// Rotation speed limit (deg/s).
  /// 回転速度制限(deg/s)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CheckSliderSerializeData rotationSpeedLimit;

  /// <summary>
  /// Particle Velocity Limit (m/s).
  /// パーティクル速度制限(m/s)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CheckSliderSerializeData particleSpeedLimit;
}
系留约束
/// <summary>
/// Tether.
/// </summary>
public TetherConstraint.SerializeData tetherConstraint = new TetherConstraint.SerializeData();
[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Maximum shrink limit (0.0 ~ 1.0).
  /// 0.0=do not shrink.
  /// 最大縮小限界(0.0 ~ 1.0)
  /// 0.0=縮小しない
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float distanceCompression;
}
距离约束
/// <summary>
/// Distance restoration.
/// </summary>
public DistanceConstraint.SerializeData distanceConstraint = new DistanceConstraint.SerializeData();
[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Overall connection stiffness (0.0 ~ 1.0).
  /// 全体的な接続の剛性(0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData stiffness;
}
三角形弯曲约束
/// <summary>
/// Triangle bending / volume.
/// </summary>
public TriangleBendingConstraint.SerializeData triangleBendingConstraint = new TriangleBendingConstraint.SerializeData();
[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Restoring force (0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float stiffness;
}
角度恢复约束
/// <summary>
/// Angle restoration.
/// </summary>
public AngleConstraint.RestorationSerializeData angleRestorationConstraint = new AngleConstraint.RestorationSerializeData();
/// <summary>
/// angle restoration.
/// 角度復元
/// </summary>
[System.Serializable]
public class RestorationSerializeData : IDataValidate
{
  /// <summary>
  /// Presence or absence of use.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public bool useAngleRestoration;

  /// <summary>
  /// resilience.
  /// 復元力
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData stiffness;

  /// <summary>
  /// Velocity decay during restoration.
  /// 復元時の速度減衰
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float velocityAttenuation;

  /// <summary>
  /// Directional Attenuation of Gravity.
  /// Note that this attenuation occurs even if the gravity is 0!
  /// 復元の重力方向減衰
  /// この減衰は重力が0でも発生するので注意!
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float gravityFalloff;
}
角度限制约束
/// <summary>
/// Angle Limit.
/// </summary>
public AngleConstraint.LimitSerializeData angleLimitConstraint = new AngleConstraint.LimitSerializeData();
/// <summary>
/// angle limit.
/// 角度制限
/// </summary>
[System.Serializable]
public class LimitSerializeData : IDataValidate
{
  /// <summary>
  /// Presence or absence of use.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public bool useAngleLimit;

  /// <summary>
  /// Limit angle (deg).
  /// 制限角度(deg)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData limitAngle;

  /// <summary>
  /// Standard stiffness.
  /// 基準剛性
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float stiffness;
}
运动约束
/// <summary>
/// Max distance / Backstop
/// </summary>
public MotionConstraint.SerializeData motionConstraint = new MotionConstraint.SerializeData();
[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Whether or not to use maximum travel range
  /// 最大移動範囲
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public bool useMaxDistance;

  /// <summary>
  /// Maximum travel range.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData maxDistance;

  /// <summary>
  /// Use of backstop.
  /// バックストップ使用の有無
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public bool useBackstop;

  /// <summary>
  /// Backstop sphere radius.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.1f, 10.0f)]
  public float backstopRadius;

  /// <summary>
  /// Distance from vertex to backstop sphere.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData backstopDistance;

  /// <summary>
  /// repulsive force(0.0 ~ 1.0)
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float stiffness;
}
碰撞体碰撞约束
/// <summary>
/// Collider collision.
/// </summary>
public ColliderCollisionConstraint.SerializeData colliderCollisionConstraint = new ColliderCollisionConstraint.SerializeData();
/// <summary>
/// Collision judgment mode.
/// 衝突判定モード
/// </summary>
public enum Mode
{
  None = 0,
  Point = 1,
  Edge = 2,
}

[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// Collision judgment mode.
  /// 衝突判定モード
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public Mode mode;

  /// <summary>
  /// Friction (0.0 ~ 1.0).
  /// Dynamic friction/stationary friction combined use.
  /// 摩擦(0.0 ~ 1.0)
  /// 動摩擦/静止摩擦兼用
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 0.3f)]
  public float friction;

  /// <summary>
  /// Collider list.
  /// コライダーリスト
  /// [OK] Runtime changes.
  /// [NG] Export/Import with Presets
  /// </summary>
  public List<ColliderComponent> colliderList = new List<ColliderComponent>();
}
自碰撞约束
/// <summary>
/// Self collision
/// </summary>
public SelfCollisionConstraint.SerializeData selfCollisionConstraint = new SelfCollisionConstraint.SerializeData();
public enum SelfCollisionMode
{
  None = 0,

  /// <summary>
  /// PointPoint
  /// </summary>
  //Point = 1, // omit!

  /// <summary>
  /// PointTriangle + EdgeEdge + Intersect
  /// </summary>
  FullMesh = 2,
}

[System.Serializable]
public class SerializeData : IDataValidate
{
  /// <summary>
  /// self-collision mode
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public SelfCollisionMode selfMode;

  /// <summary>
  /// primitive thickness.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public CurveSerializeData surfaceThickness = new CurveSerializeData(0.005f, 0.5f, 1.0f, false);

  /// <summary>
  /// mutual collision mode.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public SelfCollisionMode syncMode;

  /// <summary>
  /// Mutual Collision Opponent.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  public MagicaCloth syncPartner;

  /// <summary>
  /// cloth weight.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float clothMass = 0.0f;
}
/// <summary>
/// Wind
/// </summary>
public WindSettings wind = new WindSettings();
/// <summary>
/// 風調整用シリアライズデータ
/// Serialized data for wind adjustment.
/// </summary>
[System.Serializable]
public class WindSettings : IValid, IDataValidate
{
  /// <summary>
  /// 全体の影響率(1.0=100%)
  /// Overall impact rate (1.0=100%).
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 2.0f)]
  public float influence = 1.0f;

  /// <summary>
  /// 揺れの周期(値を大きくすると周期が速くなる)
  /// Period of shaking (the higher the value, the faster the period).
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 2.0f)]
  public float frequency = 1.0f;

  /// <summary>
  /// 乱流率
  /// turbulence rate.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 2.0f)]
  public float turbulence = 1.0f;

  /// <summary>
  /// Sin波とNoise波のブレンド率(0.0:sin ~ 1.0:noise)
  /// Blend ratio of sine wave and noise wave (0.0:sin ~ 1.0:noise).
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float blend = 0.7f;

  /// <summary>
  /// ベースラインごとの同期率
  /// Synchronization rate by baseline.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float synchronization = 0.7f;

  /// <summary>
  /// 深さ影響率
  /// Depth influence factor.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 1.0f)]
  public float depthWeight = 0.0f;

  /// <summary>
  /// 移動時の風速
  /// Wind speed when moving.
  /// [OK] Runtime changes.
  /// [OK] Export/Import with Presets
  /// </summary>
  [Range(0.0f, 10.0f)]
  public float movingWind = 0.0f;

方法


是有效的
/// <summary>
/// クロスを構築するための最低限の情報が揃っているかチェックする
/// Check if you have the minimum information to construct the cloth.
/// </summary>
/// <returns></returns>
public bool IsValid()
导出Json
/// <summary>
/// パラメータをJsonへエクスポートする
/// Export parameters to Json.
/// </summary>
/// <returns></returns>
public string ExportJson()
ImportJson
/// <summary>
/// パラメータをJsonからインポートする
/// Parameterブロックの値型のみがインポートされる
/// Import parameters from Json.
/// Only value types of Parameter blocks are imported.
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public bool ImportJson(string json)
进口
/// <summary>
/// 別のシリアライズデータからインポートする
/// Import from another serialized data.
/// </summary>
/// <param name="sdata"></param>
/// <param name="deepCopy">true = Copy all, false = parameter only</param>
public void Import(ClothSerializeData sdata, bool deepCopy = false)
/// <summary>
/// 別のクロスコンポーネントからインポートする
/// Import from another cloth component.
/// </summary>
/// <param name="src"></param>
/// <param name="deepCopy"></param>
public void Import(MagicaCloth src, bool deepCopy = false)

结束。

ClothSerializeData2

目录 [隐藏]

概述和说明


ClothSerializeData2 类包含系统引用的未公开参数。
与 ClothSerializeData 不同,不建议更改内容。

但是,应将其记录在案,因为用户可能需要创建自己的扩展。

访问


ClothSerializeData2 是私有的,不能直接访问。
要访问它,请使用 MagicaCloth 组件 GetSerializeData2()。

public ClothSerializeData2 GetSerializeData2()

性能


选择数据

/// <summary>
/// vertex paint data.
/// </summary>
[SerializeField]
public SelectionData selectionData = new SelectionData();
/// <summary>
/// 頂点の属性情報(移動/固定/無効)データ
/// このデータはシリアライズされる
/// 座標はクロスコンポーネントのローカル空間で格納される
/// Vertex attribute information (move/fix/disable) data.
/// This data is serialized.
/// Coordinates are stored in the cloth component's local space.
/// </summary>
[System.Serializable]
public class SelectionData : IValid
{
  /// <summary>
  /// 属性のローカル座標
  /// これはクロスコンポーネント空間
  /// Attribute local coordinates.
  /// This is the cloth component space.
  /// </summary>
  public float3[] positions;

  /// <summary>
  /// 上記の属性値
  /// サイズはpositionsと同じでなくてはならない
  /// Attribute value above.
  /// size must be the same as positions.
  /// </summary>
  public VertexAttribute[] attributes;

  /// <summary>
  /// セレクションデータ構築時のVirtualMeshの最大頂点接続距離
  /// Maximum vertex connection distance of VirtualMesh when constructing selection data.
  /// </summary>
  public float maxConnectionDistance;

  /// <summary>
  /// ユーザーが編集したデータかどうか
  /// Is the data edited by the user?
  /// </summary>
  public bool userEdit = false;

CurveSerializeData

目录 [隐藏]

总结

CurveSerializeData是一个类,用于根据深度设置参数值,如下所示。

img

img

img

曲线序列化数据

[System.Serializable]
public class CurveSerializeData
{
  /// <summary>
  /// Basic value.
  /// </summary>
  public float value;

  /// <summary>
  /// Use of curves.
  /// </summary>
  public bool useCurve;

  /// <summary>
  /// Animation curve.
  /// </summary>
  public AnimationCurve curve = AnimationCurve.Linear(0.0f, 1.0f, 1.0f, 1.0f);

  public CurveSerializeData();

  public CurveSerializeData(float value);

  public CurveSerializeData(float value, float curveStart, float curveEnd, bool useCurve = true);

  public CurveSerializeData(float value, AnimationCurve curve);

  public void SetValue(float value);

  public void SetValue(float value, float curveStart, float curveEnd, bool useCurve = true);

  public void SetValue(float value, AnimationCurve curve);

  /// <summary>
  /// Get the current value of Time(0.0 ~ 1.0).
  /// </summary>
  /// <param name="time"></param>
  /// <returns></returns>
  public float Evaluate(float time);
}

MagicaSphereCollider

目录 [隐藏]

性能


中心
/// <summary>
/// トランスフォームからの中心ローカルオフセット
/// Center local offset from transform.
/// </summary>
public Vector3 center;

方法


设置大小
/// <summary>
/// resize the sphere.
/// </summary>
/// <param name="radius"></param>
public void SetSize(float radius)
获取大小
/// <summary>
/// Get collider size.
///
/// Sphere(x:radius)
/// Capsule(x:start radius, y:end radius, z:length)
/// Box(x:size x, y:size y, z:size z)
///
/// </summary>
/// <returns></returns>
public virtual Vector3 GetSize()

结束。

MagicaCapsuleCollider

目录 [隐藏]

性能


方向
public enum Direction
{
[InspectorName("X-Axis")]
X = 0,

[InspectorName("Y-Axis")]
Y = 1,

[InspectorName("Z-Axis")]
Z = 2,
}

/// <summary>
/// Reference transform axis.
/// </summary>
public Direction direction = Direction.X;
半径分离
/// <summary>
/// 半径をStart/End別々に設定
/// Set radius separately for Start/End.
/// </summary>
public bool radiusSeparation = false;
中心
/// <summary>
/// トランスフォームからの中心ローカルオフセット
/// Center local offset from transform.
/// </summary>
public Vector3 center;

方法


设置大小
/// <summary>
/// set size.
/// </summary>
/// <param name="startRadius"></param>
/// <param name="endRadius"></param>
/// <param name="length"></param>
public void SetSize(float startRadius, float endRadius, float length)
获取大小
/// <summary>
/// get size.
/// (x:start radius, y:end radius, z:length)
/// </summary>
/// <returns></returns>
public override Vector3 GetSize()

结束。

MagicaPlaneCollider

目录 [隐藏]

性能


中心
/// <summary>
/// トランスフォームからの中心ローカルオフセット
/// Center local offset from transform.
/// </summary>
public Vector3 center;

结束。

MagicaWindZone

目录 [隐藏]

性能


模式
public enum Mode
{
  /// <summary>
  /// 領域を持たない全体に影響する風
  /// Wind that affects the whole without area.
  /// </summary>
  GlobalDirection = 0,

  /// <summary>
  /// 球型の領域を持つ方向風
  /// Directional wind with spherical area.
  /// </summary>
  SphereDirection = 1,

  /// <summary>
  /// ボックス型の領域を持つ方向風
  /// </summary>
  BoxDirection = 2,

  /// <summary>
  /// 球型の領域を持つ放射風
  /// Directional wind with box area.
  /// </summary>
  SphereRadial = 10,
}

/// <summary>
/// Zone mode.
/// [OK] Runtime changes.
/// </summary>
public Mode mode = Mode.GlobalDirection;

大小

/// <summary>
/// Box size.
/// [OK] Runtime changes.
/// </summary>
public Vector3 size = new Vector3(10.0f, 10.0f, 10.0f);
半径
/// <summary>
/// Sphere size.
/// [OK] Runtime changes.
/// </summary>
public float radius = 10.0f;
主要
/// <summary>
/// メイン風力
/// main wind (m/s).
/// [OK] Runtime changes.
/// </summary>
[Range(0, 30)]
public float main = 5.0f;
湍流
/// <summary>
/// 乱流率
/// turbulence rate.
/// [OK] Runtime changes.
/// </summary>
[Range(0.0f, 1.0f)]
public float turbulence = 1.0f;
方向角度 Y
/// <summary>
/// 風の方向X角度(ローカル角度)
/// wind direction x angle (local angle).
/// [OK] Runtime changes.
/// </summary>
[Range(-180, 180)]
public float directionAngleX = 0;
方向角度X
/// <summary>
/// 風の方向Y角度(ローカル角度)
/// wind direction y angle (local angle).
/// [OK] Runtime changes.
/// </summary>
[Range(-180, 180)]
public float directionAngleY = 0;
衰减
/// <summary>
/// 放射風の減衰
/// Radiation wind attenuation.
/// [OK] Runtime changes.
/// </summary>
public AnimationCurve attenuation = AnimationCurve.EaseInOut(0.0f, 1.0f, 1.0f, 0.0f);
是加法
/// <summary>
/// 他の風の影響を無効にせずに追加するフラグ
/// Flags to add without disabling other wind effects.
/// [OK] Runtime changes.
/// </summary>
public bool isAddition = false;

方法


获取风向
/// <summary>
/// 方向性風の風向きを取得する
/// Get the direction of the directional wind.
/// </summary>
/// <param name="localSpace"></param>
/// <returns></returns>
public Vector3 GetWindDirection(bool localSpace = false)
设置风向
/// <summary>
/// 方向性風の風向きを設定する
/// Set the wind direction for directional wind.
/// </summary>
/// <param name="dir"></param>
/// <param name="localSpace"></param>
public void SetWindDirection(Vector3 dir, bool localSpace = false)
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cchoop

有用的话请杯肥宅水

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值