DreamShaderLang
Graph 语言

调用

调用

调用

DreamShader » Graph » 调用

从 Graph 块中调用 Function、GraphFunction、ShaderFunction、VirtualFunction 或带输入的参数,既可以作为值表达式,也可以作为独立语句。

声明于.dsm, .dsf — 位于 Graph { … } 函数体或 Outputs 绑定表达式内部
种类表达式形式和语句形式
生成UMaterialExpressionCustom(Function、GraphFunction)、UMaterialExpressionMaterialFunctionCall(ShaderFunction、VirtualFunction)、UMaterialExpressionStaticSwitchParameter(静态开关调用),或参数自身的节点并接好其输入引脚(参数调用)

.dsm / .dsf 由 legacy 前端读取,由 2.0 绑定器绑定 (自 2.0.0 起)。本页的调用写法构建的节点和以前一样;1.x 调用与 .dss 调用读法不同的地方,由编号的 legacy 规则处理,并用自己的码说明。每种调用的 .dss 写法见 dsc migrate。

语法概要

// value form — the call produces a value
<target> = <callee> ( [ <argument> [ , <argument> ] … ] ) ;

// statement form — the call writes into named out variables
<callee> ( [ <input-argument> , ] … <out-target> [ , <out-target> ] … ) ;

<callee>         := <identifier> | <namespace> :: <identifier>
<argument>       := <expression> | <identifier> = <expression> | default
<out-target>     := <identifier>

( ) , = :: 和 default 是字面 DreamShaderLang 文本。[ … ]、{ a | b } 和 … 是元记号。在任何调用里,命名参数之后再出现位置参数都是 DSH2158 (自 2.0.0 起)。

可调用的种类

种类声明方值形式语句形式命名参数产生的节点
FunctionFunction支持——返回值,或第一个 out (自 2.0.0 起)支持支持 (自 2.0.0 起)Custom
GraphFunctionGraphFunction支持——同 Function (自 2.0.0 起)支持支持 (自 2.0.0 起)Custom
ShaderFunctionShaderFunction,位于同一文件支持,任意输出数支持支持MaterialFunctionCall
ShaderLayer、ShaderLayerBlendShaderLayer不可调用:DSH6208 (自 2.0.0 起)———
VirtualFunctionVirtualFunction支持,任意输出数支持支持MaterialFunctionCall
StaticSwitchParameter 属性Properties支持不支持支持StaticSwitchParameter
带输入的参数Properties支持不支持只能用命名参数该参数自身的节点,并完成配置

别的文件里的 ShaderFunction 要经由指向其资产的 VirtualFunction 调用:import 只引入 .dsh 头文件,而头文件里不放资产块。

UE.*、Substrate.*、数学内置、构造器和 SampleTexture2D 也使用调用语法,但它们会在上述任何种类之前被解析,并有单独的文档——见内置、数学内置和构造器。与数学内置同名的函数是 DSH6206 (自 2.0.0 起)。完整的分发顺序见名称解析。

被调方的写法

写法解析到
Name以该名字声明的函数,区分大小写比较 (自 2.0.0 起)。只在忽略大小写时恰好匹配一个函数的名字会解析到它,并警告 DSH5275
Namespace::Name声明在 Namespace(Name="Namespace") 内部的 Function / GraphFunction。解析器把 N::F 读成一个标识符 N_F,即函数声明所用的名字 (自 2.0.0 起),所以 N_F(…) 也能调用到它;裸的 F 不行。后面没有名字的 :: 是 DSH5260
DreamShaderFn_Name不再是函数的别名 (自 2.0.0 起):DSH4208
路径末段对声明为 Name="Functions/F_Tint" 的 ShaderFunction,取最后一个 / 之后的一段——F_Tint——其中不是字母、数字或 _ 的字符换成 _。VirtualFunction 的 Name 本身就必须是标识符(DSH6311)

没有重载。一个名字只声明一样东西:再声明一个同名的函数、属性或结构体是 DSH4210。例外是叶子名被它之前声明的函数(通常来自导入的头文件)占用的 ShaderFunction 块:块的函数改以 <Name>_Asset 声明,资产保留原名(提示 DSH5290)。只差大小写的两个名字是两个声明;拼法与两者都不同的调用就没有唯一的不区分大小写匹配,报 DSH4208。

值形式

