GLSL Overview
GLSL for DreamShaderLang authors — which GLSL spellings are first-class tokens in a 1.x source, which are rewritten inside Function bodies, which carry a warning, why a .dss takes HLSL only, and what has no equivalent at all.
GLSL is what most shader examples on the internet are written in. DreamShaderLang is not a GLSL
compiler and never emits GLSL — the target is Unreal's material graph and HLSL. The 1.x syntax
accommodates GLSL spellings deliberately, in three different ways; a .dss takes HLSL only. Telling
these apart is the whole point of this page.
| Mechanism | Where | What happens |
|---|---|---|
| First-class token | 1.x Properties, Inputs, Outputs, Graph declarations, Graph constructors | vec3 is a type token, read as float3; no diagnostic |
| Identifier rewrite | 1.x Function / GraphFunction signatures and bodies | whole identifiers are substituted before the HLSL is emitted, so vec3 becomes float3 and mix becomes lerp; no diagnostic |
| Legacy rule with a warning since 2.0.0 | mix, fract, mod, inversesqrt in a 1.x Graph | read as lerp, frac, fmod, rsqrt, with the warning DSH5277 |
| HLSL only | .dss | no GLSL spellings: a function name such as mix is the error DSH4250, and vec3 is no type (DSH4201) |
// GLSL
vec3 applyTint(vec3 color, vec3 tint)
{
return color * tint;
}// DreamShaderLang — the same helper. vec3 survives in the declaration,
// and becomes float3 in the generated HLSL.
Function vec3 ApplyTint(in vec3 color, in vec3 tint) {
return color * tint;
}GLSL type aliases
In a 1.x source these are real tokens, accepted everywhere the corresponding float / int /
uint / bool spelling is accepted, and read as that spelling. A .dss does not take them — write the
HLSL spelling; dsc migrate respells them for you.
| GLSL spelling | Equivalent |
|---|---|
vec2 vec3 vec4 | float2 float3 float4 |
ivec2 ivec3 ivec4 | int2 int3 int4 |
uvec2 uvec3 uvec4 | uint2 uint3 uint4 |
bvec2 bvec3 bvec4 | bool2 bool3 bool4 |
There is no vec1, ivec1, uvec1 or bvec1, and no GLSL vector spelling for half. The
single-component GLSL-style forms simply do not exist — use float or float1.
Because int, uint, bool and half all collapse to the same float component counts, choosing
between int3, ivec3, bool3 and float3 is a documentation decision, not a semantic one. The
single observable difference is the integer marker set by an integer constructor call in a
Graph block, which exists solely to reject integer division. See
Types and Values.
Rewrites inside function bodies
A Function / GraphFunction signature runs every type token through a normalizer, and the
body runs every identifier through a superset of the same map. Both match on the lower-cased
whole identifier, so the rewrite is case-insensitive.
| Rewritten identifier | Becomes | In signature types | In body text |
|---|---|---|---|
vec2 vec3 vec4 | float2 float3 float4 | ✔ | ✔ |
ivec2 ivec3 ivec4 | int2 int3 int4 | ✔ | ✔ |
uvec2 uvec3 uvec4 | uint2 uint3 uint4 | ✔ | ✔ |
bvec2 bvec3 bvec4 | bool2 bool3 bool4 | ✔ | ✔ |
mat2 | float2x2 | ✔ | ✔ |
mat3 | float3x3 | ✔ | ✔ |
mat4 | float4x4 | ✔ | ✔ |
mix | lerp | ✘ | ✔ |
fract | frac | ✘ | ✔ |
mod | fmod | ✘ | ✔ |
15 signature aliases; 18 body aliases. The rewrite is comment- and string-aware, and it applies to
Function and GraphFunction bodies only — a Graph block, a Shader body and a
ShaderFunction body are not normalized. The body rewrite gives no diagnostic; DSH5277 applies to
Graph text only.
The body rewrite matches the whole identifier, ignoring case. A helper, local variable or struct
member named Mix, Mod, Fract, Vec3, Mat4 … inside a Function or GraphFunction body is
silently renamed to lerp, fmod, frac, float3, float4x4. There is no diagnostic; the failure
surfaces as an HLSL compile error, or as silently different math. Rename the identifier.
Note that mat2 / mat3 / mat4 rewrite cleanly, but a graph has no matrix values. The declaration
parses and the call fails: a Graph call that passes a matrix to a pin is DSH4361. See
Matrices.
GLSL function names in a Graph block
Math builtins are matched by their exact HLSL name since 2.0.0. Four GLSL spellings still
work in a 1.x Graph, as a legacy rule that says so:
| GLSL name | In a 1.x Graph block | In a .dss | In a 1.x Function body |
|---|---|---|---|
mix | read as lerp, warning DSH5277 | the error DSH4250 — write lerp | rewritten to lerp |
fract | read as frac, warning DSH5277 | the error DSH4250 — write frac | rewritten to frac |
mod | read as fmod, warning DSH5277 | the error DSH4250 — write fmod | rewritten to fmod |
inversesqrt | read as rsqrt, warning DSH5277 | the error DSH4250 — write rsqrt | no such HLSL name |
clamp, dot, min, max, pow, sqrt, abs, floor, ceil, sin, cos, normalize | spelled the same in both languages — real builtins | the same | HLSL intrinsics |
smoothstep, step, length, cross, reflect, refract | real builtins since 1.6.0 — spelled the same in both languages | the same | HLSL intrinsics |
distance, exp, exp2, log, log2 | real builtins since 2.0.0 | the same | HLSL intrinsics |
Note that the Sine / Cosine nodes sin / cos build take cycles (Period = 1), not radians —
only HLSL sin in a body takes radians. The complete builtin catalogue is
Math Builtins.
Constructors and swizzle
In a 1.x source both survive the trip as written; in a .dss spell the type the HLSL way
(float3(…)), and the swizzle rules are the same.
Graph = {
vec3 color = vec3(1.0, 0.2, 0.1);
float r = color.r;
vec2 rg = color.rg;
vec3 bgr = color.bgr;
}- Constructor names follow the type tokens, so
vec2(…),vec3(…),vec4(…),ivec3(…)and so on all work in aGraphblock. - Swizzles accept between one and four channel characters, from either the
xyzwor thergbaset. Reordering and repeated reads are both allowed; mixing the two sets in one swizzle (.xg) isDSH4230since 2.0.0. There is nostpqset and nouvset —.uvisDSH4230. - A swizzle can only narrow or rearrange.
Roughness.yzon a scalar isDSH4230, not a broadcast. Repeat channel 0 (.xx) or use a constructor instead.
Details: Expressions and Conversions.
What has no equivalent
| GLSL habit | In DreamShaderLang |
|---|---|
void main() { … } | a .dss entry, export void M(inout material m); in 1.x a Shader block with Outputs bindings |
uniform float x; | in a .dss it is uniform float x;, with /// tags; in 1.x a Properties declaration. Either becomes a real material parameter |
in / out / varying / attribute at file scope | none — inputs come from UE.* nodes and parameters |
sampler2D + texture(s, uv) | in a .dss, uniform Texture2D Tex; and Tex.Sample(uv); in 1.x a texture property plus SampleTexture2D(tex, uv), or a TextureSampleParameter2D called as Tex(Coordinates = uv) |
layout(…), lowp / mediump / highp | none |
mat3 m; m * v | no matrix values in a graph (DSH4361) — use UE.TransformVector / UE.TransformPosition, or compute it in a /// @custom / Function body |
#version, #extension | none; the preprocessor has just the #if / #define family |
for, while | a .dss has them (a loop whose count is known only at run time goes in a /// @custom function); a 1.x Graph does not (DSH2208) |
discard | valid inside a /// @custom / Function HLSL body only |
Porting a snippet
A typical GLSL fragment, and the ways to land it.
float ring(vec2 uv, float t)
{
vec2 p = uv - 0.5;
float d = length(p);
return fract(sin(t) * 0.5 + d * 4.0);
}As .dss code, respelled the HLSL way, where every call is a real node:
float Ring(float2 uv, float t)
{
float2 p = uv - 0.5;
float d = length(p);
return frac(sin(t) * 0.5 + d * 4.0); // note: sin in the graph takes cycles
}Put a /// @custom line above the function and its body becomes the HLSL of one Custom node instead
(sin in radians).
As a 1.x Function, where the body is HLSL and the aliases are rewritten for you:
Function float Ring(in vec2 uv, in float t)
{
vec2 p = uv - 0.5; // vec2 -> float2 on emission
float d = length(p); // HLSL intrinsic, fine inside a body
return fract(sin(t) * 0.5 + d * 4.0); // fract -> frac
}As 1.x Graph statements, where length and frac are builtins; fract compiles too, with the
warning DSH5277:
Graph = {
vec2 uv = UE.TexCoord(Index = 0);
vec2 p = uv - 0.5;
float d = length(p); // a builtin since 1.6.0
float r = frac(sin(UE.Time()) * 0.5 + d * 4.0);
}Before 1.6.0, length was not a builtin and this line had to be spelled out as sqrt(dot(p, p)).
Older sources written that way are still perfectly valid — just no longer necessary.
The /// @custom / Function version is one Custom node; the graph-code version produces inspectable
material nodes that can be wired to parameters. Pick per case — see Functions
and DreamShaderLang 2.0.
Common GLSL keywords
For reference. Nothing in this table is part of the DreamShaderLang grammar except where noted
above (in a .dss, if, for, while, return, in / out / inout, const and uniform are the
HLSL keywords of the same name).
| Category | Keywords |
|---|---|
| Types | void, bool, int, uint, float, double, vec2, vec3, vec4, mat2, mat3, mat4 |
| Control flow | if, else, for, while, do, switch, case, default |
| Jumps | return, break, continue, discard |
| Parameters | in, out, inout |
| Modifiers | const, uniform, layout, centroid, flat, smooth, attribute, varying |
| Precision | lowp, mediump, highp |
Where to next
HLSL Overview
Where HLSL runs, and the shipped helper header.
Keyword Cheatsheet
All three vocabularies side by side.
Types and Values
The closed token set and its validity matrix.
Math Builtins
Every math name graph code understands, and what happens to GLSL spellings.
Expressions and Conversions
Operators, constructors, swizzle and widening.
HLSL Overview
HLSL for DreamShaderLang authors — where HLSL actually runs, how types and signatures map, what you can write in a @custom or Function body, and the shipped DreamShaderBuiltins.ush header.
Keyword Cheatsheet
Every word DreamShaderLang's grammar treats specially — the 1.x blocks, sections, qualifiers and contextual keywords, the .dss declarations,