DreamShaderLang
Builtins

UE.Expression

The reflected call that creates any UMaterialExpression class of the builtin catalog by name — class resolution, argument dispatch, OutputType, output selection, Custom nodes and the result type.

UE.Expression

DreamShader » Builtins » UE.Expression

The reflected node call: creates any UMaterialExpression class of the builtin catalog by name and fills its input pins and properties from the arguments.

Declared in.dsm, .dsf — inside a Graph { … } body, or a Properties { … } section (see Declaration form)
Kindbuiltin
Generatesone instance of the resolved UMaterialExpression class

Synopsis

UE.Expression( Class = <class-specifier>
               [, { OutputType | ResultType } = <type-token> ]
               [, { { Output | OutputName } = <text> | OutputIndex = <int> } ]
               [, <arg-name> = <expression> ] … )

UE.<ClassName>( [ <arg-name> = <expression> ] … )

The two forms are one path through the binder. A call names its class with Class, or else with the name after UE., so UE.Sine(…) and UE.Expression(Class = "Sine", …) are identical; a Class argument on another name wins over the name. Expression names no class, which is why the first form needs Class — without it the call is DSH5218.

OutputType is no longer required (since 2.0.0): the catalog knows what every class makes. See OutputType.

Arguments are named. A positional argument binds only on the classes the catalog gives an argument order — TextureCoordinate, Constant, Constant2Vector, Constant3Vector, Constant4Vector, Transform, TransformPosition, Panner, ComponentMask, Time, and the five Substrate composition nodes — and is DSH5220 elsewhere, DSH5221 past the end of the order (since 2.0.0). On the 27 1.x names of the UE.* catalogue the legacy front end drops a positional argument first (DSH5254), except Input of the two transforms.

Text arguments may be quoted or bare: Class = Sine and Class = "Sine" are the same, as are OutputType = float3 and OutputType = "float3".

Order of resolution

A call goes through the stages of the compiler. Each stage reports all of its errors, and a stage with errors stops the pipeline before the next one (since 2.0.0; 1.x stopped at the first failing step).

#StageWhat happens to the callCodes
1legacy front endOutput / OutputIndex become a selection on the call; OutputType / ResultType are taken off it (and kept on a Custom call); the 1.x shorthands are rewrittenDSH5250–DSH5259, DSH5261, DSH5263–DSH5265
2binder — the classClass, or the name, is looked up in the catalogDSH5216, DSH5217, DSH5218, DSH5212, DSH5210, DSH5294, DSH5300, DSH5276
3binder — the argumentseach is bound to a pin, a property, a Custom input, a Substrate argument, or kept for the built nodeDSH5220, DSH5221, DSH5285, DSH4215, DSH5214, DSH5224, DSH5215, DSH5278, DSH5284, DSH5288, DSH5291, DSH5213
4binder — the callrequired pins; the type of the valueDSH5279 (DSH5219 in a .dss), DSH4231
5IR builderproperty values become literalsDSH4373
6emitterthe node is created, its properties written, its pins connectedDSH8211, DSH8214, DSH8213, DSH8212, DSH8254

Class resolution

Class takes a quoted string, a bare word or a dotted name (DSH5217 otherwise). The specifier is trimmed and looked up in the catalog, in this order:

#Matches
1the catalog's short name — Sine
2the class name — MaterialExpressionSine
3the class path — /Script/Engine.MaterialExpressionSine
4MaterialExpression + the specifier, and the C++ name with its U — UMaterialExpressionSine
5an alias the catalog carries — TexCoord, Lerp, Mask, FunctionCall, …
6in a 1.x source only: a unique match of rows 1–3 ignoring case, with DSH5276

Nothing matched is DSH5212. Rows 1–5 are case-sensitive.

[!IMPORTANT] UMaterialExpressionSine resolves (since 2.0.0; 1.x compared against the reflected name and never matched a U-prefixed spelling). USine does not.

[!NOTE] The catalog lists the classes loaded when it is built, abstract and deprecated ones left out. An expression class living in a plugin module the editor has not loaded is not in it.

On the Substrate.* path the name is the class, and Class= is DSH5216.

