跳转到内容
CRUSHFORMV1.1.0
在 Fab 上获取

损伤玻璃

玻璃

Crushform 车身的每一块玻璃板都可能开裂、碎裂,并散落成玻璃碎片。车窗附近的命中会使其开裂,更猛烈的命中会使其碎裂;车身在玻璃板周围凹陷时,也可能使其开裂。裂纹会一直留在玻璃板上,直到车身被修复。

25 m/s 的命中使挡风玻璃碎裂成碎片。

玻璃板是车身上的一个静态网格体,即一个 UCFGlassComponent。它没有自己的碰撞。射击或投掷的石块会击中车窗处的车身碰撞体,Crushform 会把这次命中匹配到它所到达的那块玻璃板,匹配范围为 Hit Reach Cm(UCFGlassDefinition::HitReachCm,新定义中为 15 cm)以内。

每块玻璃板是一个单元,有三个等级:完好、开裂和碎裂。玻璃板按名称编号,因此各端对每块玻璃板的对应关系一致。

有三种情况可以使玻璃板开裂。玻璃板的定义为每一种情况设定阈值:

  • 命中。 玻璃板附近的命中,其速度变化量达到 Crack Delta V(UCFGlassDefinition::CrackDeltaV)时使其开裂,达到 Break Delta V(UCFGlassDefinition::BreakDeltaV)时使其碎裂。低于开裂阈值的命中对玻璃没有影响。
  • 车框。 车身在凹陷时会向玻璃板周围弯曲(凹陷与晶格对凹陷有说明)。玻璃板盒体内所有节点中位移最大的那个,达到 Frame Crack Displacement Cm 时使玻璃板开裂。这些节点的平均位移达到 Frame Break Displacement Cm 时使其碎裂。
  • 关联部件。 车身的某个部件,例如挡风玻璃前方的引擎盖(铰接部件对铰接部件有说明),可以通过玻璃板的 Crush Link Box(UCFGlassComponent::CrushLinkBox)使其开裂。该盒体内最深的节点会在离它最近的边缘处使玻璃板开裂,平均值则使其碎裂。

车框和关联部件只有在车身凹陷时才会评估玻璃。因此,玻璃需要车辆适配器上的 Dirt and Dents 开启。适配器通过它找到玻璃板。关于适配器和晶格,参见核心概念。

碎裂前的开裂次数。 将 Cracks Before Break(UCFGlassDefinition::CracksBeforeBreak)设为某个数值,可使玻璃板在被命中开裂该次数后碎裂。设为 0 时,玻璃板不会按次数碎裂。只有命中计入次数,车框不计入,因此一个保留下来的凹陷不会随时间使玻璃板碎裂。

裂纹外观。 每块玻璃板最多保留四道裂纹。裂纹的半径随命中强度增长,范围在 Min Crack Radius Cm 与 Max Crack Radius Cm 之间。Crack Style 设定图案:网状、孔状或网格状。

外部命中。 子弹或投掷的石块只有在 Takes Point Damage(UCFGlassDefinition::bTakesPointDamage)开启时,才能使玻璃板开裂。随后,定义中的 Hit Responses 表决定每一种命中使玻璃板达到哪个等级。表中没有对应行的命中种类不会产生任何效果(UCFBreakableDefinition::HitResponses)。

碎裂。 碎裂的玻璃板会被隐藏,并散落成玻璃碎片。玻璃板被方形分块覆盖,离命中点最近的分块优先。每个分块的边长为 Shard Tile Cm,碎裂成 Shards Per Tile 个碎片。至多 Max Shard Tiles 个分块会变成碎片,因此碎片最多覆盖玻璃板上这么多个分块,其余部分则直接消失:五个 50 cm 的分块覆盖 1.25 m²,夹层玻璃预设即如此。每个分块会绕玻璃板的朝外轴旋转一个随机角度,这样两个分块的碎片不会排成一条线。Shard Shape 决定碎片的形状:颗粒是小块,如钢化玻璃;板块是平片,如碎裂而不飞散的夹层玻璃。每个碎片都是碎片网格体之一,随机选取并缩放到该碎片的大小。插件自带六块不规则的多边形板,从 SM_CF_GlassShard_01 到 SM_CF_GlassShard_06,用 M_CF_GlassShard 绘制,那是边缘更亮的透明玻璃。每块碎裂的玻璃板都以同一个 Niagara 系统的粒子来抛出它的碎片,详见下文的“碎片系统”。

