DreamShaderLang
内置节点

通用 UE.Expression

按类名创建任意 UMaterialExpression 的通用反射调用,以及它的参数规则。

已注册内置节点只覆盖了 Unreal 数百个材质表达式中的 27 个。UE.Expression 是其余部分的逃生舱:它按名字创建任意非抽象的 UMaterialExpression 子类,并用命名参数填充它的输入 pin 和 UPROPERTY。

float pulse = UE.Expression(Class = "Sine", OutputType = "float1", Input = UE.Time());

还有一种更短的写法。Class 默认取函数名,所以 UE.Sine(…) 和 UE.Expression(Class = "Sine", …) 是同一个实现里的同一个调用:

float pulse = UE.Sine(OutputType = "float1", Input = UE.Time());

Expression 这个名字并不特殊,唯一的特别之处是它永远解析不出一个类 —— 这正是第一种写法必须写 Class= 的原因。

UE.Expression( Class = <class-specifier> , { OutputType | ResultType } = <type-token>
               [, { { Output | OutputName } = <text> | OutputIndex = <int> } ]
               [, <arg-name> = <expression> ] … )

UE.<ClassName>( { OutputType | ResultType } = <type-token> [, <arg-name> = <expression> ] … )
记号含义示例
<x>占位符——替换成实际内容,尖括号本身不写出来。Name = <string>
[ x ]可选——整段可以整体省略。[, Root = <string>]
{ a | b }多选一——从竖线分隔的写法里取其中一个。{ Node( … ) | Comment( … ) }
…可重复——前一项可以出现任意多次。<property-declaration> …

所有参数都必须是命名参数。位置参数会失败: Generic {Namespace}.{Function} calls require named arguments. 文本参数可以带引号也可以不带: Class = Sine 与 Class = "Sine" 相同,OutputType = float3 与 OutputType = "float3" 也相同。

和已注册内置节点不同,这条路径会校验每一个参数名。既匹配不上 pin 也匹配不上属性的名字是错误, 而不是被静默丢弃。

类解析

Class 必须是字面量 —— 带引号的字符串、裸标识符或带点的名字。说明符会先去掉首尾空白,然后按下列规则解析:

#规则
1去空白后为空 → 解析失败
2文本中含 / 或 . 时,直接按 object path 加载,且只有加载出的类派生自 UMaterialExpression 才接受 —— Class = "/Script/Engine.MaterialExpressionSine"
3否则构建候选名列表,见下
4扫描所有已加载的 UClass;第一个派生自 UMaterialExpression、非抽象、且名字忽略大小写等于任一候选名的类胜出

对说明符 S 的候选名:

候选名加入条件
S总是
U + SS 不以 U 开头
MaterialExpression + SS 不以 MaterialExpression 开头
UMaterialExpression + SS 不以 UMaterialExpression 开头

前缀判断和最终比较都不区分大小写。

不要写 U 前缀。 扫描比较的是反射类名,而反射名不带 U。UMaterialExpressionSine 的反射名是 MaterialExpressionSine,因此任何以 U 开头的说明符 —— USine、UMaterialExpressionSine —— 永远匹配不上,上表中两行带 U 前缀的候选名在实践中根本无法命中。

能解析到 UMaterialExpressionSine 的写法是 Sine、sine、任意大小写的 MaterialExpressionSine, 以及 object path /Script/Engine.MaterialExpressionSine。

扫描只覆盖已加载的类。位于编辑器尚未加载的插件模块中的表达式类找不到,调用会以 UE.{Function} could not resolve MaterialExpression class '{Class}'. 失败。抽象类即使名字完全匹配 也会被跳过。

在 Substrate.* 路径上,类由内置描述符固定,Class= 会被直接拒绝。

解析顺序

调用按下列顺序处理。这个顺序是可观察的,因为只有第一个失败的步骤会被报出来。

