DreamShaderLang
Generation

Output Bindings

The Outputs section — declaring output variables, the complete Base.<target> catalogue, and the Expression(...).Pin[i] form.

A Shader's Outputs section does two jobs at once:

  1. it declares the variables the Graph will write, and
  2. it binds those variables to Unreal material property inputs, or to pins on explicitly created UMaterialExpression nodes.

Bindings, not declarations, are what make a material. A Shader with declarations but no bindings parses with the warning No Outputs block was provided. Generation requires explicit material property bindings. and then fails generation with {File}: Outputs block is required.

Synopsis

NotationMeaningExample
<x>Placeholder — substitute a real value; the angle brackets are not typed.Name = <string>
[ x ]Optional — the whole group may be left out.[, Root = <string>]
{ a | b }Choice — take exactly one of the alternatives separated by |.{ Node( … ) | Comment( … ) }
Repetition — the preceding item may appear any number of times.<property-declaration> …
Outputs [=]
{
    <output-declaration>
    <output-binding>
}

output-declaration := <type> <name> [ = <expression> ] ;

output-binding     := Base. <target> = <source> ;
                    | Expression( <key> = <value> [, <key> = <value> ]… ) . Pin[ <index> ] = <source> ;

<source> is an output variable name, or the reserved name return. The [ and ] around <index> are literal.

The right-hand side of a binding is a name, not an expression. Base.EmissiveColor = Tint * Strength; is not a binding — compute the value in the Graph block and bind the resulting variable.

Statement classification is per statement, not per section:

Statement shapeClassified as
no top-level =bare output-variable declaration
top-level =, left side is a valid typed declarationinitialized output declaration since 1.3.4
top-level =, left side is not a valid typed declarationoutput binding

Binding target kinds

Target text begins withKindMeaning
Base. (case-insensitive)material propertyconnects to one of UMaterial's property inputs
Expression (case-insensitive)expression inputcreates a UMaterialExpression and connects to one of its input pins
anything elseOutput binding target '{Target}' must start with Base. for material outputs or Expression(...) for output nodes.

The Base.<target> catalogue

Target names are matched case-insensitively. Every accepted spelling is listed below; there are no wildcards and no "and others".

46 spellings resolving to 31 distinct EMaterialProperty values on UE 5.4 and newer. On UE 5.3 FrontMaterial does not exist, leaving 45 spellings and 30 properties. Five further spellings exist only in a custom engine fork — see Fork-only targets.

Base. spelling(s)EMaterialPropertyValue type
BaseColorMP_BaseColorFloat3
MaterialAttributes, AttributesMP_MaterialAttributesMaterialAttributes
FrontMaterial since UE 5.4MP_FrontMaterialSubstrate
EmissiveColor, EmissiveMP_EmissiveColorFloat3
OpacityMP_OpacityFloat1
OpacityMaskMP_OpacityMaskFloat1
MetallicMP_MetallicFloat1
SpecularMP_SpecularFloat1
RoughnessMP_RoughnessFloat1
NormalMP_NormalFloat3
AmbientOcclusion, AOMP_AmbientOcclusionFloat1
RefractionMP_RefractionFloat3
WorldPositionOffset, WPOMP_WorldPositionOffsetFloat3
PixelDepthOffset, PDOMP_PixelDepthOffsetFloat1
SubsurfaceColorMP_SubsurfaceColorFloat3
ClearCoatMP_CustomData0Float1
ClearCoatRoughnessMP_CustomData1Float1
CustomData0MP_CustomData0Float1
CustomData1MP_CustomData1Float1
DiffuseColorMP_DiffuseColorFloat3
SpecularColorMP_SpecularColorFloat3
SurfaceThicknessMP_SurfaceThicknessFloat1
DisplacementMP_DisplacementFloat1
CustomizedUV0, CustomizedUVs0MP_CustomizedUVs0Float2
CustomizedUV1, CustomizedUVs1MP_CustomizedUVs1Float2
CustomizedUV2, CustomizedUVs2MP_CustomizedUVs2Float2
CustomizedUV3, CustomizedUVs3MP_CustomizedUVs3Float2
CustomizedUV4, CustomizedUVs4MP_CustomizedUVs4Float2
CustomizedUV5, CustomizedUVs5MP_CustomizedUVs5Float2
CustomizedUV6, CustomizedUVs6MP_CustomizedUVs6Float2
CustomizedUV7, CustomizedUVs7MP_CustomizedUVs7Float2
AnisotropyMP_AnisotropyFloat1
TangentMP_TangentFloat3