谁负责绘制。 服务器判定玻璃的状态,并复制裂纹,每一个绘制裂纹的端都会显示它们。专用服务器判定玻璃板,但不绘制任何内容,也不加载任何碎片系统。修复会使每块玻璃板恢复完整,并清除其裂纹。

  1. 打开车辆的蓝图,例如你项目中 BP_VehicleAdvSedan 的副本。选中它的 Crushform Chaos Vehicle Adapter 组件。确认 Dirt and Dents 和 Glass 已开启。两者默认都是开启的。
  2. 创建一个玻璃定义。在 Content Browser 中选择 Add > Miscellaneous > Data Asset,选择 CFGlass Definition,然后为其命名。你也可以从 Plugins › Crushform Content › Presets 中复制一个自带的预设:DA_CF_GlassLaminated 或 DA_CF_GlassTempered。
  3. 检查定义中的碎片设置。没有碎片的定义会发出警告:碎裂的玻璃板会直接消失,而不产生任何碎片。请在编辑器工具蓝图或 Python 中调用 Build Glass Shards(UCFContentLibrary::BuildGlassShards,位于 Crushform|Content 分类)来生成碎片。该调用需要传入定义和一个碎片网格体列表;插件自带六个,由 Build Glass Shard Mesh(UCFContentLibrary::BuildGlassShardMesh)生成。
Glass
Crushform Hits
Crack Delta V5.0
Break Delta V14.0
Hit Reach Cm20.0
Frame Crack Displacement Cm4.0
Frame Break Displacement Cm12.0
Link Crack Displacement Cm30.0
Link Break Displacement Cm15.0
Cracks Before Break0
Look
Crack StyleWeb
Min Crack Radius Cm10.0
Max Crack Radius Cm45.0
Crack Merge Cm12.0
Shards
Shard ShapeSlabs
Shard Tile Cm50.0
Shards Per Tile12
Shard Min Size Cm3.0
Shard Max Size Cm9.0
Shard Thickness Cm0.6
Max Shard Tiles5
夹层挡风玻璃的玻璃定义:其开裂与碎裂阈值、外观和碎片。
  1. 为每扇车窗添加一块玻璃板。在车辆的蓝图中,选择 Add › CFGlass,位于 Crushform 分组中。将其 Static Mesh 设为车窗的网格体,将 Definition 设为你的玻璃定义。把玻璃板附着在车身下,或附着在它所在的铰接部件下。
  2. 打开车窗的静态网格体,开启 Allow CPU Access。若不开启,弯曲或倾斜车窗的碎片会落在一个平面上,因为插件无法读取车窗的形状。
  3. 可选:设置玻璃板的 Crush Link Box,例如像轿车那样设为挡风玻璃周围的区域。对于引擎盖会折叠进去的玻璃板,也可以选择引擎盖。在 Crush Link Box 上勾选 Is Valid,然后以厘米为单位,在根组件的空间中设置其 Min 和 Max。盒体无效时,不会关联任何内容。在蓝图编辑器中选中玻璃板,即可在视口中看到绘制的盒体。该盒体只在蓝图编辑器中绘制,关卡和 PIE 中不显示。
在蓝图编辑器中选中的一块玻璃板。其 Details 显示 Crush Link Box 已勾选 Is Valid,视口中浅蓝色盒体围绕在挡风玻璃周围。
在轿车上,Crush Link Box 正好围绕挡风玻璃:盒体内的节点会使玻璃板开裂。

