Backend
Graph versus ThinCustom — which object carries the graph, which one is addressable, and how the per-file setting resolves against the project default.
Backend selects how a source file is materialized: as a visible UMaterial node graph, or as
a thin material instance over a hidden base material.
Shader(Name = "<asset-path>")
{
Settings [=] {
Backend = { "Graph" | "ThinCustom" | "Instance" };
}
}The value is matched case-insensitively after trimming and quote-stripping; quotes are optional.
Backend is a special key and never reaches the
reflection resolver. Its current form arrived in since 1.5.0.
Accepted values
| Value | Resolves to | Produces |
|---|---|---|
Graph | Graph | one UMaterial at the resolved asset path, with the node graph built directly on it |
ThinCustom | ThinCustom | a UDreamShaderMaterialInstance at the resolved asset path, parented to a hidden UMaterial named MB_DreamThinBase_… |
Instance | ThinCustom | identical to ThinCustom — deprecated in 1.5.0 |
| (empty string) | Graph | as Graph — not the project default |
| (key absent) | the project's Default Compiler Backend | see Precedence |
| anything else | — | hard error, Unsupported Backend '{Value}'. Supported values: Graph, Instance, ThinCustom. |
Deprecated since 1.5.0
Use ThinCustom instead.
Backend = "Instance" is an alias for ThinCustom; the legacy graphless instance backend is
retired and there is no runtime Instance backend left. The spelling is kept for one deprecation
window so existing sources keep compiling, and it produces no diagnostic. Replace it with
Backend = "ThinCustom"; — or delete the key and let the project default apply.
Backend = ""; resolves to Graph, not to the project default. Only omitting the key falls
back to Default Compiler Backend. An empty value is otherwise indistinguishable from a typo, so
prefer removing the whole statement.
Precedence
Settings = { Backend } | Project Default Compiler Backend | Resolved backend |
|---|---|---|
| absent | ThinCustom (the shipped default) | ThinCustom |
| absent | Instance | ThinCustom |
| absent | Graph | Graph |
"Graph" | any | Graph |
"ThinCustom" | any | ThinCustom |
"Instance" | any | ThinCustom |
"" | any | Graph |
An explicit Backend always wins over the project setting, which is documented on
Project Settings.
Backend is resolved before any material object exists and before the rest of Settings is
validated, so an unrecognized value fails the compile first and no other settings diagnostic is
reported for that file.
What each backend produces
Graph
| Aspect | Behaviour |
|---|---|
| Asset written | a UMaterial at the package path derived from Name and Root |
| Graph | built directly on the material, then laid out and recompiled |
| In-memory mode | the package is flagged newly-created and its dirty flag cleared afterwards, so a Save All cannot silently persist it |
| Persist mode | the package is marked dirty, source metadata is stamped, and the package is saved |
| Reuse conflict | Asset '{ObjectPath}' already exists and is not a Material. |
ThinCustom — the default
since 1.5.0
| Aspect | Behaviour |
|---|---|
| Asset written | a UDreamShaderMaterialInstance — a UMaterialInstanceConstant subclass — at the resolved asset path. This instance is the addressable asset. |
| Hidden base name, in-memory mode | MB_DreamThinBase_<sanitized Name> — the whole Shader Name, with every character outside [A-Za-z0-9_] replaced by _. Name="Docs/M_Tint" gives MB_DreamThinBase_Docs_M_Tint |
| Hidden base name, persist mode | MB_DreamThinBase_<instance leaf name> — the instance's own object name, no path component. Name="Docs/M_Tint" gives MB_DreamThinBase_M_Tint |
| Base ownership, in-memory mode | owned by the transient package, flagged public, standalone and transient |
| Base ownership, persist mode | a subobject of the instance, so the pair shares one package and one .uasset |
| Graph and settings | built on the base; every Settings key lands there, not on the instance |
| Instance wiring | parent set to the base, parameter overrides cleared, source path and hash stamped, static permutation updated |
| Reuse conflict | Asset '{ObjectPath}' already exists and is not a DreamShader instance material. Delete it (or remove Backend="Instance") before switching backends. |
UDreamShaderMaterialInstance overrides two engine behaviours:
| Override | Rule |
|---|---|
HasOverridenBaseProperties() | forced true when the parent is a UMaterial — that is, for the root instance over the hidden base. Any other parent falls through to the stock implementation, so a child instance parented to a DreamShader instance shares the root's compiled shader map instead of compiling its own. |
IsAsset() | false while the package is newly created and Show In-Memory Materials In Content Browser is off. Memory-only materials are hidden from the Content Browser, asset-registry enumeration and save pickers. The setting is read live, on every call. |
Both backends log a warning when in-memory generation is shadowed by an already-saved asset:
In-memory material mode: '{Asset}' already exists as a saved asset, which shadows in-memory
regeneration. Delete the saved asset to make it fully in-memory.See In-memory Materials.
Changing the project default
Changing Default Compiler Backend while the editor is running regenerates every source file in
memory and logs DreamShader default compiler backend changed; regenerating all source files in memory.
If persisted generated assets exist, a notification points at the cleanup action:
{Count} previously generated asset(s) are still saved on disk and shadow the in-memory materials.
Run Tools > DreamShader > Clean Persisted Generated Assets to remove them.Switching an individual material between backends leaves the previous asset behind, and the next compile hits one of the reuse-conflict errors above. Delete the stale asset, then regenerate.
Notes
- The backend does not change the language surface. Both build a real node graph and accept the identical feature set; they differ only in which object carries the graph and which object is addressable.
- Under
ThinCustom, readingBlendModeor the shading model off the generated instance shows the value inherited from the hidden base — that is where the settings were written. - Neither backend writes a
.uassetduring ordinary editor work. Assets reach disk at cook time, through the commandlet, or through an explicit Materialize action. Backendis honoured only in aShaderblock. In aShaderFunctionSettingsblock it is one of the keys that is silently ignored.
Diagnostics
| Message | Cause | Fix |
|---|---|---|
| Unsupported Backend '{Value}'. Supported values: Graph, Instance, ThinCustom. | The value is not Graph, ThinCustom, Instance or empty. | Fix the spelling, or remove the key to use the project default. |
| Asset '{ObjectPath}' already exists and is not a Material. | Graph backend: the target path holds another UClass. | Delete the stale asset and regenerate. |
| Asset '{ObjectPath}' already exists and is not a DreamShader instance material. Delete it (or remove Backend="Instance") before switching backends. | ThinCustom backend: the target path holds a non-DreamShader object. | |
| Failed to create ThinCustom base material for '{Name}'. | The hidden base could not be created. | |
| Cannot create a persisted ThinCustom base without an instance for '{Name}'. | Persist mode reached base creation with no instance. | |
| Failed to create ThinCustom base material for instance '{Name}'. | The base subobject could not be created under the instance. |
Informational messages worth recognising in the log:
| Message | Meaning |
|---|---|
Generated {Asset} from {File}.{Virtual} | Graph backend success; {Virtual} is (virtual) for in-memory generation and empty otherwise |
Generated DreamShader thin-custom material {Asset} from {File}. | ThinCustom backend success |
Skipped {Asset} from {File}; source hash is unchanged. | the source-hash cache suppressed the rebuild |
In-memory material mode: '{Asset}' already exists as a saved asset, … | a saved asset shadows the memory-only one |
Example
Shader(Name="Docs/M_ThinCustom", Root="Game")
{
Properties {
VectorParameter Tint = float4(0.2, 0.6, 1.0, 1.0) [Group="Look"];
}
Settings {
Backend = "ThinCustom";
Domain = "Surface";
ShadingModel = "DefaultLit";
BlendMode = "Opaque";
TwoSided = true;
}
Outputs {
vec3 Color;
Base.BaseColor = Color;
}
Graph {
Color = Tint.rgb;
}
}Generated assets, in persist mode:
package /Game/Docs/M_ThinCustom
asset /Game/Docs/M_ThinCustom.M_ThinCustom UDreamShaderMaterialInstance
subobject MB_DreamThinBase_M_ThinCustom UMaterial (hidden base, same package)
Settings applied to: MB_DreamThinBase_M_ThinCustom
BlendMode = BLEND_Opaque
ShadingModel = MSM_DefaultLit
TwoSided = trueIn the editor's ordinary memory-only mode the instance is the same object, but the base is a
separate transient-package object named MB_DreamThinBase_Docs_M_ThinCustom — the sanitized Name,
not the leaf. The same file with Backend = "Graph"; instead produces a single UMaterial at
/Game/Docs/M_ThinCustom carrying the graph and the settings itself.
Next
- Project Settings — Default Compiler Backend and the in-memory visibility toggle
- In-memory Materials — memory-only generation and materializing to disk
- The Pipeline — where backend resolution sits
- Asset Paths — how
NameandRootbecome a package path