float L = Luma(BaseColor);
vec3  C = Common::ApplyTint(BaseColor, Tint);
vec3  N = F_Normal(uv, Output="Normal");

(单输出 Function / GraphFunction 值调用自 1.3.1 起)

种类要求
Function、GraphFunction值是返回值;带 out 参数的函数则是它的第一个 out(legacy 规则 L3b)(自 2.0.0 起;1.x 拒绝对多输出函数做值调用)。其他输出用输出选择器读取。参数按声明顺序和名字填充参数:没有得到参数的输入是 DSH4217,超出最后一个参数的参数是 DSH4224。顺序也计入 out 参数:落在其上的参数接收那个输出,和语句调用一样。
ShaderFunction、VirtualFunction值是输出 0——第一个声明的输出——除非输出选择器选了别的 (自 2.0.0 起;1.x 在声明了多个输出时要求写选择器)。声明为 opt 的输入可以省略或传 default。

GraphFunction 调用和 Function 调用一样是一个 Custom 节点;从函数体里提出来的 UE. 调用成为该节点的更多输入,用这次调用的参数降级。

被调方相同、参数相同的调用是一个节点;见节点复用。

语句形式

F_PulseTint(BaseColor, Tint, TintedColor, PulseAmount);

(多输出 ShaderFunction / VirtualFunction 语句调用自 1.3.5 起)

调用语句可以调用任何东西。没人接收其值的调用——内置、构造器、参数——会被接受,它产生的节点因为没人读而被丢掉 (自 2.0.0 起;1.x 拒绝这样的语句)。既不是调用也不是赋值的表达式语句是 DSH2211(F(a).Out;、x;);x++; 是 DSH2207,break; 是 DSH2208。

函数语句调用的参数这样读:

参数读作
全部为位置参数;每个输出至少一个,每个输入和输出至多一个最后几个接收输出,每个一个,按声明顺序——函数有返回值时返回值排第一;它们前面的是输入,按顺序(legacy 规则 L5)
任何命名参数,或数量超出该范围像 .dss 调用一样按声明顺序和名字匹配到参数:太多是 DSH4224,没有参数的输入或输出是 DSH4217

在第一种读法中,未被覆盖的输入必须声明为 opt 或传入 default,否则 DSH4217。每个声明的输出都必须收到一个目标——无法丢弃其中一个。

out 目标规则

规则失败
out 目标是可以被赋值的东西:一个变量,或它的成员或 swizzle (自 2.0.0 起;1.x 只接受普通名字)DSH4239
任何地方都未声明的名字在此声明,作为该输出类型的局部变量(legacy 规则 L5)提示 DSH5283
已声明的变量类型为该输出的类型。比变量更宽的数值输出给出其前导分量,标量输出则填满它;其他一律拒绝DSH4218
一个变量被命名为两个输出不报告

[!NOTE] out 目标的拼写与某个声明只差大小写时,它就是那个声明,并带有 DSH5275 —— 而不是第二个变量 (自 2.0.0 起)。只有当任何大小写下都没有声明某个名字时,它才会 成为新的局部变量。

参数

位置参数与命名参数

被调方位置参数命名参数
Function、GraphFunction、ShaderFunction、VirtualFunction按声明顺序填充参数按名字匹配参数 (Function / GraphFunction 自 2.0.0 起);另一种大小写以 DSH5275 解析;没有该参数是 DSH4216
带输入引脚的参数拒绝:DSH5259必须:该节点的一个引脚
StaticSwitchParameter下标 0 = true 分支,下标 1 = false 分支True/A、False/B

位置参数在前、命名参数在后;反过来是 DSH2158。同一个参数被给了两次——按位置和按名字,或按名字两次——是 DSH4215。 在语句调用中,命名参数会关闭末尾接收输出的读法(见 语句形式)。

参数名精确比较,带上面的 DSH5275 回退;节点引脚在另一种大小写下匹配时警告 DSH5276。1.x 前端 自己读取的名字——Output、OutputName、OutputIndex、True、False、A、B——匹配时 忽略大小写。

default

(自 1.2.3 起)

default 是一个裸标识符,用于占住一个有意留空的输入(legacy 规则 L25)。 它区分大小写地匹配 (自 2.0.0 起),且仅在没有声明同名变量时生效。