An unrecognized name fails with Unsupported material output '{Name}'.

ClearCoat and CustomData0 are the same material property, as are ClearCoatRoughness and CustomData1. Binding both spellings of a pair in one Shader writes the same input twice; the later statement wins, with no diagnostic.

Fork-only targets

These resolve only when the engine defines MOON_ENGINE. On a stock Unreal build they are Unsupported material output.

Base. spellingEMaterialPropertyValue type
MooaEncodedAttribute0MP_MooaEncodedAttribute0Float4
MooaEncodedAttribute1MP_MooaEncodedAttribute1Float4
MooaEncodedAttribute2MP_MooaEncodedAttribute2Float4
MooaEncodedAttribute3MP_MooaEncodedAttribute3Float4
MooaEncodedAttribute4MP_MooaEncodedAttribute4Float4

Targets with side effects

Two Base. targets change the generated material's render state as a side effect of being bound. They are the only bindings that do so, and both are easy to trip over.

Base.MaterialAttributes

since 1.2.5

Binding Base.MaterialAttributes sets UMaterial::bUseMaterialAttributes = true — the Use Material Attributes checkbox — so the material exposes the single attributes input instead of the individual property inputs. You do not tick the checkbox yourself, and you cannot un-tick it from the material editor: the property is reset and reapplied on every regeneration.

The bound variable must carry a MaterialAttributes value, otherwise:

{File}: Material output '{Name}' expects a MaterialAttributes value.

Base.FrontMaterial

since UE 5.4

Binding Base.FrontMaterial:

  • force-sets the shading model to Substrate (MSM_Strata);
  • requires that Settings either declares ShadingModel="Substrate" (or its accepted alias ShadingModel="Strata") or declares no ShadingModel at all — anything else fails with {File}: Base.FrontMaterial requires ShadingModel="Substrate" or no explicit ShadingModel setting.;
  • is mutually exclusive with Base.MaterialAttributes{File}: Base.FrontMaterial and Base.MaterialAttributes cannot be used by the same Shader.;
  • cannot be driven by the whole-surface Custom-node path — {File}: Base.FrontMaterial expects a Substrate value and cannot be driven by a material Custom node. Use a Graph block and Substrate.* nodes.;
  • does not exist on UE 5.3, where it reports Base.FrontMaterial requires Unreal Engine 5.4 or newer.

The bound variable must be a Substrate value, produced by the Substrate.* builtins:

Outputs = {
    Substrate Surface;
    Base.FrontMaterial = Surface;
}
Graph = {
    Surface = Substrate.Unlit(EmissiveColor = Color);
}

The Expression( … ).Pin[i] target

Some Unreal outputs are not material property inputs at all — they are custom output nodes sitting loose in the graph. The non-Base binding form creates such a node and connects the source variable to one of its input pins.

Expression( Class = "<ExpressionClass>" [, <key> = <value> ]… ) . Pin[ <index> ] = <source> ;

Requirements, in the order they are checked

