DreamShaderLang
Plugin referenceDreamShaderLang

Shader

Shader

Shader

DreamShader » DreamShaderLang » Shader

A top-level block that declares one Unreal material asset: its parameters, its render-state settings, its output bindings, and the node graph that feeds them.

Declared in.dsm — a .dsh holding one is DSH2249 (see Source files)
Kindtop-level block
GeneratesUMaterial (Graph backend) or UDreamShaderMaterialInstance + a hidden UMaterial base (ThinCustom backend)
Multiplicityat most one per file (see Notes)

Synopsis

Shader(Name = "<asset-path>" [, Root = "<root>"])
{
    [Properties [=] { <property-declaration> ; … }]
    [Settings   [=] { <key> = <value> ; … }]
    [Outputs    [=] { { <output-declaration> ; | <output-binding> ; | Expression( … ) { Pin[i] = <source> ; … } } … }]
    [Graph      [=] { <graph-statement> … }]
    [Layout     [=] { { Node( … ) | Comment( … ) } ; … }]
}

The = between a section name and its { … } block is optional sugar (since 1.5.0); a ; after a section's closing } is optional. Sections may appear in any order and may be repeated.

The keyword Shader is matched case-sensitively; section names are matched case-insensitively. See Lexical elements.

A .dss writes the same material as #pragma material(...), uniforms and one export void <Name>(inout material m) — see DreamShaderLang 2.0; dsc migrate rewrites a .dsm that way.

Header attributes

AttributeRequiredValueEffect
NameyesstringThe asset's logical path. The last /-separated segment is the asset name; preceding segments become folders.
RootnostringThe package root the folders hang off. Defaults to /Game when absent or empty.
NoGenerationnotrue | false(after 2.1.2) Only a compile that names the file builds this block's asset; see NoGeneration. Another value is DSH2260.

Attribute keys are matched case-insensitively (name= works). Values may be quoted or bare; a bare value ends at the first , or ). A duplicate key keeps the later value, with the warning DSH2244 (since 2.0.0; silent before). A trailing comma before ) is accepted, as in 1.x (2.0.0 – 2.1.0 refused it with DSH2243).

Full Name / Root grammar, the accepted root spellings, and the resulting on-disk path are specified in Asset paths.

Sections

SectionAcceptedRepeat behaviourReference
PropertiesyesappendsProperties
Settingsyesmerges; last key wins, a key written twice is the warning DSH3262Shader settings
OutputsyesappendsOutput bindings
Graphyesthe later body wins, with the warning DSH2258Graph
Layoutyesresets — a second Layout discards the first, with the warning DSH2258Layout
Codeno — DSH2246——
Inputsno — unknown section, DSH2245——
Resultsno — unknown section, DSH2245——
Optionsno — unknown section, DSH2245——

Properties in a Shader declares parameter, const and UE.* builtin nodes. This is not the same grammar Properties gets inside a VirtualFunction, where it is a synonym for Inputs.

The Outputs / Graph relationship

Outputs holds two kinds of statement, disambiguated per statement:

Statement shapeMeaning
<type> <name> ;output-variable declaration; the Graph must assign it
<type> <name> = <expression> ;initialized output declaration (since 1.3.4)
<target> = <variable> ;output binding — Base.<Property> or Expression( … ).Pin[<i>]
Expression( … ) { Pin[<i>] = <variable> ; … }block form — several pins on one terminal node (since 1.9.0)

The rule that governs whether Graph is required is evaluated after the whole block is read:

  • A Shader with no Graph section and an empty Outputs is DSH2255. Without a Graph, the Outputs statements have to compute the values themselves — an output declaration with an initializer, or (since 2.0.0) a binding whose right side is an expression, such as Base.FrontMaterial = Substrate.Layer(Coat, Body);.
  • An empty Graph = { } is legal.
  • Bindings are what actually connect the material. A Shader with no Outputs section is the warning DSH2256: the material builds, with nothing wired to it (since 2.0.0; through 1.9.x generation then failed).
// Legal: no Graph body needed, the output declaration carries its own initializer.
Shader(Name="M_Flat")
{
    Properties = { vec3 Tint = vec3(1.0, 0.2, 0.2); }
    Outputs = {
        vec3 Color = Tint;
        Base.EmissiveColor = Color;
    }
    Graph = { }
}

Generated asset

Name + Root resolve to a package path exactly as described in Asset paths. Which UClass lands there depends on the resolved backend:

BackendAsset writtenNotes
GraphUMaterialthe node graph is built directly on the material
ThinCustom (since 1.5.0)UDreamShaderMaterialInstance whose parent is a hidden UMaterial subobject named MB_DreamThinBase_<leaf>one asset, one package; parameter overrides you set on the instance are yours to keep — a rebuild captures them and puts back every name the new base still declares (since 1.9.0), see Divergence
Instancealias for ThinCustom (deprecated in 1.5.0)