OutputType

OutputType — or its alias ResultType — is not required (since 2.0.0). The legacy front end takes it off the call, and the type of the value comes from the catalog. It still matters in two places:

  • on a Custom node it is the node's output type — see Custom nodes;
  • on a node with one numeric output, a numeric type token is the width the value is typed with, as in 1.x, and the node is wired whole.

Everything else it was — a texture, MaterialAttributes or Substrate token, a misspelled token — is dropped without a diagnostic. The token tables are on the OutputType page.

Argument dispatch

These names are not dispatched:

NamePurpose
Classclass specifier; matched with exactly this spelling
OutputType, ResultTypedeclared output type — taken off by the front end, any case
Output, OutputNameoutput selector by name — any case
OutputIndexoutput selector by index — any case

Every other argument is resolved against the class's catalog entry in this order. The first match wins.

#TestResult
athe name is an input pin of the class, or one of its aliasesthe value is connected to that pin
bthe name is a property of the class, or one of its aliasesthe value is written into the node
cin a 1.x source: a pin, then a property, whose name or alias is the only one to match ignoring caseas a or b, with DSH5276
dthe class is Customa new input of the node, named as written — see Custom nodes
ethe node is a Substrate BSDF and the name a virtual argumentthe input of a conversion node in front of the pins
fin a 1.x source: DefaultValue on a class that has nonedropped with DSH5288
gin a 1.x source, or on a class whose pins depend on its properties: the value is a number, a texture, a material, a Substrate value or a nodekept with DSH5291 and connected by that name when the node is built (DSH8212 if the node has no such pin)
h—DSH5213, with a "did you mean" when a spelling is close

An input-pin name beats a property of the same name; a real pin or property name beats an alias. The same pin or property twice is DSH4215.

The aliases are:

AliasExample
a bool property's name without its leading b, where a capital follows the b (since 2.0.0)FractionalPart → bFractionalPart
a property's display name, with its spaces removed or turned into _ShaderOffsets, Shader_Offsets → WorldPositionShaderOffset
a pin's display name in identifier formTrue, False → StaticSwitch.A, StaticSwitch.B
the 1.x spellings with no rule behind themIndex (TextureCoordinate.CoordinateIndex), Origin (ObjectPositionWS.OriginType), Source / Destination (Transform, TransformPosition), Asset / Parameter (CollectionParameter), UV (TextureSample.Coordinates)

The catalog lists the input pins and the properties that are editable and neither deprecated nor transient; 1.x reached any UPROPERTY, editable or not (since 2.0.0). Argument names are otherwise exact: no separator is stripped.

Input pins

An argument that resolves to a pin is an expression and is connected. Its type is checked against the pin's as the catalog types it:

PinValueResult
float1–float4the same width, or a scalar (spread across the pin)connected
float1–float4a narrower vectorconnected as it is — what the node does with fewer components is the node's business
float1–float4a wider vectorin a 1.x source connected whole, with the info DSH5289; otherwise DSH5214
a pin the engine does not typeany number, a material, a Substrate valueconnected as it is
MaterialAttributes, Substrate, texturea value of another kindDSH5214

Literal properties

Any other matched name is a property, written into the node when it is built. The binder checks the value; the emitter writes it with the 1.x literal writer, and a value it cannot write is DSH8213, whose message carries the writer's own code.

Property typeThe binder acceptsThe emitter reads it asCode inside DSH8213
FBoolPropertya constanttrue / false, case-insensitiveDSH7132
FIntPropertya constanta decimal integerDSH7133
FUInt32Propertya constantan integer in 0 … 4294967295DSH7134
FFloatPropertya constanta numberDSH7135
FDoublePropertya constanta numberDSH7136
FStrPropertya quoted string, a word or a dotted namethe trimmed text, verbatim — always succeeds—
FNamePropertythe samethe trimmed text as an FName — always succeeds—
FObjectPropertyBasethe samesee Object propertiesDSH7137–DSH7139
FEnumProperty, FByteProperty with an enumsee Enum valuesthe enum valueDSH7140, DSH7141
FByteProperty without an enuma constantan integer in 0 … 255DSH7142
anything else — structs, arraysa quoted string or a wordUnreal's own import text, e.g. "(R=1,G=0,B=0,A=1)"DSH7143