情况行为
对 ShaderFunction / VirtualFunction 的输入传 default输入引脚保持未连接;函数自身的默认值生效。
对不是 opt 的输入传 default同上 (自 2.0.0 起;1.x 拒绝)。
在 Function / GraphFunction 调用里用 default接受 (自 2.0.0 起);Custom 节点不为该参数获得输入。
Default、DEFAULT普通名字:没有声明同名对象时是 DSH4200。

完全省略末尾的可选输入,效果与传 default 相同。

输出选择

Output、OutputName 和 OutputIndex 是 1.x 前端自己读取的命名参数:它会将它们从调用中移除,改为选择输出, 如同在调用之后写 .Name 或 [k]。它们 适用于任何函数种类的调用 (Function 和 GraphFunction 自 2.0.0 起),也适用于 UE.* 调用。

参数接受含义
Output带引号的名字或标识符选择该名字的输出——先精确匹配,再不区分大小写并带 DSH5275
OutputName同上Output 的完全同义词
OutputIndex0 或更大的整数字面量按从 0 起的下标选择:按声明顺序的输出,返回值作为输出 0
规则失败
Output/OutputName 与 OutputIndex 互斥DSH5252
OutputIndex 必须是 0 或更大的整数DSH5250
Output / OutputName 必须是带引号的名字或标识符,不能是表达式DSH5251
构造器不接受选择器DSH5253
参数调用不接受选择器DSH5265
名字必须匹配函数的某个输出DSH5280。在返回值的函数上,不是输出名的名字会改按值的 swizzle 读取(不是 swizzle 时 DSH4230)
下标必须在输出范围内DSH5282
多输出函数不带选择器调用不是错误 (自 2.0.0 起):调用读取输出 0
所选输出必须存在于已加载的资产上——先按名字匹配,再不区分大小写,然后(对 VirtualFunction)按其声明位置匹配发射资产时 DSH8221

[!WARNING] 选择器使调用成为一个值。它不能用在语句调用中:被选中的调用是一个无人接收的表达式, 即 DSH2211。

UE.Expression(…) 接受同样的三个选择器;节点没有的名字是 DSH5201,超出其输出的下标是 DSH5282。见 UE.Expression。

BreakOutFloatNComponents

名为 BreakOutFloat2Components、BreakOutFloat3Components 或 BreakOutFloat4Components (任意大小写)、第一个参数是位置参数、且带有输出选择器的调用会被读作 第一个参数的 swizzle。不会产生 MaterialFunctionCall 节点,也不会查找该名字的 函数 (自 2.0.0 起)。所选输出指名一个通道,其字母不区分大小写:

输出名通道
x、r、"0"0
y、g、"1"1
z、b、"2"2
w、a、"3"3

OutputIndex= 按下标选择同一通道。该通道必须位于名字所说的宽度之内(BreakOutFloat2Components 为 0–1)。否则 ——没有选择器、第一个参数是命名参数、通道超出宽度——该调用就是对同名函数的一次普通调用。两个选择器同时给出 是 DSH5252。

调用参数

输入引脚接线

(自 1.4.1 起)

节点自带输入引脚的已声明参数可以被“调用”,以接好这些引脚。前端把这类属性的每一次使用——调用或裸读取——都写成一次独立的 UE.Expression(Class = "<type>", ParameterName = "<name>", …) 调用,声明的默认值和元数据作为参数,调用的参数接到引脚上 (自 2.0.0 起)。参数相同的使用经过去重 pass(dedupe pass)后是一个节点;裸读取和引脚调用的参数不同,所以是指向同一个材质参数的两个节点。纹理采样参数读的是它的 RGBA 输出。

接受这种形式的参数节点类型完整清单:

ChannelMaskParameterStaticComponentMaskParameterTextureSampleParameter2D
TextureSampleParameter2DArrayTextureSampleParameterCubeTextureSampleParameterCubeArray
TextureSampleParameterVolumeTextureSampleParameterSubUVRuntimeVirtualTextureSampleParameter
SparseVolumeTextureSampleParameter

引脚名是节点自己的、引擎目录里列出的名字;另一种大小写带 DSH5276 解析。每个参数都必须是命名的(DSH5259),每个值都像任何 UE. 参数一样按引脚检查(DSH5214)。