用 Get Glass 从车辆适配器获取玻璃单元。只有 Glass 和 Dirt and Dents 都开启时,它才会返回结果。然后将 On Unit Level Changed(UCFBreakableUnitsComponent::OnUnitLevelChanged)绑定到一个自定义事件。该事件传递 Units、UnitIndex、Level 和 PreviousLevel。

每当某块玻璃板的等级发生变化时,每一端都会触发该事件。这也包括中途加入的玩家,他会收到已经开裂或碎裂的玻璃板状态。因此,应在处理函数中检查 Level,而不要假定该事件就意味着碎裂。不要由它启动一次性的特效。若要读取车身每一侧的凹陷程度,请使用损伤区域与事件。

此图绑定 On Unit Level Changed,并打印新的 Level。

在 C++ 中,可以让离某个点最近的玻璃板开裂或碎裂。这仅在权威端生效。

#include "CFScriptedHits.h"
// Authority only: crack the pane nearest WorldPoint, within 50 cm of it.
const bool bCracked = CFScriptedHits::HitPaneNear(*Deform, WorldPoint, 50.0f, /*bBreak=*/false);

Deform 是车身的 UCFDeformComponent,WorldPoint 是世界空间中的 FVector。将 bBreak 设为 true,则改为使该玻璃板碎裂。如果没有玻璃板在该距离之内,或者什么都没有改变,函数返回 false。

属性作用默认值(新定义)
UCFGlassDefinition::CrackDeltaV玻璃板附近命中的速度变化量(m/s),达到该值时玻璃板开裂。5
UCFGlassDefinition::BreakDeltaV命中的速度变化量(m/s),达到该值时命中使玻璃板碎裂。必须高于 Crack Delta V。12
UCFGlassDefinition::HitReachCm命中匹配到玻璃板时,玻璃板盒体向外扩展的距离(cm)。15
UCFGlassDefinition::FrameCrackDisplacementCm玻璃板盒体内最大节点位移(cm),达到该值时车框使玻璃板开裂。4
UCFGlassDefinition::FrameBreakDisplacementCm玻璃板盒体内平均节点位移(cm),达到该值时车框使其碎裂。10
UCFGlassDefinition::LinkCrackDisplacementCmCrush Link Box 内最大节点位移(cm),达到该值时关联部件使玻璃板开裂。25
UCFGlassDefinition::LinkBreakDisplacementCmCrush Link Box 内平均节点位移(cm),达到该值时关联部件使玻璃板碎裂。15
UCFGlassDefinition::CracksBeforeBreak命中造成的裂纹达到该次数后,玻璃板碎裂。为零:从不按次数碎裂。0
UCFGlassDefinition::CrackStyle命中留下的裂纹图案:网状、孔状或网格状。Web
UCFGlassDefinition::MinCrackRadiusCm最弱命中留下的裂纹半径(cm)。8
UCFGlassDefinition::MaxCrackRadiusCm最强命中留下的裂纹半径(cm)。45
UCFGlassDefinition::ShardShape碎裂的玻璃板散落成的形状:颗粒或板块。Granules
UCFGlassDefinition::ShardTileCm玻璃板上方形分块的边长(cm),每个分块生成 Shards Per Tile 个碎片。至少为 2。30
UCFGlassDefinition::ShardsPerTile玻璃板的一个分块碎裂成的碎片数。8
UCFGlassDefinition::ShardMinSizeCm碎片的最小边长(cm)。2
UCFGlassDefinition::ShardMaxSizeCm碎片的最大边长(cm)。4
UCFGlassDefinition::ShardThicknessCm碎片的厚度(cm)。仅限板块。0.5
UCFGlassDefinition::MaxShardTiles一块玻璃板碎裂时,变成碎片的分块数量上限。6
UCFGlassDefinition::ShardSystem抛出这种玻璃碎片的 Niagara 系统。无:使用项目的 Default Glass Shard System。无
UCFGlassDefinition::bTakesPointDamage子弹或投掷的石块能否使玻璃板开裂和碎裂。关
UCFGlassComponent::CrushLinkBox车身中其挤压也会使此玻璃板开裂的部分。空盒体不关联任何内容。空