The backend comes from Settings = { Backend = "…"; } if present, otherwise from the project's Default Compiler Backend setting. See Backend and Project settings.

[!NOTE] A Graph-backend UMaterial is an ordinary asset and is saved on every successful build (since 2.0.0). A ThinCustom product stays Ephemeral — in memory, no package on disk — until a cook, an explicit Materialize, or a child instance gives it one, and once it has a package it stays on disk. See Ephemeral materials.

[!WARNING] Regeneration clears the target graph. Node positions not pinned by Layout, added nodes, node property tweaks, and comment boxes whose text begins with DreamShader: are destroyed. Only comment boxes that do not carry the DreamShader: prefix survive. Under the ThinCustom backend the instance's parameter overrides are cleared too, but they are captured first and restored afterwards (since 1.9.0) — a parameter the source no longer declares is the one case that loses its value. See Regeneration.

Notes

  • At most one Shader per file (DSH2250). Through 1.9.x imports were inlined into one text before parsing, so the rule spanned the import closure; a header is read on its own now and cannot hold a Shader (DSH2249), so an import never adds one. The .dsh check reads tokens, not text: a comment that mentions Shader( is fine. See Source files.
  • Shader() with no attributes is DSH2242, the missing Name.
  • Shader may share a .dsm with VirtualFunction, Function, GraphFunction and Namespace blocks, which are helpers of the material, and with ShaderFunction, ShaderLayer and ShaderLayerBlend blocks: one compile of the file builds them all, each into its own asset, and the material may call such a function by name (2.0.0 – 2.1.0 refused it with DSH6201). A Shader in a .dsf is DSH2259.
  • A .dsm that declares no Shader block is still compilable — it simply produces whatever function assets it does declare.
  • Binding Base.MaterialAttributes turns on Use Material Attributes on the material. See Output bindings for Base.FrontMaterial and the other targets.

Diagnostics

Every stage reports all of its errors, each at its own line and column (since 2.0.0).

Parse time

CodeRaised when
DSH2241Shader is not followed by its attribute list
DSH2242the attribute list has no Name, or an empty one
DSH2243a malformed attribute list — a missing key, = or value, a missing , or )
DSH2244(warning) an attribute written twice
DSH2250a second Shader block in the file
DSH2249a Shader block in a .dsh
DSH2257the body {, a section name, or a section's { is missing
DSH2245a section other than Properties, Settings, Outputs, Graph and Layout
DSH2246a Code section
DSH2258(warning) a Graph or Layout section written twice
DSH2255no Graph section, and an empty Outputs
DSH2256(warning) no Outputs section
DSH2150the file ends inside the block

Bind and generation time

CodeRaised when
DSH4210a property, a function or another name declared twice
DSH7202Settings = { Backend = … } names no backend; Instance is read as ThinCustom with the warning DSH7204
DSH8200Name / Root do not resolve to a valid asset path
DSH8201the material could not be created or reused — the target path holds another class, or an asset DreamShader did not generate; the reason is appended
DSH8203the same, for a ThinCustom instance
DSH8206the asset is open in an asset editor, so it was not rebuilt
DSH8207the asset was edited by hand since it was generated, so it was not rebuilt; the reason it carries is the DSH8115 text — see Divergence

The messages of Properties, Settings, Outputs and Graph are on their own pages. Every code: diagnostics.

Example

Shader(Name="Materials/M_Emissive", Root="Game")
{
    Properties = {
        Group("Look") {
            vec3  Tint      = vec3(1.0, 0.4, 0.1) [Description="Emissive tint"];
            float Intensity = 2.0                 [Slider(0, 10)];
        }
        TextureSampleParameter2D BaseTex = Path(Game, "Textures/T_Noise");
    }

    Settings = {
        ShadingModel = "Unlit";
        BlendMode    = "Translucent";
        TwoSided     = true;
    }

    Outputs = {
        vec3  Color;
        float Alpha;

        Base.EmissiveColor = Color;
        Base.Opacity       = Alpha;
    }

    Graph = {
        vec2 UV  = UE.TexCoord(Index = 0);
        vec4 Tex = BaseTex(Coordinates = UV);
        Color = Tex.rgb * Tint * Intensity;
        Alpha = Tex.a;
    }

    Layout = {
        Comment(Name="Sampling", X=-1200, Y=-200, W=900, H=400);
        Node(Var="UV", X=-1100, Y=-120);
    }
}

Generated asset:

package     /Game/Materials/M_Emissive
object path /Game/Materials/M_Emissive.M_Emissive
on disk     <Project>/Content/Materials/M_Emissive.uasset      (once Materialized, or under the Graph backend)

[!NOTE] BaseTex is declared as TextureSampleParameter2D, not as the compact Texture2D, because only the sample-parameter family owns the input pins the BaseTex(Coordinates = UV) call form wires. A compact Texture2D generates a texture object parameter, which has no such pins; calling it falls through to the function dispatcher and fails. See Using parameters in Graph.

See also

On this page