[!NOTE] 资产槽位——采样器参数指向的贴图、曲线或字体——是用 [TextureSlot=Path(…)] 这类声明元数据设置的,它会成为节点的一个属性参数。 调用参数再指名声明已经设置过的属性是 DSH4215。既不是引脚也不是节点属性的名字是 DSH5213;当 它的值是图值时改为提示 DSH5291,节点建出来后按这个名字接引脚 (节点上没有这个引脚时 DSH8212)。

StaticSwitchParameter

(自 1.2.3 起)

StaticSwitchParameter 属性不作为裸标识符解析(DSH4200);它需要两个分支,所以只能 通过调用形式读取。

分支参数名,按查找顺序
true先 True=,再 A=,再位置下标 0
false先 False=,再 B=,再位置下标 1

两个分支都必须存在(DSH5258);其他参数被丢弃并警告 DSH5254。该调用成为一个 UE.Expression(Class = "StaticSwitchParameter", …),两个分支接在它的 A 和 B 引脚上, 像任何 UE. 节点的引脚一样检查 (自 2.0.0 起)。

vec3 Albedo = UseDetail(True = DetailColor, False = BaseColor);

递归与嵌套

情况行为
GraphFunction 经由提出来的 UE. 调用直接或间接再调用自己DSH6330:每次调用都会产生一个新的 Custom 节点
Function 函数体互相调用成环DSH6260:它们的函数体要嵌进同一个 Custom 节点
同一文件的 ShaderFunction 块互相调用成环DSH8299
一条表达式里嵌套调用合法——参数就是普通表达式,所以 F(G(x), 2.0) 对任何可调用种类都成立。
把调用用作 Outputs 绑定表达式合法——绑定就是完整表达式。

诊断

每个诊断都有稳定的代码;代码的页面里有消息和处理方法。消息以 <file>(<line>,<col>): DSHnnnn: <message> 报告,位置在它 所指的调用或参数上。

解析与分发

代码触发时机
DSH4208被调方既不是函数、内置、结构体,也根本不是名字(在加括号的表达式上调用)。
DSH5275(警告) 名字只在忽略大小写时才匹配到某个函数或内置。
DSH5277(警告) mix、fract、mod 或 inversesqrt:内置的 GLSL 拼法。
DSH4210两个声明共用一个名字。
DSH5290(提示) ShaderFunction 块因为名字被占用而以 <Name>_Asset 声明。
DSH6206函数与内置同名。
DSH6208调用 Shader、ShaderLayer 或 ShaderLayerBlend。
DSH5260:: 后面没有名字。
DSH2211语句是一个没人接收其值的表达式。
DSH2158位置参数出现在命名参数之后。

参数与 out 目标

代码触发时机
DSH4224参数比函数的参数多。
DSH4216命名参数指名的参数不存在。
DSH4215同一个参数给了两次。
DSH4217不是 opt 的输入没有得到参数;或在按名字读取的调用里,某个输出没有目标。
DSH4226输入参数无法转换到参数的类型。
DSH5289(提示) 比参数更宽的输入参数取前导分量。
DSH4239out 目标不能被赋值。
DSH4218out 目标的类型接不住这个输出。
DSH5283(提示) 没在任何地方声明过的 out 目标成为局部变量。
DSH4200在另一种大小写下写 default,或任何其他未声明的名字被读作值。

输出选择

代码触发时机
DSH5252同时给了 Output/OutputName 和 OutputIndex。
DSH5250OutputIndex 不是 0 或更大的整数。
DSH5251Output 既不是带引号的名字也不是标识符。
DSH5253在构造器上用了选择器。
DSH5265在参数调用上用了选择器。
DSH5280函数没有这个名字的输出。
DSH5282下标超出了输出范围。

Function

代码触发时机
DSH4201参数或结果类型不是类型。
DSH6305函数既不返回值,也没有 out 参数。
DSH6304函数同时有返回类型和 out 参数。
DSH6253Substrate 输入或结果:Custom 节点没有 Substrate 引脚。
DSH6254纹理结果。
DSH6210MaterialAttributes 输入。
DSH6257(警告) 有返回类型,但函数体从不返回值。
DSH6308带返回类型的函数里出现裸 return;。
DSH6260函数体互相调用成环。
DSH8214发射器无法创建该 Custom 节点。

GraphFunction

Function 之下的全部内容,以及:

代码触发条件
DSH6314函数体中的 UE. 调用没有闭合的 )。
DSH6316(警告) 函数体中的 Substrate. 调用未被提升为节点。
DSH6325被提升的 UE. 调用读取了调用方的变量,这在 1.x 中是允许的。
DSH6326被提升的 UE. 调用读取了一个既不是参数、也未在文件作用域声明的名字。
DSH6329被提升的 UE. 调用产生了一个没有任何 Custom 节点输入承载的值(纹理可以;材质或 Substrate 值不行)。
DSH6330函数通过其被提升的调用到达自身。

被提升的调用像任何其他表达式一样绑定,所以其中的错误会以其所在表达式自身的代码报告。

ShaderFunction 家族与 VirtualFunction

代码触发条件
DSH6312VirtualFunction 没有 Asset 选项。
DSH6313VirtualFunction 未声明任何输出。
DSH6311VirtualFunction 的 Name 缺失或不是标识符。
DSH4315ShaderFunction 不产生任何输出。
DSH8270Asset 引用未解析为资产路径。
DSH8219函数资产无法加载,或无法赋给调用节点(一个调用自身的函数)。
DSH8220资产没有该名称的输入(对于 VirtualFunction,也没有声明位置处的输入)。
DSH8221资产没有该名称的输出。
DSH8214发射器无法创建 MaterialFunctionCall 节点。

参数调用形式

代码触发条件
DSH5259引脚调用中出现位置参数。
DSH5276(警告) 引脚名仅在忽略大小写时匹配。
DSH5214值放不进它的引脚。
DSH4215某个引脚或属性被给了两次,或由调用给出,或由声明和调用共同给出。
DSH5213一个既不是引脚也不是属性的名字,其值又不是图值。
DSH5291(信息) 目录中未列出、但在节点存在后按名字连接的名字。
DSH8212活动节点没有该名称的引脚。
DSH5258一个缺少两个分支的 StaticSwitchParameter 调用。
DSH5254(警告) StaticSwitchParameter 调用中不是分支的参数,被丢弃。
DSH4200没有调用却读取 StaticSwitchParameter。

示例

import "Helpers.dsh";

Shader(Name="Docs/M_Calls")
{
    Properties {
        vec3                   Tint    = vec3(1.0, 0.4, 0.1);
        TextureSampleParameter2D Albedo = Path(Game, "Textures/T_Albedo");
        StaticSwitchParameter  UseTint = true;
    }

    Settings {
        Domain       = "Surface";
        ShadingModel = "Unlit";
    }

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

    Graph {
        vec2 UV  = UE.TexCoord(Index = 0);

        // Parameter pin call: wires the sampler's Coordinates pin, read through RGBA.
        vec4 Tex = Albedo(Coordinates = UV);

        // Value form, Function with a return value, declared in Helpers.dsh.
        float L  = Luma(Tex.rgb);

        // Value form, namespaced Function: the value is its first out parameter.
        vec3 Lit = Common::ApplyTint(Tex.rgb, Tint);

        // Statement form: inputs first, then one out target per output. Neither target is
        // declared, so each becomes a local of its output's type (info DSH5283).
        PulseTint(Lit, Tint, Pulsed, Amount);

        // StaticSwitchParameter call selects between the two.
        Color = UseTint(True = Pulsed, False = vec3(L, L, L));
    }
}

Helpers.dsh:

Function float Luma(in vec3 color) { return dot(color, float3(0.299, 0.587, 0.114)); }

Function PulseTint(in vec3 color, in vec3 tint, out vec3 result, out float amount) {
    amount = 0.5 + 0.5 * sin(color.r * 6.28318);
    result = color * tint * amount;
}

Namespace(Name="Common")
{
    Function ApplyTint(in vec3 color, in vec3 tint, out vec3 result) {
        result = color * tint;
    }
}

生成的节点:

TextureCoordinate                      -> UV
TextureSampleParameter2D  Albedo       -> Tex          (Coordinates pin wired to UV)
Custom  "Luma"                         -> L
Custom  "Common::ApplyTint"            -> Lit
Custom  "PulseTint"                    -> Pulsed (output result), Amount (output amount)
AppendVector, AppendVector             -> vec3(L, L, L)
StaticSwitchParameter  UseTint         -> Color

PulseTint Custom 节点的输出按函数的 out 参数命名——result 是输出 0,amount 是附加输出——(自 2.0.0 起;1.x 按调用方的变量命名附加输出)。

另请参阅

本页目录