以上是新定义的数值。自带的预设有所不同。轿车使用的 DA_CF_GlassLaminated 在 5 m/s 开裂,在 14 m/s 碎裂,覆盖范围为 20 cm。它的分块为 50 cm,每块 12 个 3 到 9 cm 的碎片,最多 5 个分块。DA_CF_GlassTempered 在 6 m/s 开裂,在 9 m/s 碎裂。它的分块为 30 cm,每块 16 个 1 到 2.5 cm 的碎片,最多 4 个分块。

每块碎裂的玻璃板都通过一个取自对象池的 Niagara 系统来抛出它的碎片。该系统在播完时、玻璃板被修复时以及游戏结束时回到池中。距离本地摄像机超过 UCFBreakableSettings::DebrisMaxSpawnDistanceCm(10000 cm)的玻璃板不抛出碎片。

定义可在 Shard System(UCFGlassDefinition::ShardSystem)中指定自己的系统。没有 Shard System 的定义,使用项目在 Project Settings › Plugins › Crushform 的 Glass 分组中的 Default Glass Shard System。插件将它设为 NS_CF_GlassShards。默认系统在游戏开始时于后台加载。在它进入内存之前,碎裂不会抛出碎片,而游戏也绝不会在碎裂的那一帧里等待它。定义自己的系统随定义一起加载,因此没有这段空档。

网格体槽位。 每个碎片从一个网格体槽位取得它的网格体,槽位是一个静态网格体用户参数:User.CF_ShardMesh0、User.CF_ShardMesh1,依此类推。槽位 0 取定义中第一个不同的碎片网格体,槽位 1 取第二个,顺序即这些网格体首次出现在各碎片中的顺序。默认系统有六个槽位,从 CF_ShardMesh0 到 CF_ShardMesh5。第七个不同的网格体复用槽位 0,第八个复用槽位 1,依此类推。定义自己的系统需要为每个不同的网格体准备一个槽位。当没有 Shard System 的定义拥有六个以上不同的碎片网格体时,编辑器会发出警告。系统中没有的槽位不会绘制任何网格体。

碎片声音。 当碎片撞上物体时,玻璃板会为其中最快的那个播放碎片撞击声,最多每 0.25 s 一次(UCFBreakableSettings::DebrisImpactCooldownSeconds)。撞击小于 UCFBreakableSettings::DebrisMinImpulsePerKg 的碎片不播放任何声音。自定义系统需要下文所述的 Export 数据接口才能发出这种声音。

自定义系统必须公开什么。 请按下列名称为系统提供这些用户参数。插件在每次生成时都会设置其中每一个,因此被复用于另一块玻璃板的池中系统,不会保留上一块玻璃板的任何数值。系统中没有的参数会被忽略。

参数类型含义单位
User.CF_ShardPositions位置数组每个碎片在世界空间中的中心。cm
User.CF_ShardRotations四元数数组每个碎片在世界空间中的旋转。无
User.CF_ShardVelocities向量数组每个碎片的初始线速度。cm/s
User.CF_ShardAngularVelocities向量数组每个碎片绕世界坐标轴的初始自旋。deg/s
User.CF_ShardScales向量数组每个碎片的缩放。它与碎片网格体的大小相乘。无
User.CF_ShardMeshIndices整数数组每个碎片取用网格体的槽位。槽位编号
User.CF_ShardCount整数本次生成中的碎片数量。无
User.CF_ShardLifetime浮点数碎片最多存活的秒数。s
User.CF_ShardRestSeconds浮点数静止的碎片在下沉前一动不动躺着的秒数。s
User.CF_ShardSinkSeconds浮点数碎片下沉消失所需的秒数。s
User.CF_ShardCollisionDelay浮点数生成后多少秒,系统才让碎片参与碰撞。插件设为 0.1。s
User.CF_ShardCallback对象系统的 Export 数据接口把每次碎片命中报告给的回调。无
User.CF_ShardMesh0、User.CF_ShardMesh1……静态网格体槽位 0、槽位 1 等的网格体。无