A value the binder does not accept is DSH5224: a computed value for a numeric property, or a number for a text property.

[!WARNING] FStrProperty and FNameProperty never fail. Whatever text the argument carries — including an unresolvable path — is stored verbatim. Neither a diagnostic nor a fallback value is produced.

Enum values

The binder matches an enum value against the values the catalog lists for the property — hidden values left out, each written without its prefix (PostProcessInput0 for PPI_PostProcessInput0).

WrittenIn a .dssIn a 1.x source
PostProcessInput0acceptedaccepted
postprocessinput0DSH5215, with a "did you mean"accepted, with DSH5278
PPI_PostProcessInput0, ESceneTextureId::PPI_PostProcessInput0DSH5215accepted, with DSH5278
a display name that differs from the value's nameDSH5215DSH5215 (since 2.0.0)

The 1.x match (rule L12) ignores case, spaces, tabs and the characters _, -, :, . and /, and tries the value whole, after an Enum:: scope, and after its own prefix. The node is written with the catalog's spelling. UE.SceneTexture and the transform bases rely on this.

Object properties

An object property takes Path(<root>, "<asset>"), a quoted object path "/Game/…", or Class'/Game/…'. A Path(…) argument is carried as text and resolved when the node is built. See Path(…).

SituationResult
The value is neither a quoted string, a word nor a Path(…)DSH5224
The text begins with Path( or /, or ends in ', and does not resolveDSH8213 with the resolver's own message
The text is no asset referenceDSH8213 (DSH7137)
The asset fails to load, and the property is a UTexture named Texture or TextureObjectthe property is set to null and this counts as success
The asset fails to load, any other propertyDSH8213 (DSH7138)
The asset loads but is the wrong classDSH8213 (DSH7139)

[!WARNING] The null-on-failure rule is silent. UE.Expression(Class = "TextureSample", Texture = Path(Game, "Missing/T_Nope")) compiles with an unassigned texture instead of reporting the missing asset. Only the two property names Texture and TextureObject on UTexture-typed properties behave this way.

Selecting an output

A node with several outputs is read through one of two mutually exclusive selectors, which the front end turns into a selection on the call.

ArgumentAliasesKindBecomes
OutputOutputNamea quoted name or a word.Name on the call
OutputIndex—whole number ≥ 0[k] on the call
MistakeCode
both selectorsDSH5252
OutputIndex not a whole number of zero or moreDSH5250
Output neither a quoted name nor a wordDSH5251
a selector on a constructorDSH5253
a name no output of the class hasDSH5201
an index past the last outputDSH5282

The name is compared with the outputs the catalog lists, exactly; in a 1.x source a name that matches only ignoring case is accepted with DSH5276. It may contain spaces (Output = "Second Roughness"). An unnamed masked output of a node with several outputs is listed under the channels its mask keeps (RGB, R, A); see output names.

Using neither selector, the call is the node: see Result type and component count.

Custom nodes

UE.Expression(Class = "Custom", …) — MaterialExpressionCustom too — makes a node whose pins are the call's (rule L4):

AspectBehaviour
OutputTypethe node's output type: float, float1, half, half1 → Float1; float2, vec2, half2 → Float2; float3, vec3, half3 → Float3; float4, vec4, half4 → Float4; MaterialAttributes → MaterialAttributes. Compared ignoring case and spaces; anything else is DSH5261. Without one, the class's own output type
AdditionalOutputsthe node's further outputs, in the engine's import text; each is then selected by its name, and output 0 is called return
An argument that is no pin or propertya new input, named exactly as written; a value that is no number, bool or texture is DSH5284, the same name twice DSH4215
The fresh nodeits Inputs and AdditionalOutputs arrays are cleared before the call's are written
An output selectornames one of the declared outputs: another name is DSH5201, an index past them DSH5282 (since 2.0.0; 1.x made placeholder outputs Output1, Output2, … up to the one asked for)
Node reusetwo identical Custom calls are one node, as any two identical calls are (since 2.0.0)

Result type and component count

The value of a call, by what the catalog says of the class:

#The classThe value
1has no output (a custom-output class)none — the call is a statement; used as a value it is DSH4231
2is Customthe type OutputType gives; with AdditionalOutputs, a node whose outputs are named
3has several outputsa node: name one, or use it where its first output — or the whole value its channel outputs make up — fits exactly. In a 1.x source a first output of no fixed width is read as that output (DSH5287), and so is the first output of any node passed straight to a pin (2.0.0 – 2.1.0: DSH5201); otherwise DSH5201
4has one output of a known typethat type
5has one output the engine does not typeas wide as the widest number on a pin the engine does not type either — or the Substrate or material value such a pin carries — else as wide as the place it is read into

In a 1.x source, a numeric OutputType on a class of row 4 or 5 types the value instead, as above.

An output's type is its mask's width when it has a mask, else the engine's value type; where the engine says only "a float", a table of known widths decides — 1.x's own, consulted for a class with one output, and a few rows the catalog adds:

WidthClasses
2TextureCoordinate, Panner, Rotator, SceneTexelSize; SceneTexture outputs Size and InvSize
3ObjectPositionWS, CameraVectorWS, VertexNormalWS, VertexTangentWS, Transform, TransformPosition, SkyAtmosphereLightDirection, PixelNormalWS, CrossProduct, ObjectBounds, CameraPositionWS, ReflectionVectorWS
1PixelDepth, TwoSidedSign, Arctangent2Fast, Length, MaterialXLuminance, Time, SceneDepth, ObjectRadius, PerInstanceRandom, PerInstanceFadeAmount

A MaterialAttributes result is a material value.

Side effects on the material

Two classes are registered as material parameters when they are built, so they appear in the material instance editor:

ClassRegistration
UMaterialExpressionStaticSwitchParameter with a parameter namean editor-only static switch value on the material or material function
UMaterialExpressionStaticComponentMaskParameter with a parameter namean editor-only static component-mask value, from the node's four default channels

Both are given a fresh expression GUID when theirs is invalid.

Node reuse

The IR merges two nodes of the same class with the same properties and the same inputs into one, and everything that read the second reads the first (since 2.0.0). The comparison is of the nodes, not of the calls' spelling: argument order, an alias or a case-only difference play no part, and a Custom node merges like any other. A statement — a node with no output — never merges. See Node reuse.

SampleTexture2D

SampleTexture2D(<texture-object>, <uv>)

A reserved two-argument form, resolved by the legacy front end before user properties and functions and matched case-sensitively. It rewrites to

UE.Expression(Class = "TextureSample", TextureObject = <arg0>, Coordinates = <arg1>)

and the call stands for the whole sample: float4 t = SampleTexture2D(T, uv) is the RGBA output, float3 c = … the RGB output, .a the A output. Both arguments are positional and both are required; any other shape — a named argument, a third argument, an output selector — is DSH5256.

A property declared with a texture-sample parameter token (TextureSampleParameter2D and its kin) is called with its pins instead — BaseTex(Coordinates = uv). See Parameters in Graph.

Declaration form

A UE.<Name>(…) — UE.Expression(Class = …) included — may stand as a property type inside Properties. It is the declaration form of any UE. call: a local at the head of each Graph body that reads the property, bound like the Graph form. What differs from 1.x (since 2.0.0):

AspectNow1.x
OutputType / ResultTypeoptional; the type of the local — see Declared output widthrequired, from a reduced token set
Input-pin namesmatched, as in Graphnot matched — properties only
Input valuesa quoted string, a number, true / false, or a word (another variable); anything else, a vector literal float3(…) among them, is kept as text, which a pin refuses (DSH4202)a declared property, a scalar, or a 2–4 component vector literal
ParameterNameonly as writtenset from the property name when the class has one
Metadata [ … ]read and not appliedapplied to the node
Output / OutputIndexordinary arguments: DSH5213, or DSH5291 and DSH8212select the output

Notes

  • Property names are flat. Dotted paths and [index] selectors are not accepted here; those exist only in the Settings section, which is a different resolver.
  • A required pin left unconnected is a warning — DSH5279 in a 1.x source — and the engine reports it when the material compiles if the node needs the pin.
  • A typo in a name and a typo in Class are two codes: UE.Sinee() is DSH5210, UE.Expression(Class = "Sinee") is DSH5212.
  • A call may be swizzled like any other expression: UE.Expression(Class = "VertexColor").rgb. See Swizzle.
  • dsc export-catalog writes out every class with its pins, properties, aliases and outputs — the practical way to discover argument names. The editor also exports a manifest to Saved/DreamShader/Bridge/material-expressions.json; see Bridge.

Diagnostics

Every code is listed with its message and its full description on its page in Diagnostics.

CodeRaised when
DSH5218UE.Expression without Class
DSH5217Class is not a quoted string, a word or a dotted name
DSH5212Class matches no class of the catalog
DSH5210the name after UE. matches no class of the catalog
DSH5216Class on a Substrate.* call
DSH5276 (warning)in a 1.x source, a class, pin, property or output matches only ignoring case
DSH5220 / DSH5221a positional argument on a class with no argument order, or past its end
DSH5213an argument names no pin or property
DSH5291 (info)an argument naming no pin is kept for the built node to name
DSH4215a pin, property or Custom input is given twice
DSH5214a value does not fit its pin
DSH5289 (info)in a 1.x source, a wider vector is connected whole
DSH5224a property value is not a literal or constant of the kind the property takes
DSH5215an enum value is not a value of the enum
DSH5278 (warning)in a 1.x source, an enum value is spelled the 1.x way
DSH5284a Custom input is given something a Custom pin cannot carry
DSH5261a Custom OutputType is not one of the accepted tokens
DSH5288 (warning)in a 1.x source, DefaultValue on a class that has none is dropped
DSH5279 (warning)in a 1.x source, a required pin is left unconnected
DSH5250–DSH5253, DSH5201, DSH5282an output selector — see Selecting an output
DSH4231a node with no output is used as a value
DSH4373a property value is computed at run time
DSH5256SampleTexture2D is not called with exactly two positional arguments
DSH8211the engine building the asset has no such class
DSH8214the node could not be created
DSH8213a property could not be written; the message carries DSH7131–DSH7144 or the asset resolver's code
DSH8212the built node has no pin of a name kept with DSH5291

Example

Shader(Name="Docs/M_Generic")
{
    Properties {
        Texture2D BaseTex = Path(Game, "Textures/T_Noise");
        vec3      Dimmed  = vec3(0.2, 0.2, 0.2);
    }

    Settings { ShadingModel = "Unlit"; }

    Outputs {
        vec3 Color;
        Base.EmissiveColor = Color;
    }

    Graph {
        // Class defaults to the function name.
        float pulse = UE.Sine(Input = UE.Time());

        // Explicit Class, an enum property by its value's name, then output 0 swizzled.
        float3 scene = UE.Expression(Class = "SceneTexture",
                                     SceneTextureId = "PostProcessInput0").Color.rgb;

        // An object property through Path(...), and a pin by its pin name.
        float4 tex = UE.Expression(Class = "TextureSample",
                                   Texture      = Path(Game, "Textures/T_Noise"),
                                   Coordinates  = UE.TexCoord(Index = 0));

        // Pins by their display names (True, False for A, B), and a bool property.
        float3 sel = UE.Expression(Class = "StaticSwitch",
                                   True = Dimmed, False = tex.rgb, DefaultValue = true);

        Color = (scene + sel) * pulse;
    }
}

Generated nodes:

Time                                  -> Sine                       (pulse)
SceneTexture (PPI_PostProcessInput0)  -> Color, mask .rgb           (scene)
TextureCoordinate (Index 0)           -> TextureSample.Coordinates
TextureSample (Texture = T_Noise)                                   (tex)
Constant3Vector (0.2, 0.2, 0.2)       -> StaticSwitch.True
StaticSwitch  (DefaultValue = true)                                 (sel)
Add, Multiply                                                       (Color)

See also

On this page