资产生成
从 .dsm / .dsf / .dsh 到 UMaterial / UMaterialFunction 的生成流程。
DreamShaderLang 的编译目标是 Unreal 资产,而不是传统字节码或可执行文件。一次生成通常从 .dsm 开始,解析 import graph,生成材质节点、Custom 节点、材质函数和相关元数据。
生成流程
.dsm / .dsf
├─ import .dsf / .dsh / Package
├─ 解析顶层声明
├─ 解析 Properties / Settings / Outputs / Graph
├─ 生成或复用 UMaterial / UMaterialFunction
├─ 清理旧表达式
├─ 创建参数节点、UE.* 节点、Graph 节点和 Custom 节点
├─ 连接输出
├─ 应用 Settings
└─ 保存资产并写入源文件元数据.dsm 与 .dsh
| 文件 | 生成行为 |
|---|---|
.dsm | 可以生成 UMaterial、Material Layer 函数资产,也可以生成或声明材质函数。 |
.dsf | 用于生成可复用 ShaderFunction 资产,并可被 .dsm 或其他 .dsf 导入。 |
.dsh | 不直接生成 Shader / ShaderFunction 资产,可作为共享依赖并声明 VirtualFunction。 |
保存 .dsh 时,DreamShader 会通过 import graph 找到受影响的 .dsm / .dsf 并刷新。
资产路径
Name 使用 Root 下的相对 package 风格路径。Root 可省略,默认是 Game:
Shader(Name="DreamMaterials/M_Sample", Root="Game")生成:
/Game/DreamMaterials/M_Sample.M_Sample生成到项目内容插件时,使用 Plugin.PluginName:
Shader(Name="DreamMaterials/M_Sample", Root="Plugin.MyPlugin")生成:
/MyPlugin/DreamMaterials/M_Sample.M_Sample物理保存位置是:
[Project]/Plugins/MyPlugin/Content/DreamMaterials/M_Sample.uasset插件目标需要位于项目 Plugins 目录、已启用、可包含内容且存在 Content 目录,否则生成器会报错。
Plugins.MyPlugin / Plugins/MyPlugin 也作为兼容写法支持,解析结果与 Plugin.MyPlugin 相同。
如果同路径已有资产:
| 情况 | 行为 |
|---|---|
已有 UMaterial,当前生成 Shader | 复用并更新。 |
已有 UMaterialFunction,当前生成 ShaderFunction | 复用并更新。 |
| 已有其他类型资产 | 报错,避免覆盖不兼容资产。 |
节点生成
| 语言元素 | Unreal 生成结果 |
|---|---|
| 标量 property | UMaterialExpressionScalarParameter |
| 向量 property | UMaterialExpressionVectorParameter |
| 纹理 property | UMaterialExpressionTextureObjectParameter |
VolumeTexture / Texture3D property | Volume Texture Object Parameter,并使用 VolumeTexture 默认资源或显式 Path(...)。 |
| 显式 Parameter property | 对应的 Unreal 参数节点,例如 Scalar / Vector / Texture Sample / Static Bool / Static Switch |
UE.CollectionParam | UMaterialExpressionCollectionParameter |
StaticSwitchParameter 调用 | UMaterialExpressionStaticSwitchParameter |
UE.TexCoord | UMaterialExpressionTextureCoordinate |
UE.Time | UMaterialExpressionTime |
UE.Panner | UMaterialExpressionPanner |
| 算术表达式 | Add / Subtract / Multiply / Divide 节点 |
| Swizzle | ComponentMask / AppendVector |
Function 调用 | Custom 节点 |
ShaderFunction 调用 | MaterialFunctionCall 节点 |
VirtualFunction 调用 | 指向已有资产的 MaterialFunctionCall 节点 |
if / else | Material If 节点 |
Properties 声明尾部的分号式 [...] 属性块会按 Unreal MaterialExpression 的 UPROPERTY 名称反射写入生成节点。Group、SortPriority 和 Description 是常用别名,其中 Description 会写到节点 Desc。材质函数 pin 当前主要使用 description 和 sort priority;Unreal Function Input / Output 本身没有分组字段。
ShaderFunction 的 Properties 会在创建 FunctionInput 之前生成,因此 Inputs 的预览默认值可以引用这些 property/helper 节点。ShaderFunction / VirtualFunction 输入前的 opt 会映射到 FunctionInput 的“使用预览值作为默认值”语义。调用侧传入 default 或省略尾部可选输入时,生成器不会连接该输入 pin,让 Unreal 使用预览默认值。
VirtualFunction 资产引用
VirtualFunction 不创建新资产,而是通过 Options.Asset 加载已有 UMaterialFunction:
VirtualFunction(Name="BufferWriter")
{
Options = {
Asset = Path(Plugins.MoonToon, "MaterialFunctions/Buffer/Writer");
}
Inputs = {
float3 Color;
float Alpha;
}
Outputs = {
float3 Result;
}
}Path(Plugin.MoonToon, "...") / Path(Plugins.MoonToon, "...") 会解析到插件挂载根 /MoonToon,对应物理内容目录 [Project]/Plugins/MoonToon/Content。生成 Graph 时,DreamShader 会创建 MaterialFunctionCall 节点并连接到这个已有资产。
Function 生成
普通 Function:
Function ApplyTint(in vec3 color, in vec3 tint, out vec3 result) {
result = color * tint;
}生成行为:
- 函数代码写入生成
.ush。 - Graph 调用时创建 Custom 节点。
- Custom 节点 include 生成
.ush。 - Custom 节点调用 DreamShader 生成的安全函数符号。
SelfContained / Inline 函数会尽量把依赖代码嵌入 Custom 节点。
Source hash 缓存
生成资产会写入元数据:
DreamShader.SourceFile
DreamShader.SourceHash
DreamShader.GeneratedAtUtc如果源文件 hash 没变化,生成器可以跳过重复生成。这让保存、扫描和全量重编更轻。
材质重置
更新已有材质时,DreamShader 会清理旧表达式并重置常见材质属性,再根据当前 Settings 重新应用。这样删除某个旧 setting 后,不容易留下资产上的历史状态。
反编译导出
DreamShader 插件提供 Content Browser 导出入口:
| Unreal 资产 | 导出结果 |
|---|---|
UMaterial | DShader/Decompiled/Materials/*.dsm |
UMaterialFunction | DShader/Decompiled/Functions/*.dsf |
反编译器会尽量把常见常量、参数、算术节点、swizzle、纹理采样、Custom 节点和 MaterialFunctionCall 导出为 DreamShader Graph 文本。少见或尚未专门建模的 MaterialExpression 会回退到 UE.Expression(...),以保留可继续生成的结构。
如果材质图中已有注释框和节点区域,导出时会尽量生成 #Region 和 Layout = { ... }。这适合把手工材质迁移到文本源文件,但目前还不是完整稳定的双向往返系统。