DreamShaderLang
HLSL / GLSL 背景

GLSL 简介

写给 DreamShaderLang 作者的 GLSL 背景 —— 哪些 GLSL 写法是一等 token、哪些会在 Function 体内被改写,以及哪些根本没有对应物。

网上大多数着色器示例都是 GLSL 写的。DreamShaderLang 不是 GLSL 编译器,也从不输出 GLSL —— 它的目标是 Unreal 的材质图和 HLSL。但语言对 GLSL 写法是刻意照顾的,而且照顾方式有两种, 分清这两种就是本页的全部要点。

机制位置发生了什么
一等 tokenPropertiesInputsOutputsGraph 声明、Graph 构造器vec3 就是一个类型 token。什么都不改写,存下来和报出来都是你写的样子
标识符改写Function / GraphFunction 的签名和函数体在输出 HLSL 之前按整标识符替换,于是 vec3 变成 float3mix 变成 lerp
// GLSL
vec3 applyTint(vec3 color, vec3 tint)
{
    return color * tint;
}
// DreamShaderLang —— 同一个 helper。vec3 在声明里保留,
// 在生成的 HLSL 里变成 float3。
Function vec3 ApplyTint(in vec3 color, in vec3 tint) {
    return color * tint;
}

GLSL 类型别名

这些是真正的 token,凡是接受对应 float / int / uint / bool 写法的地方都接受它们。

GLSL 写法等价于
vec2 vec3 vec4float2 float3 float4
ivec2 ivec3 ivec4int2 int3 int4
uvec2 uvec3 uvec4uint2 uint3 uint4
bvec2 bvec3 bvec4bool2 bool3 bool4

没有 vec1ivec1uvec1bvec1,也没有 half 的 GLSL 向量写法。单分量的 GLSL 风格形式 根本不存在 —— 请用 floatfloat1

由于 intuintboolhalf 最终都折叠到同一套浮点分量数,在 int3ivec3bool3float3 之间做选择是文档层面的决定,不是语义层面的。唯一可观察的差别是 Graph 块中整数 构造器调用设置的整数标记,它存在的唯一目的是拒绝整数除法。见 类型与值

函数体内部的改写

Function / GraphFunction签名会把每个类型 token 过一遍规范化器,函数体则把每个标识符 过一遍同一张表的超集。两者都按小写化后的整标识符匹配,所以改写不区分大小写。

被改写的标识符变成签名类型中函数体文本中
vec2 vec3 vec4float2 float3 float4
ivec2 ivec3 ivec4int2 int3 int4
uvec2 uvec3 uvec4uint2 uint3 uint4
bvec2 bvec3 bvec4bool2 bool3 bool4
mat2float2x2
mat3float3x3
mat4float4x4
mixlerp
fractfrac
modfmod

签名别名 15 条;函数体别名 18 条。改写能识别注释和字符串,并且作用于 FunctionGraphFunction 体 —— Graph 块、Shader 体和 ShaderFunction 体都不做规范化。

函数体改写按整标识符匹配、不区分大小写。FunctionGraphFunction 体里名为 MixModFractVec3Mat4 … 的 helper、局部变量或结构体成员,都会被静默改名成 lerpfmodfracfloat3float4x4。没有任何诊断;故障表现为 HLSL 编译错误,或者悄悄算错。请改名。

注意 mat2 / mat3 / mat4 改写得很干净,但落到的是语言不支持的类型。声明能解析, 失败发生在调用时 —— … input 'basis' uses unsupported type 'float3x3'.HLSL 简介中的矩阵一节。

Graph 块里的 GLSL 函数名

Graph 块里什么都不改写,所以 GLSL 写法必须本身就是真正的内置 —— 其中三个确实是:

GLSL 名字Graph 块中Function 体中
mix真正的内置,lerp 的别名改写成 lerp
fract真正的内置 since 1.5.0,与 frac 同一节点改写成 frac
mod真正的内置 since 1.5.0,与 fmod 同一节点改写成 fmod
clampdotminmaxpowsqrtabsfloorceilsincosnormalize两种语言拼写相同 —— 都是真正的内置HLSL 内建函数
smoothstepsteplengthdistancecrossreflectrefractexplog不是内置 —— 走 UE.Expression(Class = …) 或写进 FunctionHLSL 内建函数,可直接使用

完整的内置目录见数学内置

构造器与 swizzle

两者都能原样带过来,GLSL 写法保留。

Graph = {
    vec3  color = vec3(1.0, 0.2, 0.1);
    float r     = color.r;
    vec2  rg    = color.rg;
    vec3  bgr   = color.bgr;
}
  • 构造器名跟随类型 token,所以 vec2(…)vec3(…)vec4(…)ivec3(…) 等在 Graph 块里都能用。
  • swizzle 接受一到四个通道字符,来自 xyzwrgba 两个集合,不区分大小写。重排和重复都允许。 没有 stpq 集合,也没有 uv 集合 —— .uv 会失败。
  • swizzle 只能收窄或重排。对标量写 Roughness.yz 是硬错误,不是广播: Swizzle 'yz' is invalid for a value with 1 components. 请重复通道 0(.xx)或改用构造器。

细节见运算符与转换

完全没有对应物的东西

GLSL 习惯在 DreamShaderLang 中
void main() { … }没有 —— 用带 Outputs 绑定的 Shader 块描述材质
uniform float x;写成 Properties 声明;节点会变成真正的材质参数
文件作用域的 in / out / varying / attribute没有 —— 输入来自 UE.* 节点和参数
sampler2D + texture(s, uv)纹理 property 加 SampleTexture2D(tex, uv),或者用 TextureSampleParameter2D 调用 Tex(Coordinates = uv)
layout(…)lowp / mediump / highp没有
mat3 m; m * v没有矩阵类型 —— 用 UE.TransformVector / UE.TransformPosition
#version#extension没有
discard只在 Function 的 HLSL 体内部有效

移植一段片段

一段典型的 GLSL 片段,以及落地的两种方式。

float ring(vec2 uv, float t)
{
    vec2  p = uv - 0.5;
    float d = length(p);
    return fract(sin(t) * 0.5 + d * 4.0);
}

写成 Function,函数体是 HLSL,别名由语言替你改写:

Function float Ring(in vec2 uv, in float t)
{
    vec2  p = uv - 0.5;          // 输出时 vec2 -> float2
    float d = length(p);         // HLSL 内建函数,在函数体里没问题
    return fract(sin(t) * 0.5 + d * 4.0);   // fract -> frac
}

写成 Graph 语句,这里什么都不改写,而且 length 不是内置:

Graph = {
    vec2  uv = UE.TexCoord(Index = 0);
    vec2  p  = uv - 0.5;
    float d  = sqrt(dot(p, p));                    // length,手动展开
    float r  = fract(sin(UE.Time()) * 0.5 + d * 4.0);
}

Function 版本更短;Graph 版本产出可以在材质图里查看、也可以接参数的真实节点。按场景选择 —— 见函数

GLSL 常见关键字

仅作参考。除上文明确说明的以外,这张表里的东西都不属于 DreamShaderLang 语法。

分类关键字
类型voidboolintuintfloatdoublevec2vec3vec4mat2mat3mat4
控制流ifelseforwhiledoswitchcasedefault
跳转returnbreakcontinuediscard
参数inoutinout
修饰constuniformlayoutcentroidflatsmoothattributevarying
精度lowpmediumphighp

接下来

本页目录