Material Settings
The Shader Settings block — six special keys, the reflection resolver that reaches every UMaterial property, and what a regenerated material resets to.
Settings writes properties onto the asset the enclosing block generates. In a Shader block that
asset is a UMaterial, and this is the page that describes what you may write.
The most important thing to know first:
Settings is not a fixed list of supported keys. Exactly six keys are hand-handled. Every other
key is resolved against the generated UMaterial by Unreal reflection — including nested struct
paths and fixed-array indices. No table can be complete for that surface, because it is the
engine's property set, not the plugin's.
Settings key
├── one of blendmode rendertype shadingmodel materialdomain domain backend
│ └── hand-handled: value parsed through the alias maps
└── anything else
└── alias table → UMaterial / UMaterialInterface / UObject property lookup
(name, b-stripped name, or DisplayName)
→ value parsed per the property's C++ typeThe shape of the block
Settings [=] { <setting-statement> … }
<setting-statement> := <key> = <value> ;
<key> := <segment> [ . <segment> ] …
<segment> := <identifier> [ [<integer>] ]
<value> := <bare-text> | "<text>"The = between the section name and its { … } block is optional sugar since 1.5.0. The
; after the last statement is optional. The [<integer>] in <segment> is literal
punctuation; the surrounding [ … ] is the optional-marker meta-bracket.
How a statement is parsed:
| # | Step | Consequence |
|---|---|---|
| 1 | // and /* … */ comments are stripped from the whole block | comments may appear anywhere, including mid-statement |
| 2 | The block is split on ; at parenthesis depth 0 and bracket depth 0, outside string literals | Color = (R=1,G=0,B=0); is one statement; empty statements are dropped |
| 3 | Each statement is split on the first = at parenthesis/bracket depth 0 outside a string | the inner = of (R=1,G=0,B=0) does not split the statement |
| 4 | The key is normalized — trimmed and lower-cased | key matching is case-insensitive |
| 5 | The value is unquoted — if the trimmed text both starts and ends with ", the quotes are removed and \ escapes unescaped; otherwise it is kept verbatim | quotes are optional on every setting |
| 6 | The pair is added to the block's map | duplicate keys overwrite, last wins |
Because of step 5, TwoSided = true; and TwoSided = "true"; are identical, and
Domain = Surface; behaves exactly like Domain = "Surface";. A block may contain more than one
Settings section; they merge into one map and a key declared twice keeps the last value.
The six special keys
Matched after trimming, lower-casing and deleting spaces, _ and -, these six never reach the
reflection resolver:
blendmode rendertype shadingmodel materialdomain domain backend| Canonical key | Synonym | Value grammar | Value when absent | Effect |
|---|---|---|---|---|
BlendMode | RenderType | one of the blend-mode spellings | Opaque | sets UMaterial::BlendMode |
ShadingModel | — | one of the shading-model spellings | DefaultLit | calls SetShadingModel |
MaterialDomain | Domain | one of the domain spellings | Surface | sets UMaterial::MaterialDomain |
Backend | — | Graph, ThinCustom, Instance, or the empty string | the project's Default Compiler Backend | selects the materialization strategy — see Backend |
When both a canonical key and its synonym are present, the canonical key wins: BlendMode beats
RenderType, MaterialDomain beats Domain. There is no diagnostic for the conflict.
A spelling that differs from a special key only by spaces, underscores or hyphens is silently
dropped. Blend_Mode = "Translucent"; does not set the blend mode: the direct probe for
BlendMode misses the stored key blend_mode, and the reflection loop skips it because its
separator-stripped form is on the special-key list. No error, no warning, no effect. The same
applies to Render_Type, Shading Model, Material-Domain, a Domain with an internal space, and
Back_end. Write the six names without separators.
Application order
- The whole block is validated first — every special value is resolved and every generic value
is written to a throw-away transient
UMaterial. A single bad value aborts before the real material is touched. BlendMode, thenShadingModel, thenMaterialDomain.- The generic keys, in the parsed map's iteration order.
The generic pass iterates a hash map, so no ordering is guaranteed between two generic keys. The
three special keys are always written first, which is why a blend-mode-adjacent property such as
TranslucencyLightingMode sees the final blend mode.
Backend is consumed before any material exists — an unrecognized Backend value fails the compile
before the rest of Settings is validated, so no other settings diagnostic is reported for that
file.
Interaction with Base.FrontMaterial
When any output binds Base.FrontMaterial, an explicit ShadingModel that is not Substrate or
Strata is a hard error; otherwise the shading model is force-set to Substrate after the block is
applied. Binding Base.FrontMaterial and Base.MaterialAttributes on the same Shader is also a
hard error. Substrate itself requires since UE 5.4.
The reflection resolver
Every key that is not special is resolved against the generated material by Unreal reflection.
| # | Step | Detail |
|---|---|---|
| 1 | Split the key into segments on . at bracket depth 0 | Lightmass.DiffuseBoost → Lightmass, DiffuseBoost. A . inside [ … ] does not split. |
| 2 | Parse each segment's optional trailing [<integer>] | the index must be a non-negative integer and ] must be the segment's last character |
| 3 | Map the segment name through the alias table | applied per segment, before the field scan |
| 4 | Scan TFieldIterator<FProperty> over the current struct, including super-classes | so UMaterial, UMaterialInterface and UObject properties are all reachable |
| 5 | Descend | a non-terminal segment must be an FStructProperty; the walk continues inside the struct |
| 6 | Write the value | parsed according to the resolved property's C++ type |
Property-name matching
A segment matches a property when any of these three, after deleting spaces, _ and - and
lower-casing, equals the segment:
| Rule | Example |
|---|---|
The raw FProperty name | TwoSided ← TwoSided, two_sided, TWO SIDED, two-sided |
The property name with a leading b stripped, when the name is b followed by an uppercase letter | bFullyRough ← FullyRough; bIsSky ← IsSky; bIsThinSurface ← IsThinSurface |
The property's DisplayName metadata | whatever the engine declares for that property |
The b-stripping rule is one-way and permissive: the full name still matches, so both
bFullyRough = true; and FullyRough = true; resolve to the same property. A property whose name
begins with a lowercase b followed by a non-uppercase character (bias, for example) is not
b-stripped.
Nested and indexed paths
| Form | Meaning | Example |
|---|---|---|
A.B | B inside the struct property A | Lightmass.DiffuseBoost = 1.5; |
A.B.C | arbitrary depth, each non-terminal an FStructProperty | NaniteOverrideMaterial.bEnableOverride = true; |
A[N] | element N of a fixed-size C array (ArrayDim > 1) | PhysicalMaterialMap[2] = Path(Game, "Physics/PM_Metal"); |
A[N].B | a member of an indexed struct element | index and path segments compose freely |
[N] on a property whose ArrayDim is 1 is an error; omitting [N] on a property whose ArrayDim
is greater than 1 is also an error. TArray, TMap and TSet properties are not indexable this
way — they fall through to the ImportText catch-all in Value grammar.
Alias table
Ten fixed key aliases are applied per path segment before the field scan. Alias keys are compared in
their separator-stripped, lower-cased form, so Lighting_Mode, Lighting Mode and LIGHTINGMODE
all hit the first row.
| Alias | Resolves to |
|---|---|
LightingMode | TranslucencyLightingMode |
TranslucentLightingMode | TranslucencyLightingMode |
RefractionMode | RefractionMethod |
PhysicalMaterial | PhysMaterial |
PhysicalMaterialMask | PhysMaterialMask |
Lightmass | LightmassSettings |
MobileSeparateTranslucency | bEnableMobileSeparateTranslucency |
AlwaysEvaluateWorldPositionOffset | bAlwaysEvaluateWorldPositionOffset |
ResponsiveAA | bEnableResponsiveAA |
ThinSurface | bIsThinSurface |
Because the alias applies per segment, Lightmass.DiffuseBoost resolves as LightmassSettings →
DiffuseBoost.
Value grammar
The resolved property's C++ type decides how the value text is parsed. The value has already been
unquoted, so true and "true" are the same input.
| Property type | Accepted literal | Failure message |
|---|---|---|
bool | true / false, case-insensitive | '{Value}' is not a valid boolean value for '{Property}'. |
int32 | signed integer literal | '{Value}' is not a valid integer value for '{Property}'. |
uint32 | integer in [0, 4294967295] | '{Value}' is not a valid unsigned integer value for '{Property}'. |
float | any numeric literal; also true → 1.0, false → 0.0 | '{Value}' is not a valid numeric value for '{Property}'. |
double | as float | '{Value}' is not a valid numeric value for '{Property}'. |
FString | any text, trimmed — never fails | — |
FName | any text, trimmed — never fails | — |
| object reference | Path( … ) or an absolute object path | Object property '{Property}' expects Path(...) or an absolute Unreal object path. and the load/class errors |
enum class | an enum literal | '{Value}' is not a valid enum value for '{Property}'. |
uint8 enum | an enum literal | '{Value}' is not a valid enum value for '{Property}'. |
plain uint8 | integer in [0, 255] | '{Value}' is not a valid byte value for '{Property}'. |
| anything else | Unreal struct-literal text, e.g. (R=1.0,G=0.0,B=0.0,A=1.0) | Property '{Property}' on '{Object}' is not a supported literal type yet. |
Whichever message applies is wrapped as
Invalid value '{Value}' for setting '{Key}'. {TypeMessage}.
Enum literals
An enum-typed value is matched after trimming, lower-casing and deleting every space, _, -, :,
. and /. Values carrying Hidden metadata are skipped. A candidate matches the short enum name
(TLM_Surface), the fully-qualified name (ETranslucencyLightingMode::TLM_Surface), the display
name (Surface), or the short name with everything up to the first _ removed (Surface).
This matching is separate from the ShadingModel / BlendMode / Domain alias maps on
Enum Values — those three keys never reach this code.
Path( … ) values
| Form | Meaning |
|---|---|
Path("/Game/Foo/Bar") | absolute object path, one argument |
Path(Game, "Foo/Bar") | /Game/Foo/Bar |
Path(Engine, "Foo/Bar") | /Engine/Foo/Bar |
Path(Plugin.PluginName, "Foo/Bar") | the named plugin's content root |
/Game/Foo/Bar | bare absolute path, no Path( … ) wrapper |
The complete root catalogue and its errors are on Asset References.
An object-typed property whose class derives from UTexture and whose property name is exactly
Texture or TextureObject writes nullptr instead of erroring when the asset fails to load. This
is the material-expression convention; it also applies here.
When an object-typed value looks like a path — it starts with Path( or / — but fails to
resolve, the type-specific explanation is empty and the diagnostic degenerates to
Invalid value '/Game/Nope' for setting 'physmaterial'. with nothing after the period. Check that
the asset exists and that its class matches the property.
Validation
Before anything is written to the real material, each generic key/value pair is applied to a
transient probe UMaterial. The probe write and the real write use the same code, so a value that
validates always applies. The only failure specific to this stage is
Failed to create a transient material for Settings validation.
What an omitted setting resets to
A generated material is reset immediately before Settings is applied. An omitted key is therefore
not "left as it was on the previous generation" — it takes the value below.
| Property | Reset value |
|---|---|
BlendMode | Opaque |
MaterialDomain | Surface |
| shading model | DefaultLit |
TwoSided | false |
OpacityMaskClipValue | 0.3333 |
Wireframe | false |
DitheredLODTransition | false |
DitherOpacityMask | false |
bAllowNegativeEmissiveColor | false |
bCastDynamicShadowAsMasked | false |
bCastRayTracedShadows | true |
bEnableResponsiveAA | false |
bScreenSpaceReflections | false |
bContactShadows | false |
bDisableDepthTest | false |
bOutputTranslucentVelocity | false |
bWriteOnlyAlpha | false |
BlendableOutputAlpha | false |
TranslucencyLightingMode | TLM_VolumetricNonDirectional |
bTangentSpaceNormal | true |
bAlwaysEvaluateWorldPositionOffset | false |
bFullyRough | false |
bIsSky | false |
bIsThinSurface | false |
MaterialDecalResponse | MDR_ColorNormalRoughness |
bHasPixelAnimation since UE 5.4 | false |
NumCustomizedUVs | 0 |
Every other UMaterial property keeps whatever a freshly constructed material has. Keep anything
that must survive a rebuild in Settings, not as a hand edit on the generated asset.
What survives a decompile round trip
The decompiler emits Domain, ShadingModel and BlendMode
unconditionally, plus each of the following when it differs from the UMaterial class default. This
is the set guaranteed to survive UMaterial → .dsm → UMaterial; it is a subset of what
Settings accepts, not a limit on it.
Booleans (39, in emit order)
TwoSided Wireframe DitheredLODTransition
DitherOpacityMask bAllowNegativeEmissiveColor bCastDynamicShadowAsMasked
bEnableResponsiveAA bScreenSpaceReflections bContactShadows
bDisableDepthTest bOutputTranslucentVelocity bTangentSpaceNormal
bFullyRough bIsSky bIsThinSurface
bHasPixelAnimation bUsedWithSkeletalMesh bUsedWithMorphTargets
bUsedWithClothing bUsedWithNanite bUsedWithEditorCompositing
bUsedWithParticleSprites bUsedWithBeamTrails bUsedWithMeshParticles
bUsedWithNiagaraSprites bUsedWithNiagaraRibbons bUsedWithNiagaraMeshParticles
bUsedWithGeometryCache bUsedWithStaticLighting bUsedWithSplineMeshes
bUsedWithInstancedStaticMeshes bUsedWithGeometryCollections
bUsedWithHairStrands bUsedWithWater bUsedWithVirtualHeightfieldMesh
bCastRayTracedShadows bWriteOnlyAlpha BlendableOutputAlpha
bAlwaysEvaluateWorldPositionOffsetbHasPixelAnimation is emitted only on since UE 5.4.
Enums (1) — MaterialDecalResponse.
Reachable but never emitted, and therefore lost on a round trip: OpacityMaskClipValue,
NumCustomizedUVs, TranslucencyLightingMode, RefractionMethod, RefractionDepthBias,
TranslucencyPass, ShadingRate, FloatPrecisionMode, BlendableLocation, BlendablePriority,
bIsBlendable, UserSceneTexture, StencilCompare, StencilRefValue, bEnableStencilTest,
MaxWorldPositionOffsetDisplacement, PhysMaterial, PhysMaterialMask, PhysicalMaterialMap[N],
Lightmass.*, DisplacementScaling.*, NaniteOverrideMaterial.*, and every other engine property
the resolver can reach.
Material function settings
A Settings block on a ShaderFunction, ShaderLayer or ShaderLayerBlend does not share any
of the behaviour above. Exactly four keys are read there:
| Key | Sets | Value grammar | Value when absent |
|---|---|---|---|
Description | UMaterialFunction::Description | free text | cleared to the empty string |
UserExposedCaption | UMaterialFunction::UserExposedCaption | free text | cleared to the empty string |
ExposeToLibrary | UMaterialFunction::bExposeToLibrary | true / false | false |
LibraryCategories | UMaterialFunction::LibraryCategoriesText | a comma-separated list; each entry trimmed, empty entries dropped | the category list is cleared |
Settings = {
Description = "Multiplies a colour by a tint.";
UserExposedCaption = "Tint";
ExposeToLibrary = true;
LibraryCategories = "DreamShader, Color";
}Keys here are matched by trim and lower-case only — spaces, underscores and hyphens are not
folded, so Expose_To_Library is not ExposeToLibrary.
Any other key is ignored, silently. There is no validation pass over a material function's
Settings map: only these four names are looked up and everything else is dropped with no error and
no warning. Backend, Domain, ShadingModel, BlendMode, TwoSided and every other key on this
page do nothing in a ShaderFunction block — and so does a misspelling of the four.
The decompiler does not emit a Settings block when exporting a UMaterialFunction to .dsf. All
four values are lost on that round trip and must be re-added by hand.
Notes
- The reflection surface is the engine's, not the plugin's. A custom or modified engine build exposes its own properties and its own enum values through the same resolver, so this page describes the stock UE 5.3 – 5.8 surface only.
- Under the ThinCustom backend every setting lands on the hidden base
UMaterial, not on the emitted instance. Reading the blend mode off the instance shows the inherited value. - Because keys are lower-cased when stored, the
{Key}quoted in a diagnostic is the lower-cased spelling, not what the source wrote. Every message is also prefixed with the source file path.
Diagnostics
| Message | Cause | Fix |
|---|---|---|
| Unsupported material setting '{Key}'. | No property matched a path segment — the usual unknown-key error. | Check the property name on UMaterial, or whether the key needs an alias. |
| Unsupported BlendMode/RenderType '{Value}'. | The value matched no project mapping and no built-in alias. | Details |
| Unsupported ShadingModel '{Value}'. | The value matched no project mapping and no built-in alias. | Details |
| Unsupported MaterialDomain '{Value}'. | The value matched no project mapping and no built-in alias. | Details |
| ShadingModel="Substrate" requires Unreal Engine 5.4 or newer. | The value trims and case-folds to Substrate or Strata on UE 5.3. | |
| Invalid value '{Value}' for setting '{Key}'. {TypeMessage} | The literal write failed. {TypeMessage} is empty for a path-shaped object value that failed to resolve. | |
| Setting path segment cannot be empty. | An empty .-delimited segment, as in Foo..Bar. | |
| Invalid array setting segment '{Segment}'. | Malformed brackets — no ], ] before [, ] not last, or nothing before [. | |
| Invalid array index '{Index}' in setting segment '{Segment}'. | The index is not an integer, or is negative. | |
| Setting '{Segment}' is not an indexed array property. | [N] used on a property whose ArrayDim is 1. | |
| Array index {Index} is out of range for setting '{Segment}' (max {Max}). | The index is at or beyond ArrayDim. | |
| Setting '{Segment}' requires an explicit [index]. | A fixed-array property addressed without [N]. | |
| Setting path '{Key}' cannot continue through '{Segment}'. | A non-terminal segment is not a struct property. | |
| Invalid material setting path '{Key}'. | The key produced no path segments. | |
| Invalid material setting target. | The resolver was handed no object. | |
| Failed to create a transient material for Settings validation. | The probe material could not be allocated. | |
| Invalid setting declaration '{Statement}'. | A statement with no = at parenthesis/bracket depth 0. | |
| Invalid empty setting key in '{Statement}'. | The text before = is empty after trimming. | |
| {File}: Base.FrontMaterial requires ShadingModel="Substrate" or no explicit ShadingModel setting. | An explicit non-Substrate shading model with a Base.FrontMaterial binding. | |
| {File}: Base.FrontMaterial and Base.MaterialAttributes cannot be used by the same Shader. | Both bindings on one Shader. | |
| {Kind} '{Name}': ExposeToLibrary must be true or false. | A material function's ExposeToLibrary value is not a boolean literal. |
Unsupported Backend '{Value}'. Supported values: Graph, Instance, ThinCustom. is raised earlier, by
the backend resolver — see Backend.
Example
Shader(Name="Docs/M_ShaderSettings", Root="Game")
{
Properties {
VectorParameter BaseColor = float4(0.8, 0.8, 0.8, 1.0) [Group="Surface"];
ScalarParameter Roughness = 0.55 [Group="Surface"; Slider(0, 1)];
}
Settings {
// Special keys.
Domain = "Surface";
ShadingModel = "DefaultLit";
BlendMode = "Masked";
// Reflected booleans; the b-prefix is optional.
TwoSided = true;
FullyRough = true;
bIsSky = false;
// Reflected scalar and enum.
OpacityMaskClipValue = 0.25;
MaterialDecalResponse = "ColorNormalRoughness";
// Alias -> TranslucencyLightingMode, matched by display name.
LightingMode = "Surface";
// Nested struct path.
Lightmass.DiffuseBoost = 1.5;
// Object reference.
PhysicalMaterial = Path(Engine, "EngineMaterials/DefaultPhysicalMaterial");
}
Outputs {
vec3 Color;
float Rough;
float Mask;
Base.BaseColor = Color;
Base.Roughness = Rough;
Base.OpacityMask = Mask;
}
Graph {
Color = BaseColor.rgb;
Rough = Roughness;
Mask = BaseColor.a;
}
}Resulting material state:
BlendMode = BLEND_Masked
MaterialDomain = MD_Surface
ShadingModel = MSM_DefaultLit
TwoSided = true
bFullyRough = true
bIsSky = false
OpacityMaskClipValue = 0.25
MaterialDecalResponse = MDR_ColorNormalRoughness
TranslucencyLightingMode = TLM_Surface
LightmassSettings.DiffuseBoost = 1.5
PhysMaterial = /Engine/EngineMaterials/DefaultPhysicalMaterialNext
- Enum Values — every accepted
ShadingModel,BlendModeandDomainspelling - Backend — the sixth special key, and what each backend produces
- Project Settings — the mapping maps that extend the enum spellings
- Regeneration — what a rebuild resets