#步骤失败消息
1拒绝位置参数Generic {Namespace}.{Function} calls require named arguments.
2Substrate.* 描述符查找与引擎版本门槛见 Substrate
3解析 OutputType / ResultTypeUnsupported UE builtin call …、… OutputType must be a literal value.、… OutputType '{Token}' is not supported.
4解析 Class… Class must be a literal value.、UE.Expression requires Class="MaterialExpressionName".、… could not resolve MaterialExpression class '{Class}'.
5拒绝 Output/OutputName 与 OutputIndex 同时出现… cannot use OutputName/Output together with OutputIndex.
6查节点复用缓存—
7创建节点UE.{Function} failed to create '{Class}'.
8UMaterialExpressionCustom 初始化… OutputType="Substrate" is not supported by UMaterialExpressionCustom. 等
9把剩余参数分派到 pin、属性或 Custom 输入… '{Argument}' is not a property on '{Class}'.
10合成 Custom 节点的输出… OutputName must be a non-empty literal value.
11解析输出索引… OutputIndex is out of range …、… output '{Name}' was not found …
12在材质上注册 static switch / static component mask 参数—
13推导结果类型和分量数{Namespace}.{Function} output is not a Substrate value.
14组装结果并写入复用缓存—

完全不带参数的 UE.Expression() 报的是 OutputType 错误,而不是缺少 Class —— 因为步骤 3 在步骤 4 之前。

OutputType

OutputType(别名 ResultType,只在没写 OutputType 时才会被读取)在这条路径上是必需的。 不写会得到:

Unsupported UE builtin call '{Function}' in Graph. For generic MaterialExpression calls, add OutputType="float1/2/3/4/Texture2D/TextureCube/Texture2DArray/VolumeTexture/Substrate".

这条提示里列了九种写法。实际接受的集合有 44 个 token。

对生成器能识别的类来说,OutputType 只是建议值。Substrate、MaterialAttributes 和纹理输出会从 节点真实的输出值类型重新推导,已知宽度表里的类也是如此 —— 这就是为什么 UE.Expression(Class = "WorldPosition", OutputType = "float1") 仍然得到 3 分量的值。

对其他所有类,声明的 token 就是宽度,不管节点真实的输出类型是什么。在 Custom 节点上,这个 token 的权威性更强:它会被写入节点,并决定 HLSL 的返回类型。

接受的 token

全部 token 及其在各个使用面上的可用性。匹配全程不区分大小写。

Token类别分量数通用 UE.*Custom 节点property 声明
float数值1✔✔✔
float1数值1✔✔✔
half数值1✔✔✔
half1数值1✔✔✔
int数值1✔✔✔
uint数值1✔✔✔
bool数值1✔✔✔
float2数值2✔✔✔
half2数值2✔✔✔
vec2数值2✔✔✔
int2数值2✔✔✔
uint2数值2✔✔✔
bool2数值2✔✔✔
ivec2数值2✔✔✔
uvec2数值2✔✔✔
bvec2数值2✔✔✔
float3数值3✔✔✔
half3数值3✔✔✔
vec3数值3✔✔✔
int3数值3✔✔✔
uint3数值3✔✔✔
bool3数值3✔✔✔
ivec3数值3✔✔✔
uvec3数值3✔✔✔
bvec3数值3✔✔✔
float4数值4✔✔✔
half4数值4✔✔✔
vec4数值4✔✔✔
int4数值4✔✔✔
uint4数值4✔✔✔
bool4数值4✔✔✔
ivec4数值4✔✔✔
uvec4数值4✔✔✔
bvec4数值4✔✔✔
MaterialAttributesmaterial attributes0✔✔✘
SubstrateSubstrate0✔ since UE 5.4✘✘
StaticBool数值1✔✘✘
StaticBoolParameter数值1✔✘✘
Texture2D纹理对象 —— 2D0✔✘✔ †
SamplerState纹理对象 —— 2D0✔✘✘
TextureCube纹理对象 —— cube0✔✘✔ †
Texture2DArray纹理对象 —— 2D array0✔✘✔ †
Texture3D纹理对象 —— volume0✔✘✔ †
VolumeTexture纹理对象 —— volume0✔✘✔ †

† 在 property 声明这个使用面上,五个纹理 token 解析成同一种声明类别 —— 0 分量的纹理对象 property, 维度不会被记录。这和 Graph 使用面不同,那里 TextureCube 和 Texture2DArray 会产生类型不同的值。 维度要紧时请用普通类型 token 声明(TextureCube Tex;),参见类型与值。

