DreamShaderLang
Graph 语言

不支持的写法

不支持的写法

不支持的写法

DreamShader » Graph » 不支持的写法

Graph 块不实现的每一种 HLSL 与 GLSL 写法、编译器为它报告的代码,以及应该改写成什么。

声明于.dsm、.dsf——适用于每一个 Graph { … } 块体、Outputs 绑定表达式和 Outputs 声明的默认值
类型被拒绝语法的参考

Graph 块是节点图构建器,不是着色器编译器。它只有固定的几种语句形式、四个算术运算符,除 if 之外没有任何控制流。其余一切都会带诊断码被拒绝。不会再有任何写法被编译成比你写下来的更少的东西*(自 2.0.0 起)*: 1.x 生成器遇到第一个不认识的运算符就静默丢掉表达式的其余部分 (a % b 构建出 a),而现在每一种这样的写法都是错误,信息里还会说明 1.x 当时做了什么。

想写循环、?:、&& 或位运算,请把代码搬进 Function, 或用 dsc migrate 把文件迁到 .dss——那里有这些写法。

一种写法是怎样被拒绝的

legacy 前端用 2.0 的语句与表达式解析器读取 Graph 块体,它的文法是 1.x 文法的超集;然后再拒绝 1.x 没有的东西*(自 2.0.0 起)*:

阶段拒绝什么码
词法器根本不是记号的字符(@、$、反引号)、写坏的数(0.5.5、1.0fx)DSH2101、DSH2105
解析器不是 2.0 文法里语句或表达式的文本:缺了 ;、) 或名字,switchDSH2150–DSH2165
legacy 限制检查2.0 文法有、1.x 没有的写法:运算符、[ ]、强制转换、循环、return、复合赋值DSH2200–DSH2222
绑定器能解析但没有意义的写法:字符串值、整数除法、宽度不匹配DSH42xx

每条诊断都带该写法的行列。一个阶段会报告它的全部错误,有错误的阶段会在下一阶段之前停止构建。

1.x 会截断的运算符

下面每一种 1.x 都会接受,然后只构建运算符前面的部分,没有任何信息。(自 2.0.0 起) 每一种都是错误。

写法码应改写为
a % bDSH2201fmod(a, b)
a && b、a || b、!aDSH2200嵌套 if 语句,或对 0/1 掩码用 max / min
a & b、a | b、a ^ b、~aDSH2201带 HLSL 函数体的 Function
a << 2、a >> 2DSH2201a * 4.0、a / 4.0,或一个 Function
a < b、a > b、a <= b、a >= b、a == b、a != b,位于 if 条件之外DSH2200一个 if 条件
a ? b : cDSH2200if / else、lerp(c, b, mask),或一次 StaticSwitchParameter 调用
v[0]DSH2202一个 swizzle:v.x
if 条件里的第二个比较、&& 或 ||DSH2210嵌套 if 语句
// Refused (DSH2201); 1.x built this as UE.Time().
float Wave = UE.Time() % 1.0;

// Correct:
float Wave = fmod(UE.Time(), 1.0);
// Refused (DSH2210); 1.x built this as if (Color.r > 0.5).
if (Color.r > 0.5 && Color.g > 0.5) { Out = One; } else { Out = Zero; }

// Correct:
if (Color.r > 0.5) {
    if (Color.g > 0.5) { Out = One; } else { Out = Zero; }
} else {
    Out = Zero;
}

限制检查对一个被拒绝的写法只报一次、不再看它内部,所以 a % b % c 是一条诊断;a % b + c % d 是两条。

语句层面的写法