RequirementDiagnostic when violated
the target text is non-emptyOutput binding target cannot be empty.
the target begins with Base. or ExpressionOutput binding target '{Target}' must start with Base. for material outputs or Expression(...) for output nodes.
a balanced ( … ) is presentInvalid output expression target '{Target}'.
the text before ( is exactly ExpressionUnsupported output target '{Target}'.
the text after ) starts with .Expression output target '{Target}' must select a pin with .Pin[index].
that suffix is Pin[], with Pin[ matched case-insensitivelyExpression output target '{Target}' must use .Pin[index] syntax.
the index parses as an integer of 0 or moreExpression output target '{Target}' has an invalid pin index.
every argument is Key=ValueExpression output target argument '{Argument}' must use Key=Value syntax.
no argument has an empty key or valueInvalid expression output target argument '{Argument}'.
no argument key is repeatedExpression output target argument '{Key}' is declared more than once.
a Class argument is presentExpression output target '{Target}' must specify Class="...".

Argument keys are normalized — trimmed and lower-cased; values are unquoted and trimmed.

Class resolution

A value containing / or . is loaded directly as an object path, and accepted only if the loaded class derives from UMaterialExpression. Otherwise a candidate list is built — <Value>, plus U<Value>, MaterialExpression<Value> and UMaterialExpression<Value> when <Value> does not already start with that prefix — and every non-abstract UMaterialExpression subclass is scanned for a name equal to any candidate, ignoring case.

The scan compares against the reflected class name, which carries no U prefix: UMaterialExpressionThinTranslucentMaterialOutput is reflected as MaterialExpressionThinTranslucentMaterialOutput. A specifier that begins with U therefore never matches. Class="ThinTranslucentMaterialOutput" and Class="MaterialExpressionThinTranslucentMaterialOutput" name the same class; Class="UMaterialExpressionThinTranslucentMaterialOutput" fails with Output target '{Target}' could not resolve MaterialExpression class '{Class}'.

The same rule governs Class= everywhere else it appears — see UE.Expression.

Other arguments

Every argument other than Class is written to the same-named reflected property on the created node, using the same literal grammar as declaration metadata. Class stays in the argument map but is skipped when reflected properties are written, so it never produces a "not a property" error.

An argument that names an input property of the node (an FExpressionInput) is rejected rather than wired: Output target '{Target}': inline input property '{Key}' is not supported yet. Bind through .Pin[index] instead. Inputs are reachable only through the .Pin[index] suffix.

Pin indices and node reuse

  • Pin[<index>] is the zero-based index into the node's input list, in the order the engine declares them. Expression(Class="ThinTranslucentMaterialOutput").Pin[0] is TransmittanceColor and .Pin[1] is SurfaceCoverage.
  • An index past the end fails with Output target '{Target}' does not have Pin[{Index}].
  • Each pin may be bound once: Output target pin '{Target}' is bound more than once.
  • Nodes are de-duplicated by class plus sorted argument list. Two bindings whose Expression( … ) specification is identical share one node and bind different pins; a difference in any argument creates a second node.
  • The source variable must have been declared in Outputs: Output variable '{Name}' must declare an explicit type before binding to expression target '{Target}'.
  • Created output-target nodes are placed at graph X 1200, Y starting at 200, stepping +220.
Outputs = {
    float3 Transmittance;
    float  Coverage;
    float3 CoatNormal;

    // Both statements reuse one ThinTranslucentMaterialOutput node.
    Expression(Class="ThinTranslucentMaterialOutput").Pin[0] = Transmittance;
    Expression(Class="ThinTranslucentMaterialOutput").Pin[1] = Coverage;

    // A different class -> a second node.
    Expression(Class="ClearCoatNormalCustomOutput").Pin[0] = CoatNormal;
}

The reserved name return

return may be used as a binding source, but never as a declaration name.

RuleDiagnostic
return may not be declaredOutputs declarations cannot use the reserved name 'return'.
return may only bind to Base.* targetsThe reserved output name 'return' can only bind to Base material properties.
all Base.* targets return binds to must agree in typeThe return value is bound to material properties with incompatible types.
a Shader that has a Graph block may not bind return at all{File}: Graph blocks do not support binding Outputs to the reserved name 'return'.

In practice return belongs to the whole-surface Custom-node path, where the Shader has no Graph block. Any material with a Graph block should declare named output variables.

Validation rules

Applied after parsing, before any node is created.

RuleDiagnostic
a declared type must resolveUnsupported output type '{Type}' for '{Name}'.
Substrate declarations need UE 5.4 or newerOutput '{Name}' uses Substrate, which requires Unreal Engine 5.4 or newer.
the same name may not be declared twice with different typesOutput variable '{Name}' is declared with conflicting types.
one variable may not bind to two Base.* targets of different typesOutput variable '{Name}' is bound to incompatible material properties.
a declared type may not conflict with the bound property's typeOutput variable '{Name}' is declared as '{Type}' but bound material property '{Property}' expects a different type.
a variable bound to an Expression(…) target must be declaredOutput variable '{Name}' must declare an explicit type before binding to expression target '{Target}'.
the target name must resolveUnsupported material output '{Name}'.

Notes

  • Bindings and declarations may be interleaved freely; a binding may reference a variable declared later in the same section.
  • A repeated Outputs section appends to both lists.
  • No [ … ] metadata block is accepted on any Outputs statement in a Shader.
  • Each binding is routed through a generated NamedReroute pair, so the material root node stays readable in a large graph. Declarations are named DS_<Sanitized> with an index suffix.
  • Binding to a property that the current shading model or blend mode does not use is not diagnosed — Unreal simply leaves the input unread. Check the material editor's greyed-out inputs.

Common errors

MessageCauseFix
Output binding target '{Target}' must start with Base. for material outputs or Expression(...) for output nodes.An unrecognized target prefix.
Unsupported material output '{Name}'.A Base. name that is not in the catalogue above.Check the spelling against the catalogue; matching is case-insensitive but the name must be exact.
Invalid output binding '{Statement}'.The right side of the binding is empty.
{File}: Outputs block is required.The Shader declared no bindings at all.Declarations alone are not enough — add at least one Base. binding.
{File}: Base.FrontMaterial and Base.MaterialAttributes cannot be used by the same Shader.Both side-effecting targets bound in one Shader.
{File}: Base.FrontMaterial requires ShadingModel="Substrate" or no explicit ShadingModel setting.A conflicting explicit shading model alongside Base.FrontMaterial.
Base.FrontMaterial requires Unreal Engine 5.4 or newer.Base.FrontMaterial on UE 5.3.
{File}: Material output '{Name}' expects a MaterialAttributes value.A non-attributes value bound to Base.MaterialAttributes.
{File}: Material output '{Name}' expects a Substrate value.A non-Substrate value bound to a Substrate target.Details
{File}: Material output '{Name}' expects a numeric value, but got Substrate.A Substrate value bound to a numeric target.
{File}: Graph output '{Name}' does not match its declared type.The assigned value's type differs from the declaration.
Output variable '{Name}' is declared as '{Type}' but bound material property '{Property}' expects a different type.A declaration/target type conflict.
Output variable '{Name}' must declare an explicit type before binding to expression target '{Target}'.An undeclared source on an Expression(...) binding.
Output target '{Target}' could not resolve MaterialExpression class '{Class}'.Class= names no known expression class — most often because the spelling carries a U prefix.Drop the leading U. Details
Output target '{Target}' does not have Pin[{Index}].The pin index is past the end of the node's input list.
Output target pin '{Target}' is bound more than once.The same pin bound twice.
Output target '{Target}': inline input property '{Key}' is not supported yet. Bind through .Pin[index] instead.An argument naming an input pin.
{File}: Base.FrontMaterial expects a Substrate value and cannot be driven by a material Custom node. Use a Graph block and Substrate.* nodes.Base.FrontMaterial on the whole-surface Custom path.
Outputs declarations cannot use the reserved name 'return'.return used as a declaration name.
{File}: Graph blocks do not support binding Outputs to the reserved name 'return'.return bound in a Shader that has a Graph block.

The complete cross-stage list is in the diagnostics index.

Worked example

Shader(Name="DreamShaderTests/Corpus/M_Outputs")
{
    Properties = {
        vec3  Tint = vec3(0.4, 0.8, 1.0);
        float A    = 0.75;
    }

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

    Outputs = {
        vec3  Color;
        float Alpha;

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

    Graph = {
        Color = Tint;
        Alpha = A;
    }
}

Resulting connections:

UMaterial /Game/DreamShaderTests/Corpus/M_Outputs
  MP_EmissiveColor  <- NamedReroute DS_Color_<n>  <- VectorParameter "Tint"  RGB output
  MP_Opacity        <- NamedReroute DS_Alpha_<n>  <- ScalarParameter "A"     R output
  bUseMaterialAttributes = false

Where next

On this page