集成材质与着色器
材质与着色器
每个发生形变的车身、车轮、玻璃板和轮胎都由材质绘制。插件提供移动顶点、绘制磨损和绘制污垢的函数,并为每个网格提供它在图集中找到位置所需的数据。本页是这些部分的参考。关于接线的逐步讲解(其中包括一个涂漆车身的十处连接),请见快速入门。其背后的思路请见核心概念中的材质部分。
所有函数都位于插件内容的 Materials 文件夹 /Crushform/Materials 中。它们的输入和输出即材质或外观所连接的引脚。引脚名称必须完全一致,包括空格。
| 函数 | 输入 | 输出 | 构建器 |
|---|---|---|---|
MF_CF_Deform | Normal、Crumple Tiling、Fold Amplitude、Fold Wavelength、Fine Fold Wavelength、Fine Fold Strength | World Position Offset、Normal、Wear Depth、Scratch | UCFContentLibrary::BuildDeformFunction |
MF_CF_Paint | Base Color、Roughness、Metallic、Wear Depth、Primer Color、Metal Color、Scratch Tiling、Dust Color、Mud Color、Dirt Strength、Snow Color、Built-in Look、Scratch、Scratch Line Tiling | Base Color、Roughness、Metallic | BuildPaintFunction |
MF_CF_DirtAmount | 无 | Dust、Mud、Snow、Wet、Dirt Fresh、Dirt Ranks、Pattern Position、Pattern Normal | BuildDirtAmountFunction |
MF_CF_WheelDirt | Base Color、Roughness、Metallic、Dust Color、Mud Color、Dirt Strength、Snow Color、Built-in Look | Base Color、Roughness、Metallic | BuildWheelDirtFunction |
MF_CF_WheelDirtAmount | 无 | Dust、Mud、Snow、Wet、Dirt Ranks、Pattern Position、Pattern Normal | BuildWheelDirtAmountFunction |
MF_CF_GlassCrack | Base Color、Opacity、Roughness、Normal、Built-in Look | Base Color、Opacity、Roughness、Normal | BuildGlassCrackFunction |
MF_CF_GlassCrackData | 无 | Crack Mask、Crack Frost、Crack Tilt、Crack 0 至 Crack 3、Crack Radii、Pane U、Pane V | BuildGlassCrackDataFunction |
MF_CF_TireDeform | AxleAxis、HalfWidth、BulgeAmount、RimRadius、RimFalloff、FlattenScale、MaxVertDisp | Result | BuildTireDeformFunction |
MF_CF_TrunkBend | 插件代码不设置 | 世界空间的 World Position Offset | 在编辑器中制作,不由代码生成 |
MF_CF_Deform 在切线空间中工作,因此已接线材质的法线也必须是切线空间的。MF_CF_Paint 和 MF_CF_WheelDirt 带有 Built-in Look 开关,它是一个默认为 true 的静态布尔值。外观设置会使用该开关,如下文“外观”一节所述。
轮胎材质有一个标量参数 RimRadius,即轮辋半径,单位为网格单位。MF_CF_TireDeform 把它作为输入,UCFTireComponent 读取同一个参数,以知道可以把车轮从障碍物推开多远。轮胎网格体上第一个自身设置了 RimRadius 的材质槽优先,因此只继承母材质默认值的轮辋材质不会盖过轮胎自己的值。如果没有槽设置它,则由第一个带有该参数的槽提供其默认值。UCFTireProfile::RimRadiusOverride(单位厘米)会取代它。
MF_CF_TrunkBend 使树干弯曲。其自身描述写道:“Parabolic trunk bow driven by CPD 0..2; outputs world-space WPO”。它的两个母材质会将其加在风力偏移之后。
构建器会在编辑器中从头重建函数。它们按名称保留引脚 ID,且不会保存函数。重建后请保存该函数。
母材质、集合与图集
Section titled “母材质、集合与图集”| 资产 | 作用 |
|---|---|
/Crushform/Materials/M_CF_VehiclePaint | 漆面母材质:Clear Coat,在设置了 Paint Mask 的区域,Paint Color 覆盖 Base Texture |
/Crushform/Materials/M_CF_Wheel | 车轮母材质:Default Lit,经由 MF_CF_WheelDirt,并受开关 Tire Deform 控制 |
/Crushform/Materials/M_CF_GlassShard | 玻璃碎片所用的半透明清透玻璃 |
/Crushform/Materials/MPC_CF_Dirt | 污垢外观,由每个车身和车轮共享。其参数由污垢函数读取 |
/Crushform/Atlas/RT_CF_LatticeAtlas | 晶格图集。每个发生形变的网格都在其中找到自己的槽位 |
/Crushform/Atlas/RT_CF_DirtAtlas 和 RT_CF_DirtFreshAtlas | 污垢图集,尺寸与晶格图集相同 |
/Crushform/Atlas/RT_CF_ScratchAtlas | 划痕图集:大小与晶格图集相同的 RG8 渲染目标,保存每个点的划痕线覆盖度和方向 |
母材质的贴图来自插件的 T_CF_Default* 贴图,每张贴图都有一个普通参数和一个虚拟参数。参数名称是固定的。材质实例通过名称设置它们,因此重命名任何一个参数都会使设置该参数的每个实例失效。
自定义基元数据
Section titled “自定义基元数据”每个网格都在自定义基元数据中携带自己的数据,数据分块存放,由材质函数读取。各数据块的偏移量是 Project Settings > Plugins > Crushform > Atlas 中的项目设置。在 Unreal Engine 5.6 至 5.8 中,一个基元有 36 个浮点数(FCustomPrimitiveData::NumCustomPrimitiveDataFloats)。
| 数据块 | 偏移设置 | 浮点数 | 默认偏移 | 内容 |
|---|---|---|---|---|
| 形变网格 | UCFSettings::CustomDataOffset | 18 | 0 | 图集槽位、网格到根的变换各列、平移、单元格尺寸的倒数、量化值和分辨率 |
| 车轮 | UCFSettings::WheelCustomDataOffset | 2 | 34 | 两个整数:灰尘和泥浆的数量,以及雪和湿润的数量,连同各层的等级 |
| 玻璃板 | UCFSettings::GlassCustomDataOffset | 16 | 18 | 四条裂纹记录,每条四个浮点数 |
| 轮胎 | UCFSettings::TireCustomDataOffset | 32 | 0 | 四条接触记录,每条八个浮点数 |
形变数据块依次包含:索引 0 处的图集槽位;索引 1 至 9 处网格到根的旋转与缩放的三列;索引 10 至 12 处晶格空间中的网格原点;索引 13 至 15 处单元格尺寸的倒数;索引 16 处的量化值;以及索引 17 处打包后的分辨率。MF_CF_Deform 读取的索引相同,因此布局由代码决定,而不由资产决定。
| Atlas | ||
|---|---|---|
| Atlas | RT_CF_LatticeAtlas | |
| Slot Width | 256 | |
| Slot Height | 8 | |
| Custom Data Offset | ||
| Wheel Custom Data Offset | ||
| Tire Custom Data Offset | ||
| Glass Custom Data Offset | ||
| Scratch Atlas | None | |
使用默认值时,形变网格的数据块位于 0 至 17,玻璃板位于 18 至 33,车轮位于 34 至 35。轮胎有自己的 0 至 31,它从不与车身共用网格。
插件会拒绝放不下或与其他数据块重叠的数据块。玻璃数据块必须能放入基元,并与形变数据块保持不重叠。轮胎数据块必须能放下,并与车轮数据块保持不重叠。被拒绝的玻璃偏移会以错误形式记录,玻璃板也不会产生裂纹:
%s: Glass Custom Data Offset %d does not fit beside the deformed block at Custom Data Offset %d; the panes get no cracks数据块移动时,烘焙了其索引的材质函数必须重建。当你在项目设置中更改四个偏移量之一时,编辑器会自动执行此操作。它会重建烘焙这些索引的八个函数:MF_CF_Deform、MF_CF_Paint、MF_CF_DirtAmount、MF_CF_WheelDirt、MF_CF_WheelDirtAmount、MF_CF_TireDeform、MF_CF_GlassCrack 和 MF_CF_GlassCrackData。编辑器中的提示内容如下:
Crushform: the Custom Data Offsets are in the material functions. Save the Crushform material functions to keep them.重建结果不会自动保存。请保存这些函数,否则编辑器重新加载时旧索引会恢复。当八个函数中的任何一个在 Material Editor 中打开时,编辑器不会重建其中任何一个。控制台命令 Crushform.RebakeOffsets 可手动执行相同的重建,且仅存在于编辑器中。
接线用于将材质连接到插件。由以下三个步骤完成:
- 顶点偏移和法线经过
MF_CF_Deform。 - 基础颜色、粗糙度和金属度经过
MF_CF_Paint。对于与车身共享网格的玻璃和内饰,不要传入任何漆面函数。它们会随车身一同凹陷,并保留各自的外观。 - 材质的 Max World Position Offset Displacement 会被提高到你传入的值。
涂漆材质还会获得标量 CF_PaintWear,默认值为 1。与车身母材质共享、但不应磨损的材质实例将其设为 0。对于 /Crushform/ 和 /Engine/ 之外的材质,接线还会为其应用项目的外观。
在 Python 中,编辑器提供了相同的调用:
import unreal
material = unreal.load_asset(MATERIAL_PATH) # the material to wire, in your projectdeform = unreal.load_asset("/Crushform/Materials/MF_CF_Deform")paint = unreal.load_asset("/Crushform/Materials/MF_CF_Paint")bound = 60.0 + unreal.CFContentLibrary.get_default_fold_amplitude()unreal.CFContentLibrary.wire_material(material, deform, paint, bound)将 60.0 替换为你的配置文件的 Max Displacement。褶皱幅度来自函数,而不是配置文件。
同一调用也是编辑器模块的一个蓝图函数,因此编辑器工具蓝图可以调用它。下方的图表为材质接线,其中默认褶皱幅度被加到 Max Displacement 上。其 A 引脚保存 60 厘米,即 UCFProfile::MaxDisplacement 的类默认值。请将其设为你的配置文件的值。材质本身放入 Material 引脚,该图表将其留给你自行设置。
当材质使用世界空间法线,或使用材质属性却没有任何来源为其提供数据时,接线会被拒绝,材质保持原样。日志会在每种情况下写明该材质的名称。
Nanite 与 Max World Position Offset Displacement
Section titled “Nanite 与 Max World Position Offset Displacement”材质的 Max World Position Offset Displacement 是一个边界。渲染器用它判断网格的顶点最多可能移动多远。该边界必须至少等于配置文件的 Max Displacement 加上材质的褶皱幅度。褶皱会使顶点移动到凹陷之外。默认褶皱幅度为 3 厘米(CFContent::DefaultFoldAmplitude),get_default_fold_amplitude() 返回的就是它。
在 Nanite 中,这一边界更加重要。簇剔除会以此扩大其包围盒,因此过短的边界会导致渲染器剔除屏幕边缘处的凹陷面板。接线时若边界过小,会将其提高。已有自身偏移和边界的材质,会把位移量加到其边界上。只有在不接线时才需要手动设置。
轮胎母材质保持 Always Evaluate WPO 关闭。UCFTireComponent 会为每个带有形变器的车轮开启偏移,而始终计算该偏移的材质会使该开关失去作用。车轮母材质的边界为 16 厘米。
骨骼网格体的材质必须在 Usage 下标记 Used with Skeletal Mesh,否则其着色器不会被编译,网格也不会弯曲。
外观用你自己的材质函数替换函数内置的污垢或裂纹绘制。三个设置用于选择外观,位于 Project Settings > Plugins > Crushform > Look:
| 设置 | 替换 | 必需输出 |
|---|---|---|
UCFSettings::BodyDirtLook | MF_CF_Paint | Base Color |
UCFSettings::WheelDirtLook | MF_CF_WheelDirt | Base Color |
UCFSettings::GlassCrackLook | MF_CF_GlassCrack | Opacity |
| Look | ||
|---|---|---|
| Body Dirt Look | None | |
| Wheel Dirt Look | None | |
| Glass Crack Look | None | |
外观的输入和输出按名称与函数的引脚相匹配,不区分大小写,但区分空格。若某个外观输入无法由任何引脚提供数据,接线就会失败,除非你在该输入上勾选了 Use Preview Value As Default。缺少必需输出的外观会被拒绝。日志会写明缺少的输出:
WireLook: %s lacks the output "%s" that the look of %s cannot do without外观的 Normal 输入总会被提供数据。它取内置调用的法线输出、为法线引脚提供数据的来源,或一个平坦的切线空间法线。外观的 Normal 输出同样会被使用。带有 Normal 输出的内置调用会将其作为自己的法线。否则,在车身中它会放在 MF_CF_Deform 的 Normal 输入之前,或放在材质法线之前。车身漆面没有 Normal 输出,因此车身外观的法线会放在 MF_CF_Deform 之前。
| 外观 | 替换 | 数据函数 | 可能具有的输入 | 可能替换的输出 |
|---|---|---|---|---|
| Body Dirt Look | MF_CF_Paint | MF_CF_DirtAmount | Base Color、Roughness、Metallic、Normal;Dust、Mud、Snow、Wet、Dirt Fresh、Dirt Ranks、Pattern Position、Pattern Normal | Base Color(必需)、Roughness、Metallic、Normal |
| Wheel Dirt Look | MF_CF_WheelDirt | MF_CF_WheelDirtAmount | Base Color、Roughness、Metallic、Normal;Dust、Mud、Snow、Wet、Dirt Ranks、Pattern Position、Pattern Normal | Base Color(必需)、Roughness、Metallic、Normal |
| Glass Crack Look | MF_CF_GlassCrack | MF_CF_GlassCrackData | Base Color、Opacity、Roughness、Normal;Crack Mask、Crack Frost、Crack Tilt、Crack 0 至 Crack 3、Crack Radii、Pane U、Pane V | Opacity(必需)、Base Color、Roughness、Normal |
外观的输入由同名的内置调用输出,或由同名数据函数的输出提供数据。两者都无法提供数据的输入会使外观失败,除非该输入勾选了 Use Preview Value As Default:
WireLook: %s has the input "%s", which nothing can feed; name it after a pin of %s or %s, or tick Use Preview Value As Default包含多个内置函数调用的材质,只会对第一个调用应用该外观。日志会对其他调用发出警告。
更改外观设置时,会将其应用于项目中调用该函数的每个已保存材质。被修改的材质会重新编译并标记为脏(需要保存),但不会自动保存,因此请保存它们以保留新外观。在 Material Editor 中打开的材质会被跳过并给出警告。请关闭它,然后运行控制台命令 Crushform.RewireLooks,它会手动执行同样的操作。该命令仅存在于编辑器中。
污垢层被烘焙进污垢函数。更改 Dirt Layer Order,或某个污垢通道的混合方式或 Z 顺序,会立即在编辑器中重建 MF_CF_Paint 和 MF_CF_DirtAmount。Crushform.RebakeDirtOrder 可手动执行相同的操作。
烘焙器只能从 ini 文件的文本中看到设置对象中的软引用。在设置构造函数中设定的默认值无法被它看到。因此插件会手动添加 Crushform 设置对象所软引用的每个包。这包括图集、默认配置文件、路面资产、污垢集合和外观函数。它对插件运行时模块的每个设置类都这样处理,并读取类默认值(构造函数在其中放置默认值)。仅由编辑器专用属性引用的包不会被添加。
其效果是:即使没有任何地图使用,设置所指向的外观或图集也会进入游戏。
UCFContentLibrary 是上述构建器和接线的底层库。它位于 CrushformEditor 模块中,因此仅存在于编辑器中。其函数均为静态函数,位于 Crushform|Content 分类下:Python 和编辑器工具蓝图会调用它们。该库有 24 个可供蓝图调用的函数。以下为上文未涵盖的函数:
| 函数 | 作用 |
|---|---|
WireGlassMaterial | 将半透明玻璃材质的 Base Color、Opacity、Roughness 和 Normal 经由 MF_CF_GlassCrack 连接,并保留原有的数据来源。World Position Offset 保持不变。玻璃使用此调用而非 WireMaterial,且玻璃材质不会获得漆面函数。若材质使用材质属性、世界空间法线,或使用缺少引脚的函数,则会被拒绝。在 /Crushform/ 和 /Engine/ 之外,它随后会获得项目的玻璃外观。 |
ApplyLooks | 通过外观接线,将项目的三种外观分别应用到材质中各自目标的内置调用上。设置为空时会将该外观移除。WireMaterial 和 WireGlassMaterial 在结尾调用它,Crushform.RewireLooks 为每个已保存材质调用它。/Crushform/ 和 /Engine/ 中的材质保持不变。 |
RepointFunctionCalls | 将材质中某个函数的每次调用指向另一个函数,并按引脚名称保留连接。返回被更改的调用次数。用于将材质从其自己的轮胎函数迁移到 MF_CF_TireDeform。 |
BuildVehiclePaintMaterial | 重建车身的清漆母材质 M_CF_VehiclePaint。它不会接入 Crushform:请接着调用 WireMaterial。 |
BuildWheelMaterial | 重建 M_CF_Wheel,World Position Offset 中为 MF_CF_TireDeform,颜色、粗糙度和金属度上为 MF_CF_WheelDirt。 |
BuildGlassShardMaterial | 重建 M_CF_GlassShard:半透明、双面、边缘更亮的透明玻璃。 |
BuildGlassShards | 用一块碎片瓦片填充玻璃定义的碎片,每个碎片取自一个静态网格列表。玻璃页面介绍了碎片。 |
BuildGlassShardMesh | 将静态网格重建为一个玻璃碎片:1 cm 厚的凸多边形板,有 3 到 7 个角,宽约 100 cm,带盒体碰撞。相同的 Seed 生成相同的碎片。 |
BuildDirtLook | 添加 MPC_CF_Dirt 缺少的污垢外观参数,并使用其默认值。它从不更改已存在的参数,因为其值是项目的调节结果。未被任何污垢函数读取的参数会在警告中被指出。 |
SetSkinnedSectionDisabled | 在某个 LOD 中关闭或开启骨骼网格的一个分段,效果与网格编辑器中 Disable 复选框的结果相同。 |
GetAtlasPath、GetDirtAtlasPath、GetDirtFreshAtlasPath、GetScratchAtlasPath、GetDirtLookPath | 按项目设置返回晶格图集、污垢图集、新鲜污垢图集、划痕图集和污垢外观集合的完整包名。 |
GetDefaultAtlasSize | 与项目槽位尺寸一致的图集大小,即 4 乘 32 个槽位。 |
库中的其他函数是上文各节所述的构建器和接线函数。
检查是否正常工作
Section titled “检查是否正常工作”- 在 Material Editor 中打开已接线的车身材质。
MF_CF_Deform调用为 World Position Offset 和 Normal 提供数据,MF_CF_Paint为 Base Color、Roughness 和 Metallic 提供数据。 - 更改偏移量后运行
Crushform.RebakeOffsets。提示会告诉你保存 Crushform 材质函数。保存它们,然后重新打开其中一个并检查其引脚。 - 在 Play In Editor 中,用
Crushform.DebugImpact撞击车身。凹陷会在材质中显示,漆面会在被刮擦处磨损。
污垢外观被拒绝
Section titled “污垢外观被拒绝”原因。 该外观没有 Base Color 输出,或者它有一个无引脚可以提供数据的输入。日志会指明是哪一个:
WireLook: %s has the input "%s", which nothing can feed; name it after a pin of %s or %s, or tick Use Preview Value As Default解决。 将该输入重命名为与某个引脚一致,或在其上勾选 Use Preview Value As Default。然后重新为材质接线。
更改偏移量后玻璃板的裂纹不正确
Section titled “更改偏移量后玻璃板的裂纹不正确”原因。 MF_CF_GlassCrack 或 MF_CF_GlassCrackData 的重建未被保存,因此材质仍读取旧索引。或者玻璃偏移现在与形变数据块重叠:重建被拒绝并记录在日志中,该函数保留其旧索引。
解决。 保存 Crushform 材质函数。如果日志指出了重叠,请移动 GlassCustomDataOffset,使其 16 个浮点数与形变数据块不重叠,如上文的自定义基元数据表所示。
外观未应用到材质
Section titled “外观未应用到材质”原因。 材质未保存,或者它位于 /Crushform/ 或 /Engine/ 中,插件会保持这些材质不变。该外观也不会应用到你自己的材质函数内部的调用上。
解决。 保存材质,然后运行 Crushform.RewireLooks。请将调用放在材质本身中,而不是你自己的函数里。