SamplerState 只在 Graph 使用面上是 Texture2D 的可接受写法。StaticBool 和 StaticBoolParameter 都解析为 1 分量值;它们存在只是为了让值能与 StaticBool 函数输入做类型检查,除此之外和 float 没有区别。

归一化

token 的归一化并不统一 —— 用了三种不同的比较方式,当 token 带多余空白时差异是可观察的。

token 组比较方式
34 个数值 token 和 MaterialAttributes去首尾空白、转小写,并去掉所有内部空格
Substrate去首尾空白并去掉内部空格,忽略大小写比较
StaticBool、StaticBoolParameter、Texture2D、SamplerState、TextureCube、Texture2DArray、Texture3D、VolumeTexture忽略大小写,与书写原样比较 —— 不去空白,也不去空格

所以在 Graph 使用面上 OutputType = " float4 " 能解析,OutputType = " Texture2D " 不能。 这只有通过带引号的字面量才会碰到 —— 裸 token 里不可能有空白。在 property 声明使用面上值会先去空白再解析, 所以那里不存在这种不对称。下划线和连字符永远不会被去掉:float_4 和 Material-Attributes 都不是可接受的写法。

归一化后的 token 也参与节点复用键。两个只在 OutputType 写法上不同的调用 —— float3 与 vec3 —— 会构成不同的键,因此产生两个节点,尽管得到的值完全一样。

参数分派

有六个参数名是保留的,永远不会分派给节点:

保留名用途
Class类说明符
OutputType声明的输出类型
ResultTypeOutputType 的别名
Output按名字选择输出
OutputNameOutput 的别名
OutputIndex按索引选择输出

其余每个参数按下列顺序对创建出的节点解析,第一个匹配上的胜出。

#判断结果
a归一化后的参数名等于节点某个输入 pin 的归一化名字把表达式连到该 pin
b归一化后的参数名等于该类或任意父类上某个反射 FProperty 的归一化名字属性是表达式输入结构体则走 pin 路径,否则走字面量路径
c节点是 UMaterialExpressionCustom新建一个按书写原样命名的 Custom 输入 pin
d—UE.{Function}: '{Argument}' is not a property on '{Class}'.

同名时输入 pin 优先于反射属性。 好几个引擎表达式两者都有 —— 一个叫 Input 的 pin 和一个相关名字的 UPROPERTY —— 而 pin 总是赢。被 pin 名遮蔽的属性没有别的写法可以触达;只能用属性真正的 UPROPERTY 名字,那正是第二遍匹配所比较的东西。

属性匹配分两遍:

遍次匹配说明
1任何名字在去空白转小写后等于参数名的 FProperty不限于可编辑属性 —— private 和非 EditAnywhere 的 UPROPERTY 也能触达
2仅 FBoolProperty:属性名转小写后去掉开头的 bFractionalPart 就是这样触达 bFractionalPart 的

第二遍是先转小写再去掉开头的 b,而且会对任意 bool 属性做这件事。所以名为 bTangent 的 bool 属性也能用 Tangent 触达,名为 BaseColor 的 bool 属性也能用 aseColor 触达。只有 bool 属性受影响。 两个属性在这些规则下冲突时,第一遍先跑,因此第一遍胜出。

输入 pin

解析到 pin 的参数 —— 无论是通过 pin 名,还是通过类型为表达式输入结构体(FExpressionInput, 或名为 MaterialAttributesInput 的结构体)的属性 —— 其值会作为 Graph 表达式求值并连接。 值携带的通道掩码会一并传递到连接上。

随后会用 pin 声明的值类型检查这个值:

pin 类型值结果
Substrate非 Substrate{Namespace}.{Function} input '{Pin}' expects a Substrate value.
MaterialAttributes非 attributes{Namespace}.{Function} input '{Pin}' expects a MaterialAttributes value.
数值Substrate{Namespace}.{Function} input '{Pin}' does not accept Substrate values.
数值MaterialAttributes{Namespace}.{Function} input '{Pin}' does not accept MaterialAttributes values.
其他任意连接成功

pin 上不做宽度检查:把 float4 连到标量 pin 是引擎要处理的问题,不是 DreamShader 的。

字面量属性