碎片声音还需要一个 Export 数据接口,把每个粒子的位置和速度报告给 User.CF_ShardCallback。没有它,碎片照样飞散,只是少了它们的声音。

三个控制台变量设定玻璃抛出多少碎片以及何时抛出:

  • Crushform.Glass.ShardScale(1)是一块碎裂玻璃板的碎片中被抛出的比例,范围 0 到 1。0 表示一个也不抛,玻璃板仍会碎裂。
  • Crushform.Glass.MaxLiveShards(512)是碎裂玻璃板的碎片同时存活的最大数量。0 表示不设上限。超过上限时,最旧的碎裂玻璃板的碎片最先被释放,而同一次碎裂自己的碎片超出上限的部分会被裁掉。
  • Crushform.Glass.ShardSystemsPerFrame(1)是一帧内启动的碎片系统数量,0 表示不限。一起碎裂的玻璃板,抛出碎片的时间会相差一帧或几帧,这样碰撞的那一帧就不会把它们全部启动。

每一个的开销见性能页面。

在除 Shipping 之外的任何构建中,于编辑器内运行。Crushform.DebugImpact 不会命中你驾驶的车辆,因为轨迹会跳过它。开车靠近一辆停放的车,例如 Proving Ground 地图上的 BP_VehicleAdvSedan2,并将视野中心对准它的挡风玻璃。输入 Crushform.DebugImpact 8,速度变化量为 8 m/s。车窗上应出现裂纹,并听到开裂声。先设置 crushform.Impact.LogHits 1,即可记录每次命中的位置和强度。

从引擎盖上方看轿车的挡风玻璃,上面有数道网状图案的裂纹。
数次 8 m/s 的命中在挡风玻璃上留下了这些网状裂纹。

然后在同一车窗上输入 Crushform.DebugImpact 15。在 15 m/s 时,玻璃板碎裂:它消失,碎片从车身上飞散。Crushform.RepairAll 会让玻璃板恢复完整。

  • 车窗附近的命中没有留下裂纹。 命中低于 Crack Delta V(新定义中为 5 m/s),或车辆适配器的 Dirt and Dents 已关闭,因此车框和关联部件从不评估玻璃。请加大命中力度,或降低 Crack Delta V,或开启 Dirt and Dents。
  • 碎裂的车窗消失了,但没有碎片。 定义中没有碎片。请按设置第 3 步,使用 Build Glass Shards 生成碎片。
  • 子弹穿过车窗却没有留下裂纹。 Takes Point Damage 关闭,或定义的 Hit Responses 表中没有该命中种类的行。请开启该开关,并为该种类添加一行。
  • 弯曲车窗的碎片飞向错误的平面。 车窗的静态网格体没有开启 Allow CPU Access,因此插件会为其套上一个平面盒体。请开启该选项,然后重新生成碎片。
  • 游戏刚开始就碎裂时没有碎片。 默认碎片系统在游戏开始时于后台加载,在它进入内存之前,碎裂不会抛出碎片。请把定义的 Shard System 设为它自己的系统,该系统随定义一起加载。默认系统进入内存后,之后的碎裂就会照常抛出碎片。
  • 多块玻璃板同时碎裂时,缺了一些碎片。 玻璃碎片不使用碎片池,因此 Max Live Debris Pieces(UCFBreakableSettings::MaxLiveDebrisPieces)并不限制它们。所有碎裂玻璃板的存活碎片,受 Crushform.Glass.MaxLiveShards 限制,默认为 512。超过上限时,最旧的碎裂玻璃板的碎片最先消失,也就是提前消失。使用自带预设时,一块夹层挡风玻璃最多碎裂成 12 × 5 = 60 个碎片,一块钢化侧窗最多碎裂成 16 × 4 = 64 个,所以约八块夹层挡风玻璃就会达到默认上限。将上限设为 0 即不设上限。碎片所用的碎片池,见碎片。
  • 专用服务器上没有裂纹。 这是设计如此。专用服务器判定玻璃,但不绘制任何内容。请在客户端上查看裂纹。