写法码应改写为
return Color;、return;DSH2208给声明的输出变量赋值:Color = …;
for (int i = 0; i < 3; i = i + 1) {}DSH2208手工展开,或把循环搬进函数体是真 HLSL 的 Function
while (t) {}、do {} while (t);DSH2208同上
break;、continue;、discard;DSH2208——
switch (Mode) {}DSH2160嵌套 if 语句,或一次 StaticSwitchParameter 调用
float Foo(float x) { return x; }DSH2154,在本该放声明 ; 的 ( 处在顶层声明成 Function 或 GraphFunction 再调用
struct S { float a; }DSH2151:struct 不能开始一个表达式用 MaterialAttributes,或把结构体放进 Function 函数体
前面没有 if / else 的 { … }DSH2220去掉花括号
变量上的 static / constDSH2212一个 const 属性
float w[4];DSH2213多个独立变量
a + b;——没人接收的值DSH2211把它赋给变量
#include "X.ush"、#pragma …DSH1035:.dsm / .dsf 的预处理器不认识这样的行文件级 import,或一个使用该 include 的 Function
#define K 2Graph 里没有诊断:这一行属于预处理器,它在 #if 条件里使用 define一个 const 属性

Graph 块体按语句读取,而不是按文本在 ; 处切分,所以带花括号的写法后面的代码不会再被吞进同一条语句 (自 2.0.0 起)。

表达式层面的写法

写法码
x = a == b;DSH2200
a == b; (作为语句)DSH2211——比较的值无处可去
x = a++;、a++;、--a;DSH2207
x = (float)a;DSH2203——没有 C 风格强制转换;请写 float(a)
x = (y = z);DSH2204
x = 0x10;DSH2222——没有十六进制字面量;1.x 把 0x10 读成 0
x = 1.0fx;、x = 0.5.5;DSH2105
x = "text";DSH4202
x = {1, 2, 3};、Attrs.BaseColor = {1, 0, 0};DSH2162——花括号列表只作为声明的初始值读取
float4 v = {{1,2},{3,4}};DSH2214——花括号初始值不能嵌套
f(a b)DSH2152——缺少 ,
if (a) Color = X;DSH2209——花括号是必需的
@、$、反引号DSH2101

复合赋值与自增自减

+= -= *= /= %=、位运算的复合形式、++ 和 -- 都不是 1.x 运算符。

写法码
a += b;、a -= b;、a *= b;、a /= b;、a %= b;DSH2205
a++;、a--;、++a;、--a;DSH2207

(自 2.0.0 起) 空白不再有影响。1.x 把 a += b; 读成类型为 a、 名为 + 的变量声明,把 a+=b; 读成对一个名叫 a+ 的全新变量的赋值, a 保持不变且没有任何信息;现在这些都是 DSH2205。请写展开形式:a = a + b;。

// Refused (DSH2205).
Sum+=Tint;

// Correct:
Sum = Sum + Tint;

大小写写错的关键字

if 和 else 是关键字,区分大小写,for、while、return、 struct 及其他 HLSL 关键字也一样。大小写写错的拼法是一个名字。

写法结果
If (x) {}、IF (x) {}If (x) 是对一个叫 If 的函数的调用,本该放这条语句的 ; 的位置出现了 {:DSH2154
if (x) {} Else {}、ELSE {}if 能解析;Else 是一个名字,它的 { 是 DSH2154

类型 token、构造器名和 true / false 不区分大小写。其他名字先精确查找, 再不区分大小写,后者带警告(DSH5275, 引擎名为 DSH5276);见 名称解析。

根本不存在的特性

特性状态替代方案
矩阵类型(float3x3、float4x4、mat2、mat3、mat4)图里没有矩阵值:DSH4361UE.TransformVector / UE.TransformPosition,或把矩阵局部变量放在 Function 函数体内部
数组与下标DSH2213、DSH2202通道用 swizzle;层用 Texture2DArray 采样
inout 参数1.x 函数只有 in 和 out:DSH6302传一个 in 和一个 out
在 Graph 内声明函数DSH2154顶层的 Function / GraphFunction
整数运算没有——int、uint、bool 和 half 在图里都是浮点;两个整数构造器之间的 / 是 DSH4243见表达式
十六进制、八进制、二进制字面量十六进制是 DSH2222十进制字面量;见字面量
字符串值DSH4202 在命名 UE.* 参数之外——
三元条件DSH2200if / else、lerp、StaticSwitchParameter
逗号运算符没有拆成多条语句
表达式内赋值DSH2204拆成多条语句
嵌套花括号初始值DSH2214用构造器调用:float4(float2(1,2), float2(3,4))
预处理指令只有条件编译那一组和 #Region / #EndRegionimport、const 属性
Code = { … } 里的 Shader已移除——DSH2246Graph = { … }

诊断

码触发条件
DSH1035一行 #,不属于条件编译组和 #Region / #EndRegion —— #include、#pragma
DSH2101不属于任何记号的字符
DSH2105写坏的数:0.5.5、1.0fx、1e
DSH2151本该是一个表达式,却出现了别的东西:struct、= 5;、if ()
DSH2152缺少一个 ) —— 常见于两个参数之间缺了 ,
DSH2154语句没有以 ; 结束:大小写写错的 If、一个函数定义、末尾缺 ; 的最后一条语句
DSH2160语句开头出现 switch、case 或 default
DSH2162声明之外把花括号列表当作值使用
DSH2200在 if 条件之外出现比较、逻辑运算符或 ?:
DSH2201%、移位或位运算符
DSH2202[ ]
DSH2203C 风格强制转换
DSH2204表达式内赋值
DSH2205复合赋值
DSH2207++ 或 --
DSH2208for、while、do、return、break、continue、discard
DSH2209if 或 else 的块体不带花括号
DSH2210if 条件里多于一个比较,或用了 && / ||
DSH2211值无人接收的表达式语句
DSH2212Graph 变量上的存储关键字
DSH2213数组声明子
DSH2214花括号初始值里嵌套花括号列表
DSH2220一个裸 { … } 块
DSH2222十六进制字面量
DSH2246Shader 或函数块里的 Code 段
DSH4202字符串被当作值使用
DSH4243/ 的两个操作数都是整数构造器调用
DSH4361矩阵值
DSH63021.x 函数参数上的 inout

包含每条消息的完整列表见诊断索引。

示例

一段 GLSL 风格的尝试,以及它的 DreamShaderLang 等价写法。

// Refused.
Graph {
    vec2  uv    = UE.TexCoord(Index = 0);
    float t     = UE.Time() % 4.0;                 // DSH2201
    float mask  = uv.x > 0.5 && uv.y > 0.5;        // DSH2200
    vec3  col   = mask ? Hot : Cold;               // DSH2200
    col        *= Gain;                            // DSH2205
    Color = col;
}
// Correct.
Graph {
    vec2  uv = UE.TexCoord(Index = 0);
    float t  = fmod(UE.Time(), 4.0);

    vec3 col;
    if (uv.x > 0.5) {
        if (uv.y > 0.5) { col = Hot; } else { col = Cold; }
    } else {
        col = Cold;
    }

    Color = col * Gain;
}

任何真正命令式的东西——循环、位掩码、switch——都属于 Function,它的函数体是真 HLSL,会被编译进一个 Custom 节点:

Function SelfContained float Ring(in float2 uv, in float count)
{
    float acc = 0.0;
    for (int i = 0; i < 4; ++i)
    {
        acc += sin(uv.x * count * (i + 1));
    }
    return acc * 0.25;
}
Graph {
    float r = Ring(uv, 8.0);
}

参见

  • 语句 —— 确实被支持的语句形式
  • 表达式 —— 存在的那四个运算符及其优先级
  • if / else —— 唯一的控制流,以及条件运算符
  • 字面量 —— 接受的数字形式、后缀,以及什么不是字面量
  • 构造器 —— 强制转换与矩阵构造的替代方案
  • Swizzle —— 下标的替代方案
  • 调用 —— 把命令式代码搬进可调用函数
  • Function —— HLSL 函数体,循环和位运算符在那里合法
  • GraphFunction —— 把 UE.* 节点提升为引脚的 HLSL 函数体
  • 数学内置 —— fmod、min、max、clamp、lerp
  • 名称解析 —— 大小写敏感对照表
  • dsc migrate —— 把 1.x 文件改写为 .dss,那里有循环和 ?:
  • 诊断索引 —— 按阶段列出每个码

本页目录