其他匹配上的属性都用字面量写入。对象类型的属性按资产引用读取,其余按字面文本读取。

属性类型接受的值语法失败消息
FBoolPropertytrue / false,不区分大小写'{Value}' is not a valid boolean value for '{Property}'.
FIntProperty十进制整数'{Value}' is not a valid integer value for '{Property}'.
FUInt32Property0 … 4294967295 范围内的整数'{Value}' is not a valid unsigned integer value for '{Property}'.
FFloatProperty任意数值字面量'{Value}' is not a valid numeric value for '{Property}'.
FDoubleProperty任意数值字面量'{Value}' is not a valid numeric value for '{Property}'.
FStrProperty去空白后的文本,原样写入 —— 永远成功—
FNameProperty去空白后的文本作为 FName —— 永远成功—
FObjectPropertyBasePath(…) 或绝对 Unreal object path见对象属性
FEnumProperty见枚举值'{Value}' is not a valid enum value for '{Property}'.
由枚举支撑的 FByteProperty见枚举值'{Value}' is not a valid enum value for '{Property}'.
无枚举的 FByteProperty0 … 255 范围内的整数'{Value}' is not a valid byte value for '{Property}'.
其他 —— 结构体、数组、set、mapUnreal 自己的导入文本,例如 (R=1,G=0,B=0,A=1)、(X=1,Y=2,Z=3)Property '{Property}' on '{Class}' is not a supported literal type yet.

这些消息都会再包一层:UE.{Function} property '{Property}': {Message}。

FStrProperty 和 FNameProperty 永远不会失败。参数携带的任何文本 —— 包括拼错的枚举名或解析不了的 路径 —— 都会被原样存下来。既不报诊断,也不回退到默认值。

枚举值

枚举值会以四种写法与该枚举的每个非隐藏条目比较。比较前双方都转小写,并去掉空格、_、-、:、.、/ 这些字符。

#参与比较的写法
1条目短名 —— PPI_PostProcessInput0
2条目完全限定名 —— ESceneTextureId::PPI_PostProcessInput0
3条目显示名
4短名去掉第一个 _ 及其之前的全部内容 —— PostProcessInput0

规则 4 正是不带前缀的写法能生效的原因,也是 UE.SceneTexture 所依赖的机制。

对象属性

对象类型的属性接受 Path(<root>, "<asset>")、Path("/Game/…") 或裸的绝对 object path。参见 Path 资产引用。

情况结果
参数既不是字面量也不是 Path(…) 调用UE.{Function} property '{Property}' must use Path(...) or an Unreal object path.
文本以 Path( 或 / 开头但解析不了报解析器自己的消息
文本是字面量、不是资产引用、也不以上述两者开头Object property '{Property}' expects Path(...) or an absolute Unreal object path.
资产加载失败,且属性是名为 Texture 或 TextureObject 的 UTexture 属性属性被设为 null,并算作成功
资产加载失败,其他属性Failed to load asset '{Path}' for '{Property}'.
资产加载成功但类型不对Asset '{Path}' is not compatible with '{Property}'. Expected '{Class}'.

失败置空这条规则是静默的。

UE.Expression(Class = "TextureSample", OutputType = "float4",
              Texture = Path(Game, "Missing/T_Nope"))

会带着一个未赋值的纹理编译通过,而不是报告资产缺失。只有 UTexture 类型属性上的 Texture 和 TextureObject 这两个名字会这样。

选择输出

多输出的节点通过两个互斥的选择器之一读取。两个都写是错误;都不写则选择 output 0。

参数别名类型语义
OutputOutputName文本字面量先按名字解析,再按掩码伪名解析
OutputIndex—≥ 0 的整数直接索引节点的输出

按名字解析时会按顺序遍历所有输出:

输出匹配方式
有名字的输出按 FName 比较名字 —— 不区分大小写
无名字的输出用下面的掩码伪名按顺序与输出的通道掩码比较

说明符会去掉首尾空白;空说明符选择 output 0。

伪名匹配掩码为下列内容的无名输出
RGR 和 G
RGBR、G 和 B
RGBAR、G、B 和 A
R仅 R
G仅 G
B仅 B
A仅 A

这些不是 OutputType 的取值,OutputType 的 token 也永远不是合法的 Output 选择器。 UE.Expression(Class = "BreakMaterialAttributes", OutputType = "float3", Output = "BaseColor") 是按输出名字选择;Output = "RGB" 是按掩码选择。

Custom 节点

UMaterialExpressionCustom 是唯一被专门处理的类 —— 它是把原始 HLSL 塞进 Graph 的方式。

方面行为
OutputType = "Substrate"拒绝 —— UE.{Function} OutputType="Substrate" is not supported by UMaterialExpressionCustom.
其他 OutputType 值必须能映射到 Custom 输出类型;Texture2D、SamplerState、TextureCube、Texture2DArray、Texture3D、VolumeTexture、StaticBool 和 StaticBoolParameter 在别处是合法 OutputType,但在这里不是
声明的 OutputType权威 —— 会写入节点,并决定 HLSL 的返回类型
未匹配的参数变成按书写原样命名的新 Custom 输入 pin;Substrate 值会被拒绝:UE.{Function} Custom input '{Name}' does not accept Substrate values.
新建节点应用参数之前会清空它的 Inputs 和 AdditionalOutputs 数组
OutputName必须是非空字面量,并意味着请求附加输出索引 1
缺少的附加输出会合成名为 Output1、Output2… 的占位输出直到请求的索引,然后重建节点的输出
结果宽度取自节点真实的输出值类型,所以次要输出的尺寸是对的
节点复用禁用 —— 每次 Custom 调用都新建节点
float3 tinted = UE.Expression(Class = "Custom", OutputType = "float3",
                              Code = "return In * 0.5f;",
                              In   = baseColor);

结果类型与分量数

结果按下列顺序从解析出的输出的真实值类型推导。

#条件结果
1OutputType = "Substrate" 但实际输出不是 Substrate{Namespace}.{Function} output is not a Substrate value.
2实际输出是 Substrate0 分量,Substrate 值,权威
3实际输出是 MaterialAttributes0 分量,attributes 值,权威
4实际输出是任意纹理类型纹理对象,权威
5Substrate.* 工具类内置节点宽度取自输出的值类型
6Custom 节点宽度取自输出的值类型
7TextureCoordinate、Panner 或 Rotator2 分量
8其他查硬编码的已知宽度表,查不到则用声明的 OutputType

已知宽度表:

宽度类
2TextureCoordinate、Panner、ScreenPosition、Rotator、SceneTexelSize
3WorldPosition、ObjectPositionWS、CameraVectorWS、VertexNormalWS、VertexTangentWS、Transform、TransformPosition、SkyAtmosphereLightDirection、PixelNormalWS、CrossProduct
1PixelDepth、TwoSidedSign、Arctangent2Fast、Length、MaterialXLuminance

另有五个类的宽度由实际连到输入上的值决定:

类宽度
Saturate所连 Input 的宽度
StaticSwitchParameter所连 True 和 False 中较大的一个
If所连 AGreaterThanB、AEqualsB、ALessThanB 中最大的一个
StaticComponentMaskParameter已设置的 DefaultR/DefaultG/DefaultB/DefaultA 个数,最小 1
CurveAtlasRowParameter所选输出掩码的通道数,最小 1

分量数为 0、又不是纹理也不是 Substrate 的结果,就是 MaterialAttributes 值。参见 类型与值。

对材质的副作用

有两个类通过这条路径创建时会被注册为材质参数,因而出现在材质实例编辑器里:

类注册内容
带参数名的 UMaterialExpressionStaticSwitchParameter材质或材质函数上的「仅编辑器」静态开关值
UMaterialExpressionStaticComponentMaskParameter「仅编辑器」静态通道掩码值,取自节点的四个默认通道

两者的 expression GUID 无效时都会被重新分配一个。

节点复用

这条使用面是会去重的。每次调用会构建两个缓存键:

键内容
表达式键所有非保留参数,加上解析出的类名和归一化后的 OutputType 文本
输出键表达式键加上输出选择器(OutputName=…、OutputIndex=…,或 OutputIndex=0)

输出键命中会直接返回上一次的结果。表达式键命中会复用节点、只重新解析输出 —— 这正是一个多输出节点 可以用不同 Output= 选择器服务两次读取的原因。键中的字面文本会做归一化:合并连续空格、统一换行符。 UMaterialExpressionCustom 的子类从不参与复用。

节点被复用时,它的输入和属性参数不会重新应用。这在语言层面观察不到 —— 参数本来就是键的一部分, 被复用的节点必然是用同样的参数构建的 —— 但这确实意味着一个节点会对应源码中的多个调用点。

与之相对,已注册内置节点完全不查缓存,每次调用都新建节点。

SampleTexture2D

float4 texel = SampleTexture2D(BaseTex, uv);

一个保留的双参数形式,在用户 property 和函数之前解析,且区分大小写 —— sampletexture2d(t, uv) 不是它。它会被改写成

UE.Expression(Class = "TextureSample", OutputType = "float4",
              TextureObject = <arg0>, Coordinates = <arg1>)

两个参数都是位置参数,且都必需: SampleTexture2D expects exactly two positional arguments: (textureObject, uv).

如果要采样已声明的纹理参数,优先用参数自己的 pin 调用形式 —— BaseTex(Coordinates = uv) —— 它会复用参数节点,而不是新建一个普通的 TextureSample。参见 Properties 类型。

声明形式

通用的 UE.<Name>(…) 也可以作为 property 类型出现在 Properties section 中, 声明形式目录之外的名字都由同一套反射机制创建。 它的规则和 Graph 形式不同:

方面声明形式Graph 形式
OutputType / ResultType必需,取自缩减 token 集必需,取自完整集合
Class默认取内置节点名,可覆盖相同
输入 pin 名匹配不执行 —— 只匹配反射属性优先执行
未匹配的参数Custom 节点上变成 Custom 输入,否则 '{Argument}' is not a property on '{Class}'.相同
输入值先前声明的 property、标量字面量,或 2–4 分量向量字面量任意 Graph 表达式
ParameterName类暴露了该属性且作者没写时,自动取 property 名从不设置
输出选择Output / OutputName / OutputIndex;Custom 占位输出的合成方式相同相同
元数据 [ … ]创建后应用到节点上不适用
节点画布 X-800520
Properties {
    UE.Expression(Class = "ObjectRadius", OutputType = "float1") Radius;
}

这个使用面额外的消息:

消息原因
Unsupported vector literal '{Value}'.输入字面量不是 2–4 个数值分量
Failed to create a scalar constant expression.标量输入字面量的常量节点创建失败
Failed to create a float{N} constant expression.向量输入字面量的常量节点创建失败
'{Value}' is not a valid property reference or literal input.输入值既不是已声明的 property 也不是字面量
'{Class}' does not expose a ParameterName property.在没有该属性的类上写了 ParameterName 元数据
OutputIndex is out of range for '{Class}'.所选索引不存在

通常写在 Graph 里更清晰,因为输入关系在调用点就能看见。

一些值得知道的细节

  • 属性名是扁平的。这里不接受带点的路径和 [index] 选择器,那些只存在于 材质 Settings 中,那是另一个解析器。
  • 没有办法故意让引擎的必需 pin 保持未连接,也没有办法断开一个 pin。参数要么连一个值,要么不写。
  • 因为 Class 默认取函数名,类名写错时报的是 could not resolve MaterialExpression class 而不是「未知内置节点」。UE.Sinee(OutputType="float1") 和 UE.Expression(Class="Sinee", OutputType="float1") 报的是同一条消息。
  • 通用调用可以像任何表达式一样 swizzle: UE.Expression(Class = "VertexColor", OutputType = "float4").rgb。
  • 编辑器会把反射出的表达式清单导出到 Saved/DreamShader/Bridge/material-expressions.json,其中列出每个可解析类及其 pin 和属性。 这是查参数名最实用的办法 —— 参见编辑器工具。

诊断

{Function} 保留作者书写的名字和大小写;{Namespace} 就是字面上的 UE 或 Substrate。

消息触发原因处理
Unsupported UE builtin call '{Function}' in Graph. For generic MaterialExpression calls, add OutputType="float1/2/3/4/Texture2D/TextureCube/Texture2DArray/VolumeTexture/Substrate".既没写 OutputType 也没写 ResultType。补上 OutputType。注意实际接受的集合远大于提示里的九种写法。
UE.Expression requires Class="MaterialExpressionName".函数名字面上就是 Expression,却没有给 Class。
UE.{Function} could not resolve MaterialExpression class '{Class}'.没有已加载的非抽象 UMaterialExpression 子类匹配上任何候选名。去掉 U 前缀 —— 写 Sine,不要写 USine 或 UMaterialExpressionSine。并确认该类所在模块已加载。
UE.{Function} OutputType '{Token}' is not supported.token 不在 44 个之列。
UE.{Function} OutputType must be a literal value.值是表达式而不是字面量。
Generic {Namespace}.{Function} calls require named arguments.通用路径上出现了位置参数。所有参数都写名字。只有已注册内置节点和数学内置接受位置参数。
UE.{Function}: '{Argument}' is not a property on '{Class}'.参数既匹配不上输入 pin 也匹配不上反射属性。在 Saved/DreamShader/Bridge/material-expressions.json 里查 pin 名和属性名。
UE.{Function} input '{Pin}': {Message}连到 pin 上的值求值失败。
UE.{Function} property '{Property}': {Message}字面量无法转换成属性的类型。
UE.{Function} property '{Property}' must use Path(...) or an Unreal object path.对象属性的值既不是字面量也不是 Path(…) 调用。详解
UE.{Function} cannot use OutputName/Output together with OutputIndex.两个输出选择器都写了。
UE.{Function} output '{Name}' was not found on '{Class}'.既没有同名输出,也没有匹配上掩码伪名。
UE.{Function} OutputIndex is out of range for '{Class}'.索引为负、不是整数,或超出节点输出数量。
UE.{Function} created '{Class}', but it has no material outputs.节点没有暴露任何输出。
UE.{Function} failed to create '{Class}'.节点创建返回空。
UE.{Function} OutputType="Substrate" is not supported by UMaterialExpressionCustom.向 Custom 节点索要 Substrate 输出。详解
UE.{Function} OutputType '{Token}' is not a valid Custom node output type.在 Custom 节点上用了纹理或 static bool 类的 OutputType。
{Namespace}.{Function} output is not a Substrate value.在真实输出不是 Substrate 的节点上写了 OutputType="Substrate"。
SampleTexture2D expects exactly two positional arguments: (textureObject, uv).参数个数不对,或者用了命名参数。

完整清单见错误速查。

示例

Shader(Name="Docs/M_Generic")
{
    Properties {
        Texture2D BaseTex = Path(Game, "Textures/T_Noise");
        vec3      Dimmed  = vec3(0.2, 0.2, 0.2);
    }

    Settings { ShadingModel = "Unlit"; }

    Outputs {
        vec3 Color;
        Base.EmissiveColor = Color;
    }

    Graph {
        // Class 默认取函数名。
        float pulse = UE.Sine(OutputType = "float1", Input = UE.Time());

        // 显式 Class,以及不带前缀写法的枚举属性。
        float3 scene = UE.Expression(Class = "SceneTexture", OutputType = "float4",
                                     SceneTextureId = "PostProcessInput0").rgb;

        // 通过 Path(...) 写对象属性,并按 pin 名连接输入。
        float4 tex = UE.Expression(Class = "TextureSample", OutputType = "float4",
                                   Texture     = Path(Game, "Textures/T_Noise"),
                                   Coordinates = UE.TexCoord(Index = 0));

        // 宽度由所连输入决定的类。
        float3 sel = UE.Expression(Class = "StaticSwitch", OutputType = "float3",
                                   True = Dimmed, False = tex.rgb, Value = true);

        Color = (scene + sel) * pulse;
    }
}

生成的节点:

Time                                  -> Sine                       (pulse)
SceneTexture (PPI_PostProcessInput0)  -> mask .rgb                  (scene)
TextureCoordinate (Index 0)           -> TextureSample.Coordinates
TextureSample (Texture = T_Noise)                                   (tex)
Constant3Vector (0.2, 0.2, 0.2)       -> StaticSwitch.True
StaticSwitch  (Value = true)                                        (sel)
Add, Multiply                                                       (Color)

接